当前位置:首页 >> 信息与通信 >>

飞利浦 nxp LPC1768 coretx m3 使用说明


CortexNXP Cortex-M3 LPC1768 基础教程

活生变改技科 好美更活生让子电

作者: 作者:天下的人 时间: 时间:2010 年 9 月 2 日 邮箱: 邮箱:zdeh726@163.com

电子让生活更美好

写在前面
首先说一说为什么写这个教程,转眼间就毕业了

,学校的日子还没 有过够。就要工作了,由于需要想要搞一搞 ARM M3,很显然芯片选型 落在了 STM32 和 NXP 的 LPC17XX 上了。 最后选择了 LPC1768 这款型号, 买开发板、学习(以前我只用过单片机和一点点 STM32) ,学习的过程 还算顺利,找到了 ZLG 翻译的中文资料和 3 个版本的例程。学习开始 了,从 LED 灯、串口、AD、到内部定时器等等。学习的过程夹杂着 心酸和喜悦,在学习的过程中发现网络上还没有现成的学习资料。市 场上的开发板的一部分不是自己开发的都是参考的 NXP 和 ARM 公司的 官方版本,其实这本身并没有什么不好,但是后面的问题出来了,程 序注释不详细,除了手册就没有参考资料了。所以在学习的过程中就 在想要是把自己学习的过程总结一下,出一点资料,为那些奋斗在学 习一线的电子爱好者出一份力,这是一件多么令人高兴的事呀!于是 有了今天这个教程的诞生。在这里首先要感谢的是 ZLG 公司为这个系 列芯片提供了中文参考资料,其次感谢该公司注释比较详尽的程序, 为我的学习和应用提供了不少帮助。 关于同是 ARM M3 内核的 STM32 和 LPC17XX 比较,我想大家争论最大 的地方是价格。我想说的是 LPC17XX 是 NXP 公司推出的基于 M3 内核比 较高端的芯片。应该拿 STM32 中高端芯片和 LPC17XX 比较。我曾经买 过几片 stm32f103VET6 是 100 脚 512KB flash、64KB SRAM、72MHz、AD、 DA、定时器、USB 从机和 FSMC。而 LPC1768,100 脚、512KB flash、 64KB SRAM、100MHz、AD、DA、32 位定时器、USB 主/从/OTG、以太网、
天下的人(红豆电子)与贞明电子协同打造 1

电子让生活更美好

电机控制 PWM、正交编码器接口等。STM32 有 FSMC 的优势,LPC1768 有以太网、 USB 主机等优势。 可能你要说 stm32F105 和 stm32f107 也有 带 USB 主机,以太网的。可是看看价格也差不多,这几个芯片目前的 价格都在 40 元左右。还有编程,stm32 有库,而 NXP 没有,但是我觉 得 NXP 的寄存器操作也很简单,不信试试就知道了。 下面说说本教程的主要内容安排:第一部分主要介绍 LPC1768 的特 点。第二部分介绍本教程使用的最小系统版的硬件电路。第三部分是 编译环境和下载程序介绍。第四部分是芯片编程介绍,第五部分是实 例详解。芯片内部功能和操作详解会柔和在实例的每一个实验中。最 后感谢一下辛苦的我自己,没有自己的辛勤劳动就没有这个教程。期 待早一点完成这个教程。

注意:本教程叙述语言力求简洁大方,例程力求通俗易懂,可以不 注意 深入追究的东西(如协议内容)就不深入追究。本教程适合的对象是 学过或致力于学习单片机或对 ARM7、ARM cortex m3 有所了解的人或 想学 LPC17XX 的初学者适用。高手绕行。

天下的人(红豆电子)与贞明电子协同打造

2

电子让生活更美好

第一部分 第一部分 LPC1768 介绍 1.1 简介 LPC1768 是 NXP 公司推出的基于 ARM Cortex-M3 内核的微控制器 LPC17XX 系列中的一员。LPC17XX 系列 Cortex-M3 微处理器用于处 理要求高度集成和低功耗的嵌入式应用。 LPC1700 系列微控制器的 操作频率可达 100MHz 新推出的 LPC1769 和 LPC1759 可达 120MHz) ( 。 ARM Cortex-M3 CPU 具有 3 级流水线和哈佛结构。LPC17XX 系列微 控制器的外设组件包含高达 512KB 的 flash 存储器、64KB 的数据 存储器、以太网 MAC、USB 主机/从机/OTG 接口、8 通道 DMA 控制 器、4 个 UART、2 条 CAN 通道、2 个 SSP 控制器、SPI 接口、3 个 IIC 接口、2 输入和 2 输出的 IIS 接口、8 通道的 12 位 ADC、10 位 DAC、电机控制 PWM、正交编码器接口、4 个通用定时器、6 输 出的通用 PWM、带有独立电池供电的超低功耗 RTC 和多大 70 个的 通用 IO 管脚。 1.2 特性(部分) 64KB 片内 SRAM 包括: 32KB 可供高性能 CPU 通过本地代码/数据总线访问; 2 个 16KB SRAM 模块、带独立访问路径、可进行更高吞吐量的操 作。这些 SRAM 可用于以太网、USB、DMA 存储器,以及通用指令和 数据存储。 串行接口: 以太网 MAC 带 RMII 接口和相关的 DMA 控制器;
天下的人(红豆电子)与贞明电子协同打造 3

电子让生活更美好

USB 2.0 全速从机/主机/OTG 控制器,带有用于从机、主机功能 的片内 PHY 和相关的 DMA 控制器; 4 个 UART、 带小数波特率发生功能、 内部 FIFO、 支持和 RS-485 DMA 支持。1 个 UART 带有 modem 控制 IO 并支持 RS-485,全部的 UART 都支持 IrDA; CAN 控制器,带有 2 个通道; SPI 控制器, 具有同步、 串行、 全双工通信和可编程的数据长度; 2 个 SSP 控制器,带有 FIFO,可按多种协议进行通信。其中一 个可选择用于 SPI,并且和 SPI 公用中断。SSP 接口可以与 GPDMA 控制器一起使用。 3 个增强型的 IIC 总线接口。 IIS 接口,用于数字音频输入和输出,具有小数速率控制功能。 IIS 接口可与 GPDMA 一起使用。IIS 接口支持 3 线数据发送和接收 或 4 线组合发送和接收连接,以及主机时钟输入输出; 其他外设: 4 个通用定时/计数器, 共有 8 个捕获输入和 10 个比较输出。 每 个定时器都有一个外部计数输入。 一个电机控制 PWM,支持三相的电机控制; 通过片内 PLL,没有高频晶振,CPU 页可以以最高频率运转。 第二个专用的 PLL 可用于 USB 接口,以允许增加主PLL的灵 活性;

天下的人(红豆电子)与贞明电子协同打造

4

电子让生活更美好

器件选型表:

方框图:

天下的人(红豆电子)与贞明电子协同打造

5

电子让生活更美好

第二部分

最小板硬件电路

2.1 硬件电路简介 硬件电路基本结构图:

EEPROM JTAG 微控制器 UART KEY

RTC IO口 LED USB

电源
图 1 硬件电路基本结构图 硬件电路原理图:
3V3 3V3 3V3 2 1 R12 680 R11 680 R10 680 R9 680 D5 LED2 D1 LED2 D2 LED2 D3 LED2 D4 LED2 R6 R5 R4 R3 R2 R1 10K 10K 10K 10K 10K 10K TRST TDI TMS TCK RTCK TDO RESET U1 JTAG 1 3 5 7 9 11 13 15 17 19 2 4 6 8 10 12 14 16 18 20 TDO TDI TMS TRST TCK P0.26 P0.25 P0.24 P0.23 VDDA VSSA VREF+ VREFR7 P0 P0.26 P0.25 P0.24 P0.23 VDDA VSSA VREF+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 RSTOUT VREFRESET P1.31 P1.30 P0.28 P0.27 GND P0.28 P0.27 P3.26 P3.25 3V3 C21 1 3 0.1uF 4 C22 5 0.1uF P0.10 11 P0.2 10 P0.11 12 P0.3 9 15 GND MAX3232CSE VU3 C1+ C1C2+ C2VCC V+ 16 C24 2 C23 0.1uF 14 RXD2 7 13 TXD2 8 6 C25 0.1uF ISP P0.2 1 P0.3 2 P2.10 3 RESET 4 S_COM RXD2 1 2 3 4 5 6
3,5;4,6选选选电0 1,3;2,4选选选电2

3V3

GND

3V3

PLED
LED_POWER LED供电电电

R8 680

供电供电电电

1 2 3 4 5 6 7 8 9

P_BATT 1 2

TDO/SWO TDI TMS/SWDIO TRST TCK/SWDCLK P0.26/AD0.3/AOUT/RXD3 P0.25/AD0.2/I2SRX_SDA/TXD3 P0.24/AD0.1/I2SRX_WS/CAP3.1 P0.23/AD0.0/I2SRX_CLK/CAP3.0 VDDA VSSA VREF+ NC RSTOUT VREFRTCX1 RESET RTCX2 VBAT P1.31/SCK1/AD0.5 P1.30/VBUS/AD0.4 XTAL1 XTAL2 P0.28/SCL0/USB_SCL P0.27/SDA0/USB_SDA P3.26/STCLK/MAT0.1/PWM1.3 P3.25/MAT0.0/PWM1.2 VDDIO_1 P0.29/USB_D+ P0.30/USB_DVSS_1 P1.18/USB_UP_LED/PWM1.1/CAP1.0 P1.19/MC0A/USB_PPWR/CAP1.1 P1.20/MCFB0/PWM1.2/SCK0 P1.21/MCABORT/PWM1.3/SSEL0 P1.22/MC0B/USB_PWRD/MAT1.0 P1.23/MCFB1/PWM1.4/MISO0 P1.24/MCFB2/PWM1.5/MOSI0 P1.25/MC1A/MAT1.1 P1.26/MC1B/PWM1.6/CAP0.0 VSS_2 VDDREG_1 P1.27/CLKOUT/USB_OVRCR/CAP0.1 P1.28/MC2A1.0/MAT0.0 P1.29/MC2B/PCAP1.1/MAT0.1 P0.0/RD1/TXD3/SDA1 P0.1/TD1/RXD3/SCL1 LPC1768 P0.10/TXD2/SDA2/MAT3.0 P0.11/RXD2/SCL2/MAT3.0 P2.13/EINT3/I2STX_SDA LPC1768_1

P2.12/EINT2/I2STX_WS P2.11/EINT1/I2STX_CLK P2.10/EINT0/NMI VDDIO_2 VSS_3 P0.22/RTS1/TD1 P0.21/RI1/RD1 P0.20/DTR1/SCL1 P0.19/DSR1/SDA1 P0.18/DCD1/MOSI0/MOSI P0.17/CTS1/MISO0/MISO P0.15/TXD1/SCK0/SCK P0.16/RXD1/SSEL0/SSEL P2.9/USB_CONNECT/RXD2 P2.8/TD2/TXD2 P2.7/RD2/RTS1 P2.6/PCAP1.0/RI1/TRACECLK P2.5/PWM1.6/DTR1/TRACEDATA0 P2.4/PWM1.5/DSR1/TRACEDATA1 P2.3/PWM1.4/DCD1/TRACEDATA2 VDDIO_3 VSS_4 P2.2/PWM1.3/CTS1/TRACEDATA3 P2.1/PWM1.2/RXD1 P2.0/PWM1.1/TXD1 P0.9/I2STX_SDA/MOSI1/MAT2.3 P0.8/I2STX_WS/MISO1/MAT2.2 P0.7/I2STX_CLK/SCK1/MAT2.1 P0.6/I2SRX_SDA/SSEL1/MAT2.0 P0.5/I2SRX_WS/TD2/CAP2 P0.4/I2SRX_CLK/RD2/CAP2.0 P4.28/RX_MCLK/MAT2.0/TXD3 VSS_6 VDDREG_2 P4.29/TX_MCLK/MAT2.1/RXD3 P1.17/ENET_MDIO P1.16/ENET_MDC P1.15/ENET_REF_CLK P1.14/ENET_RX_ER P1.10/ENET_RXD1 P1.9/ENET_RXD0 P1.8/ENET_CRS P1.4/ENET_TX_EN P1.1/ENET_TXD1 P1.0/ENET_TXD0 VDDIO_4 VSS_5 P0.3/RXD0/AD0.6 P0.2/TXD0/AD0.7 RTCK

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 99 98 100

P2.12 P2.11 P2.10 VDDIO_2 VSS_3 P0.22 P0.21 P0.20 P0.19 P0.18 P0.17 P0.15 P0.16 P2.9 P2.8 P2.7 P2.6 P2.5 P2.4 P2.3 VDDIO_3 VSS_4 P2.2 P2.1 P2.0 P0.9 P0.8 P0.7 P0.6 P0.5 P0.4 P4.28 VSS_6 VDDREG_2 P4.29 P1.17 P1.16 P1.15 P1.14 P1.10 P1.9 P1.8 P1.4 P1.1 P1.0 VDDIO_4 VSS_5 P0.3 P0.2

P3 3V3 C20 0.1uF P2.12 P2.11 P2.10 VDDIO_2 VSS_3 P0.22 P0.21 P0.20 P0.19 P0.18 P0.17 P0.15 P0.16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 P2.9 P2.8 P2.7 P2.6 P2.5 P2.4 P2.3 VDDIO_3 VSS_4 P2.2 P2.1 P2.0

P2.0

P2.1

P2.2

P2.3 GND

LED

POWER_LED

BT1

GND

JTAG
GND

Battery

3V3 R13 P2.10 10K S2 SW-PB GND INT0
INT0

3V3 P2.11

R14 10K S3

3V3 P2.12

R15 10K S4

3V3

10K C10 S1 0.1uF

VDDA 10 VSSA 11 VREF+ 12 13 RSTOUT 14 VREF- 15 RX1 16 RESET 17 RX2 18 VBAT 19 P1.31 P1.30 X1 X2 20 21 22 23 24 25 26 27

IO&PIN

3V3 C19 0.1uF P2 P0.9 1 P0.8 2 P0.7 3 P0.6 4 P0.5 5 P0.4 6 P4.28 7 VSS_6 8 VDDREG_2 9 P4.29 10 P1.17 11 P1.16 12 13 14 15 16 17 18 19 20 21 22 23 24 P1.15 P1.14 P1.10 P1.9 P1.8 P1.4 P1.1 P1.0 VDDIO_4 VSS_5 P0.3 P0.2

SW-PB
key1

SW-PB GND
key2

2 1

GND

SW-PB

INT0&KEY
3V3 0.1uF GND 3V3 COM 1 6 2 RTS 7 3 8 DTR 4 9 5 GND

IO&PIN

GND

C15 0.1uF P1 11 10 P3.26 P3.25 VDDIO_1 P0.29 P0.30 VSS_1 P1.18 P1.19 P1.20 P1.21 P1.22 P1.23 P1.24 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 P1.25 P1.26 VSS_2 VDDREG_1 P1.27 P1.28 P1.29 P0.0 P0.1 P0.10 P0.11 P2.13 GND

VDDIO_1 28 P0.29 29 P0.30 30 VSS_1 31 P1.18 P1.19 P1.20 P1.21 P1.22 P1.23 P1.24 P1.25 P1.26 32 33 34 35 36 37 38 39 40

GND

C18 0.1uF 3V3 RX1 1

IO&PIN

TXD2

C14 10PF Y1 GND

GND

2

RX2 3V3 C17 0.1uF X2 GND X1

C13 10PF C12

D Connector 9

C16 0.1uF 3V3

VSS_2 41 VDDREG_1 42 P1.27 P1.28 P1.29 P0.0 P0.1 P0.10 P0.11 P2.13 43 44 45 46 47 48 49 50

1

22PF Y2 GND

GND 3V3 R18 10K

2

IO&PIN

UART&ISP

C11 22PF

RTCK

Q2 8050
ISP

R16 33K

DTR Power_1 GND 1 2 3 GND
1,2USB供供 2,3供电电电供供

S_d 1 3 2 4

P2.10 RESET

Q1 8050 D6

R17 33K

RTS

D7

Diode 1N4148
使使选电0下下下下,1,2;3,4一一一一电

GND Diode 1N4148 GND
USB_DVUSB

C27 20pF

P1.30 R19 22 R20

R21 4k7

C26 0.1uF J1 1 2 3 4 VBUS DD+ GND 787780-1 power 1 3 2

VCC 3V3 U2 C8 220uF C6 0.01uF C5 0.1uF 3 1 IN GND OUT OUT 2 4 C7 0.1uF 3V3 C9 220uF L1 10uH L3 10uH VDDA C1 0.1uF C2 1uF L2 10uH L4 10uH VREF+ C3 0.1uF C4 1uF

P0.30 3V3 R26 4.7K P0.28 P0.27 R25 4.7K 8 6 5 4
USB_D+

P0.29 U4 VCC WP SCL A0 SDA A1 GND A2 24C02 PNP_8550 R23 GND 10k 7 1 2 3 C28 20pF

22 R22 1K5

REG1117-3.3

MINA_POWER USB_DEVICE
POWER_S GND GND

VSSA

VREF-

GND 3V3 Q3

USB_CONNECT S_USB

R24 2K

P2.9

1 2 3 GND
2,3直电电电 1,2芯芯电电

图 2 硬件电路原理图
天下的人(红豆电子)与贞明电子协同打造 6

电子让生活更美好

2.2 电源电路
Power_1
1,2USB供供 2,3供电电电供供

1 2 3

VCC 3V3 power U2 1 3 2 C8 220uF C6 0.01uF C5 0.1uF 3 1 IN GND OUT OUT 2 4 C7 0.1uF 3V3 C9 220uF L1 10uH L3 10uH VDDA C1 0.1uF C2 1uF L2 10uH L4 10uH VREF+ C3 0.1uF C4 1uF

REG1117-3.3

MINA_POWER
GND GND

VSSA

VREF-

POWER_S

LPC17XX 系列微控制器在电源部分需要五种电压源对其供电, 分 别是: A、 内核和外部通路所需的 3.3V 电源 VDD(3V3) ; B、 内部稳压器所需的 3.3V 电源 VDD(REG) (3V3) ; C、 模拟部分(如片上 ADC 和 DAC)所需的 3.3V 电源; D、 模数转换器 ADC 所需的参考电源 VREFP; E、 实时时钟 RTC 所需的 3.3V 电源 VBAT; 在本设计中电源采用外部 5V 供电, 可以是 USB 取电也可以是电 源适配器供电。通过 Power_1 短路冒选择,若短路 1、2 则是 USB 取电。若短路 2、3 则是电源接口取电!电源进入目标板后首先经 过一个开关 POWER_S,控制电源的通断。然和经过 C5、C6、C8 三 个电容滤波, 输入 1117-3.3 以获得 3.3V 电源。 LPC1768 具有独立 的模拟电源和 AD 输入参考电压,为了降低噪声和出错几率,模拟 电源和数字电源需要隔离,本设计的 L1-L4 就是将数字电源的高 频噪声和模拟电源隔离。 1117-3.3 是 3.3V 稳压芯片输出电流高达 800mA。实时时钟 RTC 部分本部分采用纽扣电池供电,供电管脚连 接短路冒,不用时可以取掉。
天下的人(红豆电子)与贞明电子协同打造 7

电子让生活更美好

2.3 复位电路
3V3 R7 10K C10 S1 0.1uF

SW-PB GND

LPC17XX 系列微控制器拥有 4 个复位源, 分别是外部 RESET 复位, 看门狗复位,上电复位(POR)以及掉电检测复位(BOD) 。本部分 硬件电路完成上电复位和外部复位。 本设计中芯片的外部复位和上电复位由按键复位和 RC 复位电路 完成。芯片是低电平复位有效,当复位管脚上的低电平持续一定 的时钟周期就会发生芯片复位。上电时复位低电平时间由 RC 的值 决定。 手动复位时需要按下复位按键 S1, 当松开复位按键 S1 后复 位发生。 2.4 系统时钟电路

天下的人(红豆电子)与贞明电子协同打造

8

电子让生活更美好

RX1 1

C14 10PF Y1 GND

RX2 X1

2

C13 10PF C12

1

22PF Y2 GND

X2

2

C11 22PF

LPC17XX 包括 3 个独立的时钟源,分别为主时钟振荡器、RTC 时 钟振荡器和内部 RC 振荡器,在 LPC17XX 复位后,LPC17XX 将由内 部 RC 振荡器提供时钟直至由软件切换到另外的时钟振荡源为止, 这使得系统可以不依懒于外部时钟进行操作,而且使引导加载程 序可以在一个确定的频率下进行操作。 A、 内部 RC 振荡器 内部 RC 振荡器(IRC)可以作为看门狗的时钟源,也可以作为 时钟,驱动锁相环(PLL)提供给 CPU。IRC 的精度不足,因此不 能用于 USB 接口, 通常 IRC 频率是 4MHz, 在开机或者芯片复位时, LPC17XX 使用 IRC 作为时钟源, 之后可以通过软件切换使用其他的 时钟源。 B、 主晶振 主晶振可以用于使用或者不是用 PLL0 为 CPU 提供时钟, 其频率 范围是 1-24MHz,这个频率可以通过主 PLL(PLL0)倍频至更高的 频 率 直 到 CPU 最 大 频 率 。 通 常 把 主 晶 振 输 出 的 时 钟 称 为
天下的人(红豆电子)与贞明电子协同打造 9

电子让生活更美好

OSC_CLK,PLL0 输入引脚上的时钟称为 PLLCLKIN,ARM 处理器时钟 频率称为 CCLK, 当使用主晶振提供时钟并不激活 PLL 时, PLLCLKIN 和 CCLK 的值直接相等。 LPC17XX 的板上晶振可以工作在两种模式下: 从属模式 (一般使 用有源晶振的情况)和震荡模式(普通晶振) ,在从属模式下,输 入时钟信号(XTAL1 引脚)与一个 100pF 电容相连,其幅值不得少 于 200mV,XTAL2 引脚不连接。在震荡模式下,由于片内集成了反 馈电阻,所以主需要在外部连接一个晶振和电容就可以形成基本 模式震荡。本设计中使用震荡模式。 C、 RTC 晶振 RTC 晶振的频率是 32.768KHz, 一般用于给 RTC 实时时钟提供时 钟源,RTC 时钟源可以提供1Hz 给 RTC 并且可以输出 32KHz 的时 钟频率,作为 PLL0 和 CPU 或者看门狗定时器使用时钟源。 本设计中 Y1 是 RTC 时钟使用 32.768KHz 晶振, 是主晶振使用 Y2 12MHz 晶振。 2.5 JTAG 接口电路
3V3 GND 3V3 3V3 R6 R5 R4 R3 R2 R1 10K 10K 10K 10K 10K 10K TRST TDI TMS TCK RTCK TDO RESET JTAG 1 3 5 7 9 11 13 15 17 19 2 4 6 8 10 12 14 16 18 20

JTAG
GND

天下的人(红豆电子)与贞明电子协同打造

10

电子让生活更美好

采用 ARM 公司提出的标准 20 脚 JTAG 仿真调试接口,JTAG 信号 的定义及与 LPC1768 的连接如图。在 RTCK 引脚接一个 4.7K 的下 拉电阻,使系统复位后 LPC1768 内部 JTAG 接口使能,这样就可以 直接进行 JTAG 仿真调试了。 2.6 串口电路
3V3 C21 0.1uF C22 0.1uF 1 3 4 5 U3 C1+ C1C2+ C2VCC V+ 16 C24 2 C23 0.1uF 14 RXD2 7 13 TXD2 8 GND MAX3232CSE V6 C25 0.1uF ISP P0.2 1 P0.3 2 P2.10 3 RESET 4 S_COM RXD2 1 2 3 4 5 6
3,5;4,6选选选电 0 1,3;2,4选选选电 2

0.1uF GND 3V3 COM 1 6 2 RTS 7 3 8 4 DTR 9 5 GND

P0.10 11 P0.2 10 P0.11 12 P0.3 9 15

11 10

TXD2

D Connector 9

GND

UART&ISP

Max3232 是工作在 3.3V 的 RS232 电平转换芯片,内部有 2 组串 口转换电路,本设计中将 LPC1768 的串口 0 和串口 2 引出,通过 跳线帽复用一个串口头,当 S_COM 的 1、3,2、4 短路的时候选择 串口 2,3、5,4、6 短路的时候选择串口 0。在通过 RS232 串口 ISP 编程的时候必须将串口选择在串口 0 上。使用 TTL 电平通过 ISP 口进行 ISP 编程的时候没有这个限制。 由于在用串口 ISP 编程 的时候要使用到串口的 RTS 和 DTR 引脚,所以在进行串口 ISP 编 程的时候不能使用 3 线串口。必须使用支持 RTS 和 DTR 的串口。

天下的人(红豆电子)与贞明电子协同打造

11

电子让生活更美好

2.7 按键电路
R13 P2.10 10K S2 SW-PB GND INT0
INT0

3V3 P2.11

R14 10K S3

3V3 P2.12

R15 10K S4

3V3

SW-PB
key1

SW-PB GND
key2

2 1

GND

INT0&KEY

LPC1768 最小板上一个设有 3 个通用按键和一个复位按键, 其中 INT0 既可以做普通按键用也可以做外部中断使用。其余 2 个是普 通按键。设计上每一个按键都添加了一个 10K 的上拉电阻。 2.8 LED 显示电路
3V3 3V3 R12 680 R11 680 R10 680 R9 680 D5 LED2 D1 LED2 D2 LED2 D3 LED2 D4 LED2

PLED
LED_POWER LED供电电电

2 1

R8 680

P2.0

P2.1

P2.2

P2.3 GND

LED

POWER_LED

LPC1768 最小板上有 4 个通用 LED 灯和一个电源指示灯,通用 LED 采用灌电流设计,并且有一个使能短路冒,当拔掉短路冒时 LED 电路断电。 2.9 EEPROM 电路
3V3 R26 4.7K P0.28 P0.27 R25 4.7K 8 6 5 4

U4 VCC SCL SDA GND 24C02 WP A0 A1 A2 7 1 2 3

GND

天下的人(红豆电子)与贞明电子协同打造

12

电子让生活更美好

LPC1768 支持 400K 高速模式的硬件 IIC 接口,所以设计了一片 24C02 为系统扩展一块电可擦除存储器。 用于系统保持掉电需要保 护的数据。 24C02 操作简便性能稳定, 是保存小量数据的不错选择。 为了减小总线操作功耗,总线的上拉电阻使用 4.7K。 2.10 USB 从机电路
GND GND C26 0.1uF J1 1 VBUS 2 D3 D+ 4 GND 787780-1 R22 1K5 GND 3V3 Q3
USB_CONNECT S_USB

VUSB USB_D-

C27 20pF

P1.30 R19 22 R20

R21 4k7

P0.30
USB_D+

P0.29 C28 20pF

22

USB_DEVICE

PNP_8550 R23 10k R24 2K

P2.9

1 2 3 GND
2,3直电电电

为了实现 USB 数据通讯和 USB bootloader 下载程序,LPC1768 最小板板载了 USB 从机接口,此电路不但有 USB 总线的基本辅助 原件,还有一个 USB 全速配置端口,USB 主机的 D+和 D-总线是有 下拉电阻的, D+上出现上升沿时说明有一个 USB 全速设备插入, 当 当 D-上上出现上升沿时说明由一个 USB 低速设备插入。LPC1768 支持 USB 全速,因此需要在 D+上由一个 1.5K 的上拉电阻。如果 S_USB 2,3 脚短接,则 Q3 上电就导通,则无论何时接上 USB 接口 都将使 USB 主机认为有一个全速 USB 插入。如果 1,2 短接则受到 程序通过 P2.9 号管脚控制。这样可以使系统在做 USB 通讯时才让
天下的人(红豆电子)与贞明电子协同打造 13

电子让生活更美好

主机认为由一个 USB 全速设备插入。 2.11 LPC1768 芯片
U1 TDO TDI TMS TRST TCK P0.26 P0.25 P0.24 P0.23 VDDA VSSA VREF+ VREFR7 10K C10 S1 0.1uF P1.31 P1.30 X1 X2 P0.28 P0.27 P3.26 P3.25 3V3 C15 0.1uF VDDIO_1 28 P0.29 29 P0.30 30 VSS_1 31 P1.18 P1.19 P1.20 P1.21 P1.22 P1.23 P1.24 P1.25 P1.26 32 33 34 35 36 37 38 39 40 20 21 22 23 24 25 26 27 1 2 3 4 5 6 7 8 9 TDO/SWO TDI TMS/SWDIO TRST TCK/SWDCLK P0.26/AD0.3/AOUT/RXD3 P0.25/AD0.2/I2SRX_SDA/TXD3 P0.24/AD0.1/I2SRX_WS/CAP3.1 P0.23/AD0.0/I2SRX_CLK/CAP3.0 VDDA VSSA VREF+ NC RSTOUT VREFRTCX1 RESET RTCX2 VBAT P1.31/SCK1/AD0.5 P1.30/VBUS/AD0.4 XTAL1 XTAL2 P0.28/SCL0/USB_SCL P0.27/SDA0/USB_SDA P3.26/STCLK/MAT0.1/PWM1.3 P3.25/MAT0.0/PWM1.2 VDDIO_1 P0.29/USB_D+ P0.30/USB_DVSS_1 P1.18/USB_UP_LED/PWM1.1/CAP1.0 P1.19/MC0A/USB_PPWR/CAP1.1 P1.20/MCFB0/PWM1.2/SCK0 P1.21/MCABORT/PWM1.3/SSEL0 P1.22/MC0B/USB_PWRD/MAT1.0 P1.23/MCFB1/PWM1.4/MISO0 P1.24/MCFB2/PWM1.5/MOSI0 P1.25/MC1A/MAT1.1 P1.26/MC1B/PWM1.6/CAP0.0 VSS_2 VDDREG_1 P1.27/CLKOUT/USB_OVRCR/CAP0.1 P1.28/MC2A1.0/MAT0.0 P1.29/MC2B/PCAP1.1/MAT0.1 P0.0/RD1/TXD3/SDA1 P0.1/TD1/RXD3/SCL1 P0.10/TXD2/SDA2/MAT3.0 P0.11/RXD2/SCL2/MAT3.0 P2.13/EINT3/I2STX_SDA LPC1768_1 P2.12/EINT2/I2STX_WS P2.11/EINT1/I2STX_CLK P2.10/EINT0/NMI VDDIO_2 VSS_3 P0.22/RTS1/TD1 P0.21/RI1/RD1 P0.20/DTR1/SCL1 P0.19/DSR1/SDA1 P0.18/DCD1/MOSI0/MOSI P0.17/CTS1/MISO0/MISO P0.15/TXD1/SCK0/SCK P0.16/RXD1/SSEL0/SSEL P2.9/USB_CONNECT/RXD2 P2.8/TD2/TXD2 P2.7/RD2/RTS1 P2.6/PCAP1.0/RI1/TRACECLK P2.5/PWM1.6/DTR1/TRACEDATA0 P2.4/PWM1.5/DSR1/TRACEDATA1 P2.3/PWM1.4/DCD1/TRACEDATA2 VDDIO_3 VSS_4 P2.2/PWM1.3/CTS1/TRACEDATA3 P2.1/PWM1.2/RXD1 P2.0/PWM1.1/TXD1 P0.9/I2STX_SDA/MOSI1/MAT2.3 P0.8/I2STX_WS/MISO1/MAT2.2 P0.7/I2STX_CLK/SCK1/MAT2.1 P0.6/I2SRX_SDA/SSEL1/MAT2.0 P0.5/I2SRX_WS/TD2/CAP2 P0.4/I2SRX_CLK/RD2/CAP2.0 P4.28/RX_MCLK/MAT2.0/TXD3 VSS_6 VDDREG_2 P4.29/TX_MCLK/MAT2.1/RXD3 P1.17/ENET_MDIO P1.16/ENET_MDC P1.15/ENET_REF_CLK P1.14/ENET_RX_ER P1.10/ENET_RXD1 P1.9/ENET_RXD0 P1.8/ENET_CRS P1.4/ENET_TX_EN P1.1/ENET_TXD1 P1.0/ENET_TXD0 VDDIO_4 VSS_5 P0.3/RXD0/AD0.6 P0.2/TXD0/AD0.7 RTCK 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 99 98 100 P2.12 P2.11 P2.10 VDDIO_2 VSS_3 P0.22 P0.21 P0.20 P0.19 P0.18 P0.17 P0.15 P0.16 P2.9 P2.8 P2.7 P2.6 P2.5 P2.4 P2.3 VDDIO_3 VSS_4 P2.2 P2.1 P2.0 P0.9 P0.8 P0.7 P0.6 P0.5 P0.4 P4.28 VSS_6 VDDREG_2 P4.29 P1.17 P1.16 P1.15 P1.14 P1.10 P1.9 P1.8 P1.4 P1.1 P1.0 VDDIO_4 VSS_5 P0.3 P0.2 GND RTCK 3V3

3V3 C20 0.1uF

供电供电电电

P_BATT 1 2 BT1

GND

Battery

3V3

VDDA 10 VSSA 11 VREF+ 12 13 RSTOUT 14 VREF- 15 RX1 16 RESET 17 RX2 18 VBAT 19

3V3 C19 0.1uF

SW-PB GND

GND

GND

GND

C18 0.1uF

GND

C16 0.1uF 3V3

VSS_2 41 VDDREG_1 42 P1.27 P1.28 P1.29 P0.0 P0.1 P0.10 P0.11 P2.13 43 44 45 46 47 48 49 50

3V3 C17 0.1uF

LPC1768

上图就是 LPC1768 芯片管脚连接图,在每一对 VDD 和 VSS 之间 都有一个 0.1uF 的去耦电容,以保证芯片正常稳定工作。

天下的人(红豆电子)与贞明电子协同打造

14

电子让生活更美好

第三部分 编译环境和程序下载 3.1 编译环境 LPC1768 的编译环境主要有 keil 或称 MDK 和 IAR,目前最新版 本 4.12(这里说的 keil 是指 keil 的 ARM 版本,不是指 keil 的 51 版本) 。这两个编译软件都是比较有名的编译器,其中用过 51 的人不会不知道 keil,当然 IAR 也是一个强大的编译器, 有良好的 C++支持能力。一般入门我们选择 keil,因为 keil 操作简单使用 方便。下面就介绍一下如何通过 keil 创建一个 LPC1768 的工程。 Keil 软件可以在官方网站上下载到限制版,当然你不喜欢限制版 那就找个国内的破解软件吧! Google 一下就出来了。 然后安装 keil 软件,一般 keil 被安装在 C:\keil 路径下,不要改变其默认路径 否则有可能出现编译头文件找不到路径的可能。安装好 keil 后会

在桌面上出现快捷方式如图所示:

。双击快捷方式将打开

keil 软件,如下图所示,一般打开后显示上次关闭时的工程。

新建工程步骤:
天下的人(红豆电子)与贞明电子协同打造 15

电子让生活更美好

A、点击 Project 菜单下的 New uVision Project。如图:

B、出现保存工程的界面,保存到我们想要保存的路径下,文件 名即为本工程名, 注意工程文件众多建议新建一个空文件夹保存。

C、选择芯片,在 NXP 列表下选择 LPC1768 芯片。然后点击 OK。 接下来出现的对话框选择“是” ;

天下的人(红豆电子)与贞明电子协同打造

16

电子让生活更美好

D、到现在一个工程就创建好了:

E、下面新建一个文件,点击 F、然后点击保存

或者 File 菜单下的 New。

,出现保存对话款,输入文件名以.c 为后
17

天下的人(红豆电子)与贞明电子协同打造

电子让生活更美好

缀名。

G、 接下来右键点击左侧 Target1 下的 Source Group1 的下拉菜 单的 Add File to Group…将我们刚刚新建的文件添加到工程。

F、出现添加对话框后选择新建的文件或已有的 C 程序源文件, 然后点击 Add,点击 Add 后就可以点击 Add 下面的 Close 了。

天下的人(红豆电子)与贞明电子协同打造

18

电子让生活更美好

接下来就可以编写程序了。编写好程序,点击编译 不过要想生成 hex 文件还要点击



配置工程 output。 Create 将

HEX File 前方框打钩,然后点击 OK。

这样工程在编译的时候就会自动生成 HEX 文件了。如果需要使 用 jlink 在 keil 环境下调试和下载程序,需要在 Debug 菜单下选 择 Use Cortex-M3 J-LINK 然后点击 Seting。 seting 下的 debug 在 菜单下的 Prot 选择 SW,MAX Clock 选择 3M,在 flash download 页面下点击 ADD,选择合适的型号和容量,点 OK 后到 Utilities
天下的人(红豆电子)与贞明电子协同打造 19

电子让生活更美好

菜单下选择 Use Cortex-M3 J-LINK。

天下的人(红豆电子)与贞明电子协同打造

20

电子让生活更美好

接下来我们就可以使用

下载程序和使用

调试了。到

此关于 keil 建立工程就介绍完了。 3.2 使用 JLINK 下载 Jlink 是调试 ARM 的一个很好的工具, 因其支持 ARM 家族, 同时 也支持 KEIL 和 IAR 等 IDE 环境,所以受到大多数的开发工程人员 的喜爱。上文介绍的基于 keil 的下载和调试就是基于 jlink 仿真 器的。Jlink 是 SEGGER 公司研制的,要使用 jlink 当然要安装该 公司推出的配套软件了。软件可以在官方网站上下载到。下面我 们将介绍如何用 jlink 官方提供的软件进行程序下载和读出。首

先安装 JLinkARM,然后双击打开软件

,打开后如图所示:

使用之前要设置好目标芯片型号和通讯方式等参数,点击 下的 Project settings ,在弹出的对话框中点击 Target Interface 选择 SWD 和 Auto selection,然后选择 CPU 页面,在
天下的人(红豆电子)与贞明电子协同打造 21

电子让生活更美好

Device 中选择 LPC1768,然后确定。然后选择 File 下的 Open 打 开生成 HEX 文件,点击 Target 菜单下的 Auto 就可以了。呵呵, 这是最简单的方法,关于 MCU 编程、擦除、读出都在 Target 里实 现。只要认识英文就知道怎么操作了,不认识可以 Google。关于 jlink 烧写软件的介绍就到这里。 3.3 使用 NXP 公司提供的 ISP 软件下载程序 对于学生而言使用 NXP 公司的 ISP 软件下载无疑是最节省成本 的,只需要一个串口或者 USB 转串口。但是对于开发人员大多数 时候需要调试程序,建议还是用仿真器。使用之前要准备一条串 口线,RS232 或者 TTL 的都可以,但是要支持 RTS 和 DTR,不能使 用最简单的三线串口,硬件连接如果是 RS232 直接插上目标板就 可以了,如果是 TTL 那就是 DTR 控制复位,RTS 控制 ISP 管脚。打 开 Flash Magic 后如图所示:

点击

选择芯片, 点击
天下的人(红豆电子)与贞明电子协同打造

选择串
22

电子让生活更美好

口,

选择波特率,一般波特率选择太低

就会很慢,建议选择稍微高一点。在芯片擦除前面打钩 ,然后加载 hex 文件:

在校验后编程前的方框打钩

,然后点击开始

。接下来就是等待编程结束了。 NXP 公司的 ISP 软件就介绍到这里, 在选型的时候可能你会注意 到支持众多 NXP 的芯片!

天下的人(红豆电子)与贞明电子协同打造

23

电子让生活更美好

第四章 第四章 芯片编程介绍 4.1 系统文件介绍 在写程序的时候有一些东西是编译器自带的一些文件,比如芯 片的头文件,再比如汇编的启动代码,在 LPC17XX 里还有一个系 统初始化文件。在我们的工程里主要有 3 个头文件,2 个 C 文件, 1 个.S 文件。 分别是: LPC17xx.h 、 core_cm3.h、 system_LPC17xx.h; core_cm3.c 、 system_LPC17xx.c ; startup_LPC17xx.s ; 其 中 startup_LPC17xx.s 是 系 统 自 动 加 载 的 ARM 启 动 汇 编 代 码 。 LPC17XX.h 是芯片的头文件, 定义的是芯片寄存器的结构体。 有时 候有些寄存器和手册上写法有细微的区别,打开看一下就可以了 哈,需要注意的是 keil 在头文件里关于寄存器的定义都是以结构 体的方式定义的,所以我们在写程序的时候访问寄存器也要以寄 存器方式访问,比如在 GPIO 的操作的时候由一个名叫“FIODIR” 的方向寄存器,是一个 32 位的寄存器,对应一个 IO 口的 32 位, 如果某位为 1 则对应的管脚为输出模式,因此在访问的时候写法 如下: LPC_GPIO1->FIODIR=0x000000ff; GPIO1 表示 P1 口,GPIO2 表示 P2 口,上面这行代码表示 P1 口 的低 8 位为输出模式。由于 keil 版本的原因可能有些版本定义结 构体的时候没有 LPC_这个部分使得访问 GPIO1 的写法如下: GPIO1->FIODIR=0x000000ff; 关于这个的确认可以打开 LPC17XX.h 看一下就知道了。还有一
天下的人(红豆电子)与贞明电子协同打造 24

电子让生活更美好

点需要注意的是在 keil 的头文件里定义寄存器是以 32 位的方式 定义的,所以不能使用手册中说明的字,半字的访问方式只能使 用 32 位的访问方式即:

上图所示的 FIOxDIR0 是不能用的, 要访问端口 x 需要使用结构 体 方 式 , LPC_GPIOx->FIODIR=0x00000000; 不 能 写 成 FIOxDIR0=0x00; core_cm3.c、 core_cm3.h 分别是 ARM M3 外围驱动源代码和头文 件,在使用的过程中不需要修改什么,有兴趣的可以关注一下这 些代码的注释就知道这些代码是用来干什么的了。 system_LPC17xx.h、system_LPC17xx.c 这两个文件是与编程有非 常密切关系的文件。从名字上就可以知道是关于系统的文件,这 两个文件为我们提供了一个系统初始化函数,SystemInit();默认 使用外部晶振,外部晶振是 12MHz,使用 PLL0 倍频,LPC1700 的 系统初始化包括时钟配置、电源管理、功耗管理等。其中比较复 杂的是时钟配置,由于有 2 个 PLL,一个是主 PLL0,可以为系统 和 USB 提供时钟,一个是 PLL1 专门为 USB 提供 48M 时钟,可以不 使用。由于 LPC1700 的时钟灵活性较大,也使得配置时钟的过程 稍微复杂一些。但是我们的系统文件都将这些做好了,我们要修
天下的人(红豆电子)与贞明电子协同打造 25

电子让生活更美好

改时钟频率或者其他参数只需要修改对应的宏定义即可。另外该 文件还做了比较详尽的注释,只要潜心阅读没有太大难度的。在 LPC17xx.h 里有 core_cm3.h 和 system_LPC17xx.h 的调用, 因此我 们不需要在主函数里再次调用。如

下面叙述一下关于 keil 文件调用的一些方法; 在单片机的使用过程中一般程序都不会很大,需要调用的文件 比较少,我曾经把所有的程序放在一个“.c”文件里,这样在程 序不大的时候比较方便,但是这样不便于代码的重用也不便于代 码的管理,况且一旦代码量一大,查阅起来相当的不便。因此需 要把一些功能独立的代码分立出去,这样就有了功能独立的“.h” 和“.c”文件。在使用的时候比较普遍的做法是将源代码放在一 个工程文件夹里的一个专门的文件夹,当然这个文件夹里还可以 再有文件夹比如头文件的文件夹和源代码的文件夹或者是功能不 同的代码的文件夹,我觉得无论如何至少应该将代码放在工程文 件夹里的独立文件夹里,不应该直接放在工程文件夹里。一个功 能独立的源代码通常由一个.h 文件和一个.c 文件构成。 他们的文 件名是一样的如 UART 的功能源代码可以是:UART.h”“UART.c” “ 和 , 在主函数的调用时一般是写成#include”UART.h”;然后将 UART.c 添加到工程,这样在主函数中就可以使用添加的代码了。当然也 可以直接将.h 和.c 文件都包含进来, 也是可以在主函数中使用的。
天下的人(红豆电子)与贞明电子协同打造 26

电子让生活更美好

在 ARM 编程的工程中一般文件都比较多,最好由一个层次和清晰 的结构,避免影响阅读和使用。具体详尽的说明可以阅读 keil 的 帮助和说明文档。

4.2 LPC17xx 的基本使用介绍 在 LPC17xx 的编程过程中最基本的要注意的有两方面,一方面 是系统配置,另一方面是外围基础配置。系统配置包括系统时钟, 功耗管理,睡眠模式等等。外围的基础配置包括所使用模块的功 耗管理 (LPC17xx 出于降低总功耗的原因对每一个外设都有一个使 能方式的功耗管理,默认复位后有一些外设是默认开启的有一些 是默认关闭的,具体参见手册的第四章计时和功率控制的 4.8.9 外设功率控制寄存器 PCONP) 、时钟配置(外设时钟选择参见第 4 章计时和功率控制的 4.7.4 节外设时钟选择寄存器 PCLKSEL0 和 PCLKSEL1 的对应位) 管脚配置 、 (由于每一个管脚有多种功能因此 有专门的寄存器参见第 8 章引脚连接模块)等。 关于系统初始化: 关于系统初始化 在前面的介绍中我们知道 LPC17xx 只要有 3 个时钟源,分别是 内部 RC 振荡器、主晶振(1-24M) 、RTC 晶振,主晶振、RTC、内部 RC 都可以来驱动 PLL0 从而给 CPU 和片内外设提供时钟,当 PLL0 未连接时系统才可以安全的切换时钟源。时钟源的选择需要配置 时钟选择寄存器: 时钟源选择寄存器 (CLKSRCSEL,0x400FC10C)
天下的人(红豆电子)与贞明电子协同打造 27

电子让生活更美好

锁相环 PLL0 PLL0 接受输入的时钟范围是 32KHz-50MHz。 时钟源由 CLKSRCSEL 寄存器选择,输入频率可以倍频到一个较高的频率上,之后可以 通过分频为 CPU、 外设以及可选的 USB 子系统提供精确的时钟。 值 得注意的是 USB 子系统又有自己专用的 PLL。PLL0 可以产生最高 至 CPU 允许的最大 100M 的频率。 PLL0 的输入频率通过一个预分频器分频成为 PLL 内部频率,预 分频的值用变量 N 表示,范围 1-256 之间,然后通过一个电流控 制振荡器(CCO)倍频到范围 275-550M 之间,倍频器的值用 M 表 示,CCO 频率在通过 CPU 频率设置寄存器分频成为提供给 CPU 的 CCLK 时钟。 PPL 的使能是由 PLL0CON 寄存器控制,PLL0 倍频器和分频器的 值都是由 PLL0CFG 寄存器控制。为了防止 PLL0 参数发生意外改变 或 PLL0 失效,对这两个寄存器进行了保护。当 PLL0 提供芯片时 钟时,由于芯片的所有操作,包括看门狗定时器在内都依赖于它, 因此 PLL0 的设置的意外改变将导致 CPU 执行不期望的操作。 在芯片复位或者进入掉电模式后, PLL0 将被关闭或者屏蔽, PLL0 必须有软件配置、使能连接到系统中。PLL0 接口框图如图所示:
天下的人(红豆电子)与贞明电子协同打造 28

电子让生活更美好

下面描述 PLL0 涉及的寄存器及其功能描述 4.2.1 4.2.1、PLL0 控制寄存器 PLL0CON PLL0CO 寄存器可以用于使能和连接 PLL0、使能 PLL0 锁定到当 前倍频器和分配器值设定的频率上, 连接 PLL0 将使处理器和大多 数片内功能都根据 PLL0 的输出来工作。 PLL0CON 的更改只有在 对 对 PLL0CON 寄存器执行了正确的 PLL 馈送序列后才生效。

PLL0 在作为时钟源之前必须进行设置使能并锁定。将振荡器时 钟切换到 PLL0 输出或者翻转过来,操作时,内部电路对操作进行 同步以确保不会产生干扰,硬件不能保证 PLL 在连接之前锁定或 在 PLL0 失去锁定时自动断开连接,在 PLL0 失去锁定的情况下、 振荡器很可能已近变得不稳定,这样即使断开 PLL0 页挽救不了这 种情况。 4.2.2 PLL0CFG 4.2.2、PLL0 配置寄存器 PLL0CFG PLL0CFG 是最新的 PLL0 配置值的保持寄存器,包含 PLL 倍频器
天下的人(红豆电子)与贞明电子协同打造 29

电子让生活更美好

和分配器的值,在执行正确的 PLL0 馈送序列之前改变 PLL0CFG 寄 存器的值不会生效。

4.2.3 4.2.3、PLL0 状态寄存器 PLL0STAT PLL0STAT 为只读寄存器, 它是 PLL0 控制和配置信息的读回寄存 器,反映了正在使用真实 PLL0 的参数和状态。PLL0STAT 可能和 PLL0CON 和 PLL0CFG 中的值不同,这是因为没有正确的 PLL0 馈送 序列,这两个寄存器中的值并未生效。

PLL0STAT 寄存器中的 PLOCK0 位连接到中断控制器, 这样可以使 用软件打开 PLL0,并连接到其他功能、不需要等待 PLL0 锁定。当 发生中断时(PLOCK0=1)可以连接 PLL0 并禁止中断,只能通过禁 止 PLL0 中断的方式返回。 PLL0 有 3 中可能的工作方式,由 PLLE0 和 PLLC0 位组合获得:

天下的人(红豆电子)与贞明电子协同打造

30

电子让生活更美好

4.2.4 4.2.4、PLL0 馈送寄存器 PLL0FEED 必须将正确的馈送序列写入 PLL0FEED 寄存器才能使 PLL0CON 和 PLL0CFG 寄存器的更改生效,馈送序列如下: 将值 0xAA 写入 PLL0FEED 将值 0x55 写入 PLL0FEED 这两个写操作的顺序必须正确,而且在两次操作之间不需没有 其他的寄存器访问相同的地址空间,这就意味着尽量在执行 PLL0 馈送操作的时候禁止中断,不管写入的值不正确还是没有满足前 两个条件、对 PLL0CON 或者 PLL0CFG 寄存器的更改都不会生效。 4.2.5 4.2.5、PLL0 和掉电模式 掉电模式会自动关闭并断开 PLL0,从掉电模式唤醒不会自动的 恢复 PLL0 的设置,PLL0 的恢复必须由软件来完成。 4.2.6 4.2.6、PLL0 频率的计算

当 LPC17xx 微处理器系统需要使用 PLL0 时, 应当按照一下原则 进行计算配置。
天下的人(红豆电子)与贞明电子协同打造 31

电子让生活更美好

确定应用是否需要 USB 口, 并且 USB 是否由 PLL0 提供时钟, USB 需要一个准确的 50%占空比 48M 的时钟信号,这就意味着 FCCO 必 须是 48M 的整倍数(96M)并且 FCC0 要相当准确; 确定处理器的时钟频率 CCLK,这可以根据对处理器的整体要求 来确定,外围器件的时钟频率可以低于处理器的频率。 选择 PLL 输入频率 FIN 的值; 计算 M 和 N 的值,以产生一个有效且精确的 FCCO 的频率。 PLL0 的输出频率公式为:FCCO=(2*M*FIN)/N 例如:系统不需要 USB 口,目标 CPU 的速度为 72M,32.768K 的 RTC 时钟作为系统的时钟源,M=(FCCO*N)/(2*FIN),可以产生 CPU 需 求频率并且 PLL0 可以正常操作范围内的最小 FCCO 频率是 288M (4*72M) 。由 N=1 开始计算,所以 M=288*10^6/(2*32768)=4394.53. 计算所得不是一个整数,所以 CPU 的频率不是精确的 288M。 接下来介绍系统的初始化函数,System_LPC17xx.c 文件中的 void SystemInit (void)函数将繁琐的系统初始化工作都做好了,如果我们 还有一些特殊的要求可以直接修改该函数,就可以得到想要的设置。 函数源代码如下:
void SystemInit (void) { #if (CLOCK_SETUP) /* Clock Setup 时钟配置 */ LPC_SC->SCS = SCS_Val; if (SCS_Val & (1 << 5)) { /* If Main Oscillator is enabled 如果主振荡器使能 */ while ((LPC_SC->SCS & (1<<6)) == 0); /* Wait for Oscillator to be ready 等待准备 */ } LPC_SC->CCLKCFG = CCLKCFG_Val; /* Setup Clock Divider 时钟
天下的人(红豆电子)与贞明电子协同打造 32

电子让生活更美好

分频 */ #if (PLL0_SETUP) LPC_SC->CLKSRCSEL = CLKSRCSEL_Val; /* Select Clock Source for PLL0 为 PLL0 选择时钟源 LPC_SC->PLL0CFG = PLL0CFG_Val; /* configure PLL0 配置 PPL0 */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; LPC_SC->PLL0CON = 0x01; /* PLL0 Enable PLL 使能 */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; while (!(LPC_SC->PLL0STAT & (1<<26))); /* Wait for PLOCK0 */ LPC_SC->PLL0CON = 0x03; /* PLL0 Enable & Connect PLL0 使能和连接 */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24)))); /* Wait for PLLC0_STAT & PLLE0_STAT */ #endif #if (PLL1_SETUP) LPC_SC->PLL1CFG = PLL1CFG_Val; LPC_SC->PLL1FEED = 0xAA; LPC_SC->PLL1FEED = 0x55; LPC_SC->PLL1CON = 0x01; /* PLL1 Enable */ LPC_SC->PLL1FEED = 0xAA; LPC_SC->PLL1FEED = 0x55; while (!(LPC_SC->PLL1STAT & (1<<10))); /* Wait for PLOCK1 */ LPC_SC->PLL1CON = 0x03; /* PLL1 Enable & Connect */ LPC_SC->PLL1FEED = 0xAA; LPC_SC->PLL1FEED = 0x55; while (!(LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8)))); /* Wait for PLLC1_STAT & PLLE1_STAT */ #else LPC_SC->USBCLKCFG = USBCLKCFG_Val; /* Setup USB Clock Divider */ #endif LPC_SC->PCLKSEL0 = PCLKSEL0_Val; /* Peripheral Clock Selection */ LPC_SC->PCLKSEL1 = PCLKSEL1_Val;
天下的人(红豆电子)与贞明电子协同打造

*/

33

电子让生活更美好

LPC_SC->PCONP = PCONP_Val; /* Power Control for Peripherals */ LPC_SC->CLKOUTCFG = CLKOUTCFG_Val; /* Clock Output Configuration */ #endif #if (FLASH_SETUP == 1) /* Flash Accelerator Setup */ LPC_SC->FLASHCFG = FLASHCFG_Val; #endif }

从代码和注释可以看出,这个函数完成了对时钟的配置、系统 功耗 PCONP、时钟输出、flash 加速等系统资源配置。如果需要修 改该文件内还有详细的修改方法说明。对于没有特殊要求的应用 完全可以直接使用该函数不需修改对系统进行初始化。 初始化系统介绍完了,下面介绍功耗管理、外围时钟配置和管 脚分配。 外设功率控制 外设的功率控制特性允许在应用中关闭不需要的外设,从而节 省额外的功耗。涉及的寄存器是 PCONP。 外设功率控制寄存器 PCONP-0x400FC0C4 可通过 PCONP 寄存器关闭特定外设模块的时钟源来关闭外设, 以实现节电的目的。有少数外设功能不能被关闭(如看门狗定时 器、引脚连接模块和系统控制模块) 。 某些外设(特别是那些含有模拟功能的外设)的功耗可能与时 钟无关。这些外设有独立的禁止控制,可以关闭其电路来减少功 耗。有关外设特定的节省功耗的信息,请参考描述该外设的相关 章节。PCONP 中的每个位都控制一个外设,如表 4.33 所示。
天下的人(红豆电子)与贞明电子协同打造 34

电子让生活更美好

如果外设控制位为 1,则外设被使能。如果外设控制位为 0,则 外设的时钟被禁止,以节省功耗。例如,如果 19 为 1,则 IIC1 接口使能。如果 19 位为 0,则 IIC1 接口禁止。 注:仅当外设在 PCONP 寄存器中使能时,才能够从外设寄存器 中有效读取和有效写入外设寄存器。 (在初始化一个外设模块时应 当首先设置相关的功率控制寄存器)

天下的人(红豆电子)与贞明电子协同打造

35

电子让生活更美好

外设时钟控制 外设时钟控制涉及的寄存器有 2 个外设时钟选择寄存器。在复 位后寄存器是全 0,则对应的功能是所有外设时钟是系统时钟的 1/4,在一些应用中我们不需要配置时钟速度,但是有些应用如使 用定时器定时的时候我们需要准确的知道时钟周期或者需要较高 的时钟信号,这就需要配置这个寄存器。 外 设 时 钟 选 择 寄 存 器 0 和 1 ( PCLKSEL0-0x400fc1a8 和 PCLKSEL1-0x400fc1ac) 在外设时钟选择寄存器中,每组位控制了提供给对应外设的时 钟信号的速率。 注:RTC 模块的外设时钟固定为 CCLK/8.

天下的人(红豆电子)与贞明电子协同打造

36

电子让生活更美好

外设时钟选择寄存器 1:

从下面这个表格可以看出,每个外设对应的寄存器位如果是 00
天下的人(红豆电子)与贞明电子协同打造 37

电子让生活更美好

则表示对应的外设的时钟是 CCLK 的 1/4,01 则时钟是 CCLK 等。

管脚输出配置: 引脚连接模块使得微控制器的大部分引脚具有 1 个以上的功能。 配置寄存器控制多路开关以实现引脚与片内外设之间的连接。 外设应优先连接到适当的引脚,再激活,需要的话使能相关中 断。任何一个没有映射到相关功能引脚的使能外设,都将被认为 是未定义的。 当选择了引脚上的一个功能时,该引脚上其它可用功能无效。 涉及的寄存器有:PINSEL0-PINSEL10; PINSEL 寄存器控制器件引脚的功能,如表 8.2 所示。这些寄存 器的每一组位对应着特定的器件引脚功能。

仅当引脚选择 GPIO 功能时,GPIO 寄存器中的方向控制位才有 效。对于其它功能来说,方向是自动控制的。每个外围器件通常 有不同的引脚配置,因此每个引脚可能有不同的功能组合。 引脚模式选择寄存器 PINMODE 寄存器控制所有端口的工作模式。这包括使用片内上
天下的人(红豆电子)与贞明电子协同打造 38

电子让生活更美好

拉/下拉电阻的特性和特定的开漏操作模式。除过用于 IIC0 接口 的 IIC 引脚和 USB 引脚。不管该引脚选择用作何种功能,都可以 为每一个端口引脚选择片内上拉/下拉电阻。使用三个位来控制端 口引脚的模式,其中二个位位于 PINMODE 寄存器中,另一个位于 PINMODE_OD 寄存器中。在 PINSEL 寄存器中未使用的引脚看作为 保留位。

当引脚处于逻辑高电平时,中继模式使能上拉电阻;当引脚处 于逻辑低电平时,使能下拉电阻。当引脚配置为输入且不是通过 外部驱动时,引脚将保持上一个已知状态。 PINMODE_OD 寄存器 控制端口的开漏模式。当引脚被配置为输出且值为 0 时,开漏模 式会正常地将引脚电平拉低。但是,如果输出引脚值为 1,则引 脚的输出驱动关闭,等同于改变了引脚的方向。这样的组合就模 拟了一个开漏输出。

寄存器描述 引脚控制模块包含 11 个寄存器, 如表 8.5 所示。 在外部复位、 看门狗复位、上电复位(POR)和掉电检测复位(BOD)发生时, 该模块中的所有寄存器均复位为“0” 。
天下的人(红豆电子)与贞明电子协同打造 39

电子让生活更美好

引脚功能选择寄存器 0(PINSEL0 - 0x4002 C000) PINSEL0 寄存器控制端口 0 低半部分的位功能。 仅当引脚选择 使用 GPIO 功能时,FIO0DIR 寄存器中的方向控制位才有效。对于 其它功能来说,方向是自动控制的。 对于 100 引脚封装,引脚 功能选择寄存器 0 的位功能描述如下表所述。

天下的人(红豆电子)与贞明电子协同打造

40

电子让生活更美好

注:该部分的其它寄存器也类似引脚功能选择寄存器 0,在这 里就不一一列举了,需要详细的了解需参考英文技术手册或 ZLG 的中文技术手册的第 8 章引脚连接模块。 在使用一个片内外设的时候不但需要配置片内外设的寄存器, 还应该首先配置功耗控制、时钟选择和管脚配置,需要说明的是 在使用片内外设的时候应该首先配置功耗控制。

天下的人(红豆电子)与贞明电子协同打造

41

电子让生活更美好

第五章 第五章 实例详解 本章将详细介绍立足于本设计的最小系统板的实例编程。在这里从 最简单的编程开始,尽量拥有详尽的注释,尽量做到功能结构完整, 言辞尽量准确无误。 5.1 实验 1—4LED 跑马灯 1 本实验使用连接在 P2 口上的 4 个 LED 灯实现跑马灯的效果。 由于 LED 是采用管电流方式设计的, 所以当 P2.0 输出低电平时第一个 LED 灯亮。 本实验设计的编程有系统初始化、通用 IO 口的初始化、系统软延时和 通用 IO 口的输出等。 首先如第 3 章所述建立一个工程并且设置好工程。在 Project 里面 新建一个组,命名为 Source(本实验的所有代码、包括头文件都放在 这里) ,新建一个 main.c 文件,添加进 Source 组。在 main.c 中添加 如下代码:
#include "lpc17xx.h" // 包含头文件, 头文件内保护系统初始化头文件 void delay(void) //软延时函数,大工程中不建议使用,占用系统资源, { //M3 有系统节拍定时器,可以达到效果 uint32_t j; for(j = 3000000; j > 0; j--); } int main(void) { uint32_t i=0; //定义变量 SystemInit(); //系统初始化函数 LPC_SC->PCONP|=(1<<15); //功耗控制,此处可以注释掉,因为复位后 GPIO 默认开启 LPC_GPIO2->FIODIR=0x0000000F; //FIODIR 设置端口的输入输出 LPC_GPIO2->FIOSET=0x0000000F; //GPIO 置位,当某位为 1 则置位,为 0 不变 while(1) {
天下的人(红豆电子)与贞明电子协同打造 42

电子让生活更美好

for(i = 0; i < 4; i++) { LPC_GPIO2->FIOCLR = 1 << i; //GPIO 清零,为 1 清零,为 0 不变 delay(); } LPC_GPIO2->FIOSET=0x0000000F; delay(); } }

配置 keil 工程的选项,选择生成 HEX,配置仿真器 jlink。 在 Source 组里添加 system_LPC17xx.c 和 core_cm3.c(由于系统初 始 化 函 数 在 system_LPC17xx.c 中 定 义 , 要 调 用 该 函 数 则 要 访 问 system_LPC17xx.c,访问方式有 2 中一是工程中调用该文件对应的.h 文件然后在工程中添加.c 文件, 二是在工程中将.h 和.c 文件都调用) 。 编译,没有错误,下载到目标板上,可以看出 4 个 LED 灯依次被点亮, 然后熄灭,然后接着被依次点亮,循环。在程序中所偶寄存器的访问 都是基于结构体的,如 FIODIR 是 GPIO 的输入输出配置寄存器,访问 的 时 候 要 按 结 构 体 方 式 访 问 , 若 要 访 问 P1 口 则 有 LPC_GPIO1->FIODIR=0x00000000;由于 PCONP 在 LPC_SC 结构体定义的 所以访问时需要 LPC_SC->PCONP;结构体的定义都是按照功能定义在 LPC17xx.h 里的,不明白的查看一下。 注:需要将 LED 闪烁改成一个 LED 依次点亮,可以将: LPC_GPIO2->FIOCLR = 1 << i; 修改成: LPC_GPIO2->FIOPIN =~( 1 << i); 下面介绍一下通用 GPIO 的有关寄存器和中断寄存器映射表:
天下的人(红豆电子)与贞明电子协同打造 43

电子让生活更美好

中断寄存器映射表:

5.2 实验 2—4LED 跑马灯 2 通过上面一个实例我们很好的认识了 GPIO 的基本寄存器配置, 若需
天下的人(红豆电子)与贞明电子协同打造 44

电子让生活更美好

要从 GPIO 端口读入数据, 只需要将 FIODIR 配置成输入, 然和读 FIOPIN 即可。上一个实验使用的是软件延时的方法实现闪烁 LED 等的效果, 在需要定时的应用中,除非微小延时,一般不用软件延时,原因有 2 点,一是不准确,二是占用系统资源。所以下面介绍的一个 LED 实验 是使用 ARM Cortex-M3 内核带的一个系统节拍定时器的功能,实现延 时的目的。 系统节拍定时器,配置简单,使用方便,专为系统软件或系统管理 软件提供间隔中断。系统节拍定时器的时钟源可以是内核时钟,也可 以是 P3.26 选择 STCLK 功能提供的时钟。系统节拍定时器是一个 24 位 定时器,当计数值达到 0 时产生中断。系统节拍定时器的作用是为下 一次中断前提供一个固定时间间隔。由于定时器是 24 位的,在使用的 时候要注意定时长度的限制,不能超过界限。 系统节拍定时器的初始化函数在 core_cm3.h 里已经为我们写好。
static __INLINE uint32_t SysTick_Config(uint32_t ticks) { if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0); /* Function successful */ }
天下的人(红豆电子)与贞明电子协同打造 45

电子让生活更美好

主函数代码如下: #include "lpc17xx.h" // 包含头文件, 头文件内保护系统初始化头文件 //***************************************************** uint32_t msTicks,sign=0; //变量定义 //***************************************************** void SysTick_Handler(void) //系统节拍定时器中断函数 { msTicks++; //简单的定时++ 运算 if(msTicks==300) //定时满 500 次 一次 1ms 即 500ms 置位标志位 { sign=1; //标志位置位 msTicks=0; //定时变量 清零 } } int main(void) { uint32_t i=0; //定义变量 SystemInit(); //系统初始化函数 if (SysTick_Config(SystemCoreClock / 1000)) //系统节拍定时器初始化 函数在 core_cm3.h 里 { //设置节拍定时器 1ms 中断 注意系统节拍定时器只有 24 位 while (1); //不能越界 若越界则会出现此处的 whil(1)错误 } LPC_SC->PCONP|=(1<<15); //功耗控制,此处可以注释掉,因为复位后 GPIO 默认开启 LPC_GPIO2->FIODIR=0x0000000F; //FIODIR 设置端口的输入输出 LPC_GPIO2->FIOSET=0x0000000F; //GPIO 置位,当某位为 1 则置位,为 0 不变 while(1) { if(sign==1) //如果标志位置位 表示定时时间到 { sign=0; //标志位清零 LPC_GPIO2->FIOPIN =~( 1 << i); //GPIO2 管脚依次输出低电平 i++; //移位++ if(i==4) //4 位 满了 清零 i=0; } } }
天下的人(红豆电子)与贞明电子协同打造 46

电子让生活更美好

关于程序里面的变量定义的数据类型问题,个人认为在 8 位 MCU 里 使用 8 位变量处理速度比 16 位和 32 位变量快,而在 32 位 MCU 里处理 32 位变量的速度比 8 位变量的快,因此大多数情况是使用 32 位 int 型变量。关于变量定义的定义标识符,可以参见 core_cm3.c 调用的 stdint.h 文件里的定义,此处列举该文件里最常使用的几个: /* exact-width signed integer types */ typedef typedef typedef typedef signed signed short signed signed char int8_t; int int16_t; int int32_t; __int64 int64_t;

/* exact-width unsigned integer types */ typedef unsigned typedef unsigned short typedef unsigned typedef unsigned char uint8_t; int uint16_t; int uint32_t; __int64 uint64_t;

需要更详细的了解,可以打开此文件,该文件是 keil 自带的文件。

5.3 实验 3-UART 的使用 无论在系统调试还是通讯中,串口都起着重要的作用。本实验将介 绍 LPC17XX 的串口使用。LPC17XX 处理器有 4 个符合 16C550 工业标准 的异步串口,UART0-UART3,其中 UART1 具有标准的 MODEM 接口和 RS-485/EIA-485 模式。LPC17xx 处理器的 4 个串口具有以下特征:
天下的人(红豆电子)与贞明电子协同打造 47

电子让生活更美好

* UART 具有独立的 16 字节 FIFO * 寄存器位置符合 16C550 工业标准; * 接收器 FIFO 触发点可为 1、4、8 和 14 字节; * 内置波特率发生器; * 包含实现软件流控制的机制; * UART3 包含了一个支持红外通信的 IrDA 模式; 基本配置: 功率:位于 PCONP 寄存器中,设置 PCUART0/2/3 位。 注:复位时,UART0 会被使能(PCUART0=1) ,且 UART2/3 会被禁能 (PCUART2/3=0) 外 设 时 钟 : 位 于 PCLK_SEL0 寄 存 器 中 , 选 择 PCLK_UART0 ; 在 PCLK_SEL1 寄存器中,选择 PCLK_UART2/3。 波特率:位于 U0/2/3LCR 寄存器; UART FIFO:使用 U0/2/3FCR 寄存器中的 FIFO 使能位启动 FIFO; 管脚:通过 PINSEL 寄存器选择 UART 管脚; 中断:将 U0/2/3LCR 寄存器中的 DLAB 位置 0,使能 UART 中断。 DMA:UART0/2/3 的发生和接受可通过 GPDAM 控制器进行操作。 UART 的寄存器列表如下:

天下的人(红豆电子)与贞明电子协同打造

48

电子让生活更美好

在我们看来 UART 的寄存器配置比起 GPIO 来说复杂很多了,但是不 用担心 NXP 的工程师们早就给我们写好了 UART 功能函数文件,我们只 需要调用就能满足一般的应用,如果有特殊应用可以参照该文件自己 对照技术手册修改或编写出我们需要的程序即可。 下面就来看看为我们提供的 UART.h 和 UART.C 文件:

天下的人(红豆电子)与贞明电子协同打造

49

电子让生活更美好

文件: UART.h 文件
#ifndef __UART_H #define __UART_H #ifndef FALSE #define FALSE #endif #ifndef TRUE #define TRUE #endif #define IER_RBR #define IER_THRE #define IER_RLS #define #define #define #define #define #define #define #define #define #define #define #define #define IIR_PEND IIR_RLS IIR_RDA IIR_CTI IIR_THRE LSR_RDR LSR_OE LSR_PE LSR_FE LSR_BI LSR_THRE LSR_TEMT LSR_RXFE

(0)

(1)

0x01 0x02 0x04 0x01 0x03 0x02 0x06 0x01 0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 0x40

#define BUFSIZE

uint32_t UARTInit( uint32_t portNum, uint32_t Baudrate ); void UART0_IRQHandler( void ); void UART1_IRQHandler( void ); void UARTSend( uint32_t portNum, uint8_t *BufferPtr, uint32_t Length ); #endif /* end __UART_H */

天下的人(红豆电子)与贞明电子协同打造

50

电子让生活更美好

UART.C 文件: UART.C 文件:
#include "lpc17xx.h" #include "uart.h" #define UART0 LPC_UART0 #define UART1 LPC_UART1 #define PINCON LPC_PINCON volatile volatile volatile volatile uint32_t UART0Status, UART1Status; uint8_t UART0TxEmpty = 1, UART1TxEmpty = 1; uint8_t UART0Buffer[BUFSIZE], UART1Buffer[BUFSIZE]; uint32_t UART0Count = 0, UART1Count = 0;

/******************************************************************* * Function name: UART0Handler ** Descriptions: UART0 interrupt handler ** parameters: None ** Returned value: None ******************************************************************** / void UART0_IRQHandler (void) { uint8_t IIRValue, LSRValue; uint8_t Dummy = Dummy; IIRValue = UART0->IIR; IIRValue >>= 1; /* skip pending bit in IIR */ IIRValue &= 0x07; /* check bit 1~3, interrupt identification */ if ( IIRValue == IIR_RLS ) /* Receive Line Status */ { LSRValue = UART0->LSR; /* Receive Line Status */ if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) { /* There are errors or break interrupt */ /* Read LSR will clear the interrupt */ UART0Status = LSRValue; Dummy = UART0->RBR; /* Dummy read on RX to clear interrupt, then bail out */ return;
天下的人(红豆电子)与贞明电子协同打造 51

电子让生活更美好

} if ( LSRValue & LSR_RDR ) /* Receive Data Ready */ { /* If no error on RLS, normal ready, save into the data buffer. */ /* Note: read RBR will clear the interrupt */ UART0Buffer[UART0Count] = UART0->RBR; UART0Count++; if ( UART0Count == BUFSIZE ) { UART0Count = 0; /* buffer overflow */ } } } else if ( IIRValue == IIR_RDA ) /* Receive Data Available */ { /* Receive Data Available */ UART0Buffer[UART0Count] = UART0->RBR; UART0Count++; if ( UART0Count == BUFSIZE ) { UART0Count = 0; /* buffer overflow */ } } else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */ { /* Character Time-out indicator */ UART0Status |= 0x100; /* Bit 9 as the CTI error */ } else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */ { /* THRE interrupt */ LSRValue = UART0->LSR; /* Check status in the LSR to see if valid data in U0THR or not */ if ( LSRValue & LSR_THRE ) { UART0TxEmpty = 1; } else { UART0TxEmpty = 0; } }

天下的人(红豆电子)与贞明电子协同打造

52

电子让生活更美好

} /******************************************************************* * ** Function name: UART1Handler ** Descriptions: UART1 interrupt handler ** parameters: None ** Returned value: None ******************************************************************/ void UART1_IRQHandler (void) { uint8_t IIRValue, LSRValue; uint8_t Dummy = Dummy; IIRValue = UART1->IIR; IIRValue >>= 1; /* skip pending bit in IIR */ IIRValue &= 0x07; /* check bit 1~3, interrupt identification */ if ( IIRValue == IIR_RLS ) /* Receive Line Status */ { LSRValue = UART1->LSR; /* Receive Line Status */ if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) { /* There are errors or break interrupt */ /* Read LSR will clear the interrupt */ UART1Status = LSRValue; Dummy = UART1->RBR; /* Dummy read on RX to clear interrupt, then bail out */ return; } if ( LSRValue & LSR_RDR ) /* Receive Data Ready */ { /* If no error on RLS, normal ready, save into the data buffer. */ /* Note: read RBR will clear the interrupt */ UART1Buffer[UART1Count] = UART1->RBR; UART1Count++; if ( UART1Count == BUFSIZE ) { UART1Count = 0; /* buffer overflow */ } } } else if ( IIRValue == IIR_RDA ) /* Receive Data Available */ {
天下的人(红豆电子)与贞明电子协同打造 53

电子让生活更美好

/* Receive Data Available */ UART1Buffer[UART1Count] = UART1->RBR; UART1Count++; if ( UART1Count == BUFSIZE ) { UART1Count = 0; /* buffer overflow */ } } else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */ { /* Character Time-out indicator */ UART1Status |= 0x100; /* Bit 9 as the CTI error */ } else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */ { /* THRE interrupt */ LSRValue = UART1->LSR; /* Check status in the LSR to see if valid data in U0THR or not */ if ( LSRValue & LSR_THRE ) { UART1TxEmpty = 1; } else { UART1TxEmpty = 0; } } } /******************************************************************* * ** Function name: UARTInit ** Descriptions: Initialize UART0 port, setup pin select, ** clock, parity, stop bits, FIFO, etc. ** parameters: portNum(0 or 1) and UART baudrate ** Returned value: true or false, return false only if the ** interrupt handler can't be installed to the ** VIC table ******************************************************************** / uint32_t UARTInit( uint32_t PortNum, uint32_t baudrate ) { uint32_t Fdiv;

天下的人(红豆电子)与贞明电子协同打造

54

电子让生活更美好

if ( PortNum == 0 ) { PINCON->PINSEL0 = 0x00000050; /* RxD0 is P0.3 and TxD0 is P0.2 */ UART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ /* By default, the PCLKSELx value is zero, thus, the PCLK for all the peripherals is 1/4 of the SystemFrequency. */ // Fdiv = ( SystemFrequency/4/16 ) / baudrate ; /*baud rate, Fpclk: 18MHz */ Fdiv = ( SystemCoreClock/4/16 ) / baudrate ; UART0->DLM = Fdiv / 256; UART0->DLL = Fdiv % 256; UART0->LCR = 0x03; /* DLAB = 0 */ UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */ NVIC_EnableIRQ(UART0_IRQn); UART0->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART0 interrupt */ return (TRUE); } else if ( PortNum == 1 ) { PINCON->PINSEL4 |= 0x0000000A; /* Enable RxD1 P2.1, TxD1 P2.0 */ UART1->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ /* By default, the PCLKSELx value is zero, thus, the PCLK for all the peripherals is 1/4 of the SystemFrequency. */ // Fdiv = ( SystemFrequency/4/16 ) / baudrate ; /*baud rate */ Fdiv = ( SystemCoreClock/4/16 ) / baudrate ; UART1->DLM = Fdiv / 256; UART1->DLL = Fdiv % 256; UART1->LCR = 0x03; /* DLAB = 0 */ UART1->FCR = 0x07; /* Enable and reset TX and RX FIFO. */ NVIC_EnableIRQ(UART1_IRQn); UART1->IER = IER_RBR | IER_THRE | IER_RLS; /* interrupt */ return (TRUE); } return( FALSE ); } Enable UART1

/******************************************************************* * ** Function name: UARTSend
天下的人(红豆电子)与贞明电子协同打造 55

电子让生活更美好

** ** Descriptions: Send a block of data to the UART 0 port based ** on the data length ** ** parameters: portNum, buffer pointer, and data length ** Returned value: None *************************************************************/ void UARTSend( uint32_t portNum, uint8_t *BufferPtr, uint32_t Length ) { if ( portNum == 0 ) { while ( Length != 0 ) { /* THRE status, contain valid data */ while ( !(UART0TxEmpty & 0x01) ); UART0->THR = *BufferPtr; UART0TxEmpty = 0; /* not empty in the THR until it shifts out */ BufferPtr++; Length--; } } else { while ( Length != 0 ) { /* THRE status, contain valid data */ while ( !(UART1TxEmpty & 0x01) ); UART1->THR = *BufferPtr; UART1TxEmpty = 0; /* not empty in the THR until it shifts out */ BufferPtr++; Length--; } } return; } /******************************************************************* * ** End Of File ******************************************************************/

下面是我们的主函数:
#include "lpc17xx.h" #include "uart.h" // 包含头文件, 头文件内保护系统初始化头文件 //包含串口所使用的头文件
天下的人(红豆电子)与贞明电子协同打造 56

电子让生活更美好

//***************************************************** uint32_t msTicks,sign=0; //变量定义 extern volatile uint32_t UART0Count; //串口接收数据计数 extern volatile uint8_t UART0Buffer[BUFSIZE]; //串口数据接受缓存 //extern volatile uint32_t UART1Count; //extern volatile uint8_t UART1Buffer[BUFSIZE]; unsigned char table[]={"LED 1 LIGHT!\n"}; //***************************************************** void SysTick_Handler(void) //系统节拍定时器中断函数 { msTicks++; //简单的定时++ 运算 if(msTicks==500) //定时满 500 次 一次 1ms 即 500ms 置位标志位 { sign=1; //标志位置位 msTicks=0; //定时变量 清零 } } int main(void) { uint32_t i=0; //定义变量 SystemInit(); //系统初始化函数 if (SysTick_Config(SystemCoreClock / 1000)) //系统节拍定时器初始化 函数在 core_cm3.h 里 { //设置节拍定时器 1ms 中断 注意系统节拍定时器只有 24 位 while (1); //不能越界 若越界则会出现此处的 whil(1)错误 } UARTInit(0,9600); //UART 初始化,第一个参数是端口,第二个参数是波特率 LPC_SC->PCONP|=(1<<15); LPC_GPIO2->FIODIR=0x0000000F; //FIODIR 设置端口的输入输出 LPC_GPIO2->FIOSET=0x0000000F; while(1) { if(sign==1) //如果标志位置位 表示定时时间到 { sign=0; //标志位清零 LPC_GPIO2->FIOPIN =~( 1 << i); i++; //移位++ if(i==4) //4 位 满了 清零 i=0; table[4]=i+0x30;
天下的人(红豆电子)与贞明电子协同打造 57

电子让生活更美好

UARTSend(0,table,15); //串口输出 } if ( UART0Count != 0 ) //判断是否有数据接受到 { LPC_UART0->IER = IER_THRE | IER_RLS; /* Disable RBR */ UARTSend( 0, (uint8_t *)UART0Buffer, UART0Count ); //将接收的数据返回去 UART0Count = 0; LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */ } } }

该程序的现象是 LED 灯像实验 2 那样流动闪烁, 每移动一次就从 LED 串口向上发送一个字符串,告诉上位机此时是哪一个 LED 在亮。另外 这个程序也可接收数据, 并且将接收到的数据, 按原样返回到 PC 机端。 下面是 PC 机上串口调试工具在运行时的截图:

天下的人(红豆电子)与贞明电子协同打造

58

电子让生活更美好

5.4 实验 4—按键实验 按键是常用的输入设备,在实际应用中得到广泛应用!其中用的比 较多的是独立按键和矩阵键盘,独立按键适合按键数量较少,矩阵键 盘时候按键较多的情况。独立按键的读取是比较容易的。由原理图可 知,我们的按键外部有上拉电阻,在没有按键按下的时候,读取端口 是高电平,在有按键按下的时候,按键所在端口是低电平。这样我们 的 IO 口就可以读出是否有按键按下了。然而按键是机械装置,在按下 和弹起时都有抖动。一般的防抖方法有硬件防抖和软件防抖,硬件防 抖是在按键输入 IO 口中加入施密特触发器,会引入硬件成本。而为了 节约成本一般采用软件防抖,软件防抖的一般方法是 2 次读取中间加 一个 ms 级延时,若 2 次读取都是低电平,则说明有键按下。在按键的 操作过程中我们一般还要求按键按下依次只读出一个按下状态,一般 的做法是:在按下键盘后就在程序中使用一个 while 循环等待按键的 松开,在低速 8 位单片机上这样做没什么不好,但是如果在 32 位 ARM 上这样做将是浪费了宝贵的时间片资源。本程序采用一种状态存储的 方法将上一次按键的状态存储,若这次检测到按键按下上一次也检测 到按键按下,那么我们认为按键没有被松开!不作处理。若这次按下 时读上一次保存的状态是没有被按下,那么这是一个新的按键信息, 应当被处理! 下面是按键实验的主函数:
#include "lpc17xx.h" // 包含头文件, 头文件内保护系统初始化头文件 #include "uart.h" //包含串口所使用的头文件 //***************************************************** uint32_t msTicks,sign=0; //变量定义
天下的人(红豆电子)与贞明电子协同打造 59

电子让生活更美好

extern volatile uint32_t UART0Count; //串口接收数据计数 extern volatile uint8_t UART0Buffer[BUFSIZE]; //串口数据接受缓存 //extern volatile uint32_t UART1Count; //extern volatile uint8_t UART1Buffer[BUFSIZE]; unsigned char table[]={"key 0 down!\n"}; uint32_t key_old=0,LED=0x0000000f; //key_Old 保存按键上一次按下的 值 LED LED 灯的状态 //***************************************************** /****************** 函数声明区 *************************/ void key(void); /******** main **********************************/ int main(void) { SystemInit(); //系统初始化函数 UARTInit(0,9600); //UART 初始化,第一个参数是端口,第二个参数是波特率 LPC_SC->PCONP|=(1<<15); //功耗控制,此处可以注释掉,因为复位后 GPIO 默认开启 LPC_GPIO2->FIODIR=0x0000000f; //只将 P2 口的低 4 位设置成输出模式 LPC_GPIO2->FIOSET=0x0000000F; //GPIO 置位,当某位为 1 则置位,为 0 不变 UARTSend(0,table,15); while(1) { key(); if ( UART0Count != 0 ) //判断是否有数据接受到 { LPC_UART0->IER = IER_THRE | IER_RLS; /* Disable RBR */ UARTSend( 0, (uint8_t *)UART0Buffer, UART0Count ); //将接受的数据返回去 UART0Count = 0; LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */ } } } /************************************************************/ void key(void) { uint32_t key=0,i=0; key=LPC_GPIO2->FIOPIN; //读是否有按键按下 key=key&0x00001c00; //只观测三个按键的值,屏蔽其他位 if(key!=0x00001c00) //如果有按键按下
天下的人(红豆电子)与贞明电子协同打造 60

电子让生活更美好

{ for(i=0;i<5000;i++); //延时一小段时间 防止按键抖动 key=LPC_GPIO2->FIOPIN; //再次读取端口状态 key=key&0x00001c00; //屏蔽其他位 if(key!=0x00001c00) //是否有按键按下 { switch(key) //判断是那一个按键 { case 0x00001800: //第一个按键(P2.10)按下 if(1!=(key_old&1)) //查看上一次这个按键是否按下 如果上次也 是按下的 { //说明按键没有松开 不做处理 否则键按下 if((LED&1)==1) //LED 灯取反 LED&=~1; else LED|=1; key_old|=1; //将这一次按键的状态存储起来 table[4]=1+0x30; //修改字符串 UARTSend(0,table,15); //串口发送 } break; case 0x00001400: //第二个按键(P2.11)按下 if(2!=(key_old&2)) { if((LED&2)==2) LED&=~2; else LED|=2; key_old|=2; table[4]=2+0x30; UARTSend(0,table,15); } break; case 0x00000c00: // 第三个按键(P2.12)按下 if(4!=(key_old&4)) { if((LED&4)==4) LED&=~4; else LED|=4; key_old|=4; table[4]=3+0x30; UARTSend(0,table,15); }
天下的人(红豆电子)与贞明电子协同打造 61

电子让生活更美好

break; } LPC_GPIO2->FIOPIN=LED; } } else { key_old=0; 下” ! } } /***********************************************************/ //没有键按下 更新上次按键“均没有被按 //更新 LED 状态

5.5 实验 5—定时器实验 定时器/计数器是 MCU 内部的重要资源,一个强大的定时器/计数器 能够完成众多功能,给我们的应用带来极大的便利。在 LPC17XX 内部 含有 4 个 32 位通用定时器/计数器。4 个定时器/计数器,除了外设基 址之外完全相同。 个定时器最少有 2 个捕获输入和 2 个匹配输出, 4 并 且有多个引脚可以选择。定时器 2 引出了全部 4 个匹配输出。 32 位的定时器/计数器,带有一个可编程的 32 位预分频器。 计数器或定时器操作。 每个定时器包含 2 个 32 位的捕获通道, 当输入信号变化时捕捉定时 器的瞬时值。也可以选择产生中断。 4 个 32 位匹配寄存器,允许执行以下操作: 匹配时连续工作,在匹配时可选择产生中断; 在匹配时停止定时器运行,可选择产生中断; 在匹配时复位定时器,可选择产生中断; 有 4 个与匹配寄存器相对应的外部输出,这些输出具有以下功能: 匹配时设定为低电平;
天下的人(红豆电子)与贞明电子协同打造 62

电子让生活更美好

匹配时设为高电平; 匹配时翻转电平; 匹配时不执行任何操作; 这是 LPC17XX 定时器的基本特征,下面具体介绍一些定时器的寄存器 和使用方法。要使用定时器这个片内外设,依然需要如下外围配置:功 率(PCONP) 、外设时钟(PCLK_SEL0) 、引脚(PINSEL) 、中断、DMA(如 果使用的话) 。定时器/计数器寄存器列表:

天下的人(红豆电子)与贞明电子协同打造

63

电子让生活更美好

下面主要介绍一下以上那些寄存器: IR 是中断寄存器,如何进入中断,和启动中断,我们的系统文件都 为我们做好了,比如要使能某个中断在初始化函数里只需要加上这样 一个函数:NVIC_EnableIRQ(TIMER0_IRQn);从函数名就可以看出是使 能中断的意思,这个函数在 core_cm3.h 中定义,这里面还有其他一些 关于中断的函数如禁止某个中断等,查阅一些就能看到。这里使能的 显然是 TINMER0,表示符“TIMER0_IRQn”是在 LPC17xx.h 中定义的, 这里有所有中断的表示方法。如果要使能其他中断只需要将函数括号 中的中断名修改成别的中断名即可(中断名在 LPC17XX.h 中查阅) 。说
天下的人(红豆电子)与贞明电子协同打造 64

电子让生活更美好

完了使能中断,下面是中断函数的形式:void TIMER0_IRQHandler (void),这是定时器 0 的中断服务函数的文件名,如果要写其他中断 的中断服务函数, 只需将 TIMER0_IRQ 修改成其他中断对应的名称即可。 对于定时器进入中断函数后需要想 IR 的对应位写入 1 来复位中断。 TCR 定时器控制寄存器,只有前 2 位有效,其余位保留,位 0 是计数 器使能,为 1 时使能,为 0 时禁止。位 1 是计数器复位,为 1 是发生 复位。 CTCR 计数器控制寄存器,有效的只有前 4 位,而在定时应用中只需 要将位 0 和位 1 设置成 00 即可。因为前 2 位是定时器模式选择,00 表示选择定时模式,其余都是计数模式。位 2,3 是计数输入选择。 MCR 匹配控制寄存器,一共 12 位有效,对 4 个匹配寄存器控制,每 一个匹配通道有 3 位控制,位 0 是 MR0 匹配时是否引发中断,位 1 是 MR0 匹配是是否引发 TC 复位,位 2 是 MR0 匹配时是否引发停止。以后 的位和这几位类似。引发停止时候单次定时使用,如果要重复定时, 且需要中断来处理事物那么只需要相应的位置 1 即可。 EMR 是外部匹配寄存器, EMR 的前 4 位里写入 1 可以在对应的管脚 在 发生置位操作。对 EMR 后面寄存器的选择操作可以使匹配输出管脚在 匹配时产生相应的动作。通过前 4 位的操作和匹配操作可以实现比较 匹配管脚产生 PWM。 PR 预分频寄存器,设置预分频数。 在 25M 时钟下,即 100M/4(时钟默认)下不预分频 32 位定时器可以 一次性定时 171 秒时长,若使用预分频将会范围更广。这就是 32 位定
天下的人(红豆电子)与贞明电子协同打造 65

电子让生活更美好

时器带来的好处。 本次定时器实验实现了类似广告牌式的灯光闪烁, 个相同时间的闪 3 烁后是一个较长时间闪烁,一个较长时间闪烁后又是 5 个相同时间的 闪烁,然后是一个长时间闪烁,然后回到 3 个相等时间闪烁。采用 4 个 LED 同时闪烁实现。这部分处理代码写在了定时器的中断函数里。 这里我们采用定时器 0, 主函数里有定时器的初始化和使能。 定时器代 码如下:
timer.h timer.h #ifndef __TIMER_H #define __TIMER_H #define TIME_INTERVAL (9000000/100 - 1) extern void delayMs(uint8_t timer_num, uint32_t delayInMs); extern uint32_t init_timer( uint8_t timer_num, uint32_t timerInterval ); extern void enable_timer( uint8_t timer_num ); extern void disable_timer( uint8_t timer_num ); extern void reset_timer( uint8_t timer_num ); extern void TIMER0_IRQHandler (void); extern void TIMER1_IRQHandler (void); #endif /* end __TIMER_H */ /*************************************************** ** End Of File *****************************************************/ timer.c timer.c #include "lpc17xx.h" #include "timer.h" volatile uint32_t timer0_counter = 0; volatile uint32_t timer1_counter = 0; uint32_t num=0; uint32_t tab[]={100,100,100,400,300,300,300,300,300,600}; //10 用于存储每一次定时的时长,单位 ms /******************************************************************* ** Function name: delayMs **
天下的人(红豆电子)与贞明电子协同打造 66

电子让生活更美好

** Descriptions: ** ** ** parameters:

Start the timer delay in milo seconds until elapsed timer number, Delay value in milo second

** ** Returned value: None ******************************************************************** *********/ void delayMs(uint8_t timer_num, uint32_t delayInMs) { if ( timer_num == 0 ) { LPC_TIM0->TCR = 0x02; /* reset timer */ LPC_TIM0->PR = 0x00; /* set prescaler to zero */ LPC_TIM0->MR0 = delayInMs * (9000000 / 1000-1); LPC_TIM0->IR = 0xff; /* reset all interrrupts */ LPC_TIM0->MCR = 0x04; /* stop timer on match */ LPC_TIM0->TCR = 0x01; /* start timer */ /* wait until delay time has elapsed */ while (LPC_TIM0->TCR & 0x01); } else if ( timer_num == 1 ) { LPC_TIM1->TCR = 0x02; /* reset timer */ LPC_TIM1->PR = 0x00; /* set prescaler to zero */ LPC_TIM1->MR0 = delayInMs * (9000000 / 1000-1); LPC_TIM1->IR = 0xff; /* reset all interrrupts */ LPC_TIM1->MCR = 0x04; /* stop timer on match */ LPC_TIM1->TCR = 0x01; /* start timer */ /* wait until delay time has elapsed */ while (LPC_TIM1->TCR & 0x01); } return; } /******************************************************************* *********** ** Function name: Timer0_IRQHandler ** ** Descriptions: Timer/Counter 0 interrupt handler ** ** parameters: None
天下的人(红豆电子)与贞明电子协同打造 67

电子让生活更美好

** Returned value: None ** ******************************************************************** **********/ void TIMER0_IRQHandler (void) //定时器 0 中断服务函数 { LPC_TIM0->IR = 1; /* clear interrupt flag */ timer0_counter++; //中断次数计数 if((timer0_counter%2)==1) //中断 2 次后填入新的值 { LPC_TIM0->MR0=25000*tab[num]; //定时数据写入 num++; //移动定时时长指向变量 if(num==10) //判断是否到达末尾,如果到达则回到开始 num=0; } LPC_GPIO2->FIOPIN=~LPC_GPIO2->FIOPIN; //更新 IO 状态 if(timer0_counter==5000) //限定中断计数变量 timer0_counter=0; return; }

/******************************************************************* *********** ** Function name: Timer1_IRQHandler ** ** Descriptions: Timer/Counter 1 interrupt handler ** ** parameters: None ** Returned value: None ** ******************************************************************** **********/ void TIMER1_IRQHandler (void) //定时器 1 中断 { LPC_TIM1->IR = 1; /* clear interrupt flag */ timer1_counter++; return; }

/******************************************************************* ***********
天下的人(红豆电子)与贞明电子协同打造 68

电子让生活更美好

** Function name: enable_timer ** ** Descriptions: Enable timer ** ** parameters: timer number: 0 or 1 ** Returned value: None ** ******************************************************************** **********/ void enable_timer( uint8_t timer_num )//启动定时器 操作 TCR 第一位 { if ( timer_num == 0 ) { LPC_TIM0->TCR = 1; } else { LPC_TIM1->TCR = 1; } return; } /******************************************************************* *********** ** Function name: disable_timer ** ** Descriptions: Disable timer ** ** parameters: timer number: 0 or 1 ** Returned value: None ** ******************************************************************** **********/ void disable_timer( uint8_t timer_num )//失能定时器 操作 TCR 的第一位 { if ( timer_num == 0 ) { LPC_TIM0->TCR = 0; } else { LPC_TIM1->TCR = 0; } return;
天下的人(红豆电子)与贞明电子协同打造 69

电子让生活更美好

} /******************************************************************* *********** ** Function name: reset_timer ** ** Descriptions: Reset timer ** ** parameters: timer number: 0 or 1 ** Returned value: None ** ******************************************************************** **********/ void reset_timer( uint8_t timer_num ) //复位定时器操作 TCR 的第 1 位 { uint32_t regVal; if ( timer_num == 0 ) { regVal = LPC_TIM0->TCR; regVal |= 0x02; LPC_TIM0->TCR = regVal; } else { regVal = LPC_TIM1->TCR; regVal |= 0x02; LPC_TIM1->TCR = regVal; } return; } //****************************************************************** uint32_t init_timer ( uint8_t timer_num, uint32_t TimerInterval ) { //初始化定时器,第一个参数表示初始化那一个定时器,第二个是定时时长 if ( timer_num == 0 ) { timer0_counter = 0; LPC_TIM0->MR0 = TimerInterval; //匹配寄存器 LPC_TIM0->MCR = 3; //在 MR0 匹配是中断并且复位 //没有配置 CTCR 因为复位后就是 0,没有设置预分频 NVIC_EnableIRQ(TIMER0_IRQn); //使能中断 return (1); //初始化成功返回 1 } else if ( timer_num == 1 )
天下的人(红豆电子)与贞明电子协同打造 70

电子让生活更美好

{ timer1_counter = 0; LPC_TIM1->MR0 = TimerInterval; LPC_TIM1->MCR = 3; /* Interrupt and Reset on MR1 */ NVIC_EnableIRQ(TIMER1_IRQn); return (1); } return (0); } /************************************************************* End Of File ************************************************************/

主函数:
#include "lpc17xx.h" #include "timer.h" /******************* int main(void) { SystemInit(); main // 包含头文件, 头文件内保护系统初始化头文件

******************************/

//系统初始化函数

LPC_SC->PCONP|=(1<<15); //功耗控制,此处可以注释掉,因为复位后 GPIO 默认开启 LPC_GPIO2->FIODIR=0x0000000f; //只将 P2 口的低 4 位设置成输出模式 LPC_GPIO2->FIOSET=0x0000000F; //GPIO 置位,当某位为 1 则置位,为 0 不变 LPC_GPIO2->FIOPIN=0x0000000f; init_timer( 0, TIME_INTERVAL ); // 初始化定时器 并且定时 10ms enable_timer( 0 ); //使能定时器 0 while(1) { } }

5.6 实验 6—外部中断 LPC1768 提供了 4 个外部管脚中断, 4 个中断分别位于 P2.10-P2.13 这 上,本次实验的现象是按下三个按键(分别对应外部中断 0-中断 2) ,
天下的人(红豆电子)与贞明电子协同打造 71

电子让生活更美好

对应的 LED 灯就会量。外部中断涉及寄存器有 EXTINT、EXTMODE、 EXTPOLAR; EXTINT:当一个引脚选择使用外部中断功能时,该引脚上电平或边 沿将会置位 EXTINT 寄存器的中断标志位。这会向 NVIC 提交相应的中 断请求,如果引脚中断使能,则产生中断。向 EXTINT 寄存器的位 EINT0-EINT3 写入 1 来将其清零。 在电平触发模式下, 中断只有在引脚 出于无效状态时才能被清零。

EXTMODE:

天下的人(红豆电子)与贞明电子协同打造

72

电子让生活更美好

EXTPOLAR:

EXTMODE、 EXTPOLAR 这两个寄存器一个管理选择电平触发还是边沿触 发,一个选择上升沿和下降沿或者高低电平触发。 在外部中断配置中我们还需要在 PINSEL4 中将相应的管脚配置成外 部中断模式。 主程序如下:
#include "lpc17xx.h" void EINT0_IRQHandler () //外部中断 0 中断函数 { LPC_SC->EXTINT|=1; //清零标志位 LPC_GPIO2->FIOPIN=0x000000fe; //LED 显示 } void EINT1_IRQHandler () { LPC_SC->EXTINT|=2; LPC_GPIO2->FIOPIN=0x000000fd; } void EINT2_IRQHandler () { LPC_SC->EXTINT|=4; LPC_GPIO2->FIOPIN=0x000000fb; }
天下的人(红豆电子)与贞明电子协同打造 73

电子让生活更美好

void ext_init(void) //外部中断初始化 { LPC_PINCON->PINSEL4=0x01500000; //配置管脚,选择外部中断功能 LPC_SC->EXTMODE=0x07; //配置成脉冲触发 LPC_SC->EXTPOLAR=0x00; //配置成下降沿触发 NVIC_EnableIRQ(EINT0_IRQn); //使能外部中断 0 NVIC_EnableIRQ(EINT1_IRQn); NVIC_EnableIRQ(EINT2_IRQn); LPC_SC->EXTINT=7; //所有使用的外部中断标准位清零 } int main(void) { SystemInit(); //系统初始化 ext_init(); //中断初始化 LPC_GPIO2->FIODIR=0x000000ff; //端口方向配置 LPC_GPIO2->FIOPIN=0x000000ff; //端口电平配置 while(1); }

5.7 实验 7—通用 PWM 实验 本实验实现通过 PWM 对 LED 进行调光,可以看到的现象是 3 个 LED 有不同的亮度,还有一个 LED 的亮度从低到高不断的变化。 下面就叙述一下通用 PWM 的内部结构,LPC1768 的内置通用 PWM,可 以实现 6 路 PWM 输出。结构类似定时器,有 7 个匹配寄存器,和一个 计数器一个预分频器, 通过预分频和计数器对时钟进行计数, 个匹配 7 寄存器中匹配寄存器 0 没有对外输出管脚,实现对周期的控制,可以 选择在匹配寄存器 0 匹配时实现计数器复位、产生中断、其他匹配寄 存器输出置位(清零)等操作。6 个匹配输出 PWM 寄存器还有 6 个捕获 寄存器。 在这里我们实验使用匹配寄存器 0 控制周期, 匹配寄存器 1-4
天下的人(红豆电子)与贞明电子协同打造 74

电子让生活更美好

实现匹配输出 PWM 的功能,当匹配寄存器 0 匹配时匹配寄存器 1-4 输 出置位,当匹配寄存器 1-4 中任意一个匹配时则对应的输出清零。通 过调整匹配寄存器 0 的值可以调整产生 PWM 的周期,通过调整匹配寄 存器 1-4 的值可以调整占空比,注意,一般匹配寄存器 1-6 的调整范 围是 0 到匹配寄存器 0 的值。关于具体的寄存器描述在手册的脉宽调 制(PWM)章节中有详细描述。下面看看关于 PWM 的程序文件: PWM.h
#ifndef __PWM_H #define __PWM_H #define PWM_CYCLE #define PWM_OFFSET #define #define #define #define #define #define #define MR0_INT MR1_INT MR2_INT MR3_INT MR4_INT MR5_INT MR6_INT 1200 200 1 1 1 1 1 1 1 << << << << << << << 0 1 2 3 8 9 10

#define TCR_CNT_EN #define TCR_RESET #define TCR_PWM_EN #define #define #define #define #define #define #define #define #define #define #define #define PWMMR0I PWMMR0R PWMMR0S PWMMR1I PWMMR1R PWMMR1S PWMMR2I PWMMR2R PWMMR2S PWMMR3I PWMMR3R PWMMR3S

0x00000001 0x00000002 0x00000008 1 1 1 1 1 1 1 1 1 1 1 1 << << << << << << << << << << << << 0 1 2 3 4 5 6 7 8 9 10 11
75

天下的人(红豆电子)与贞明电子协同打造

电子让生活更美好

#define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define

PWMMR4I PWMMR4R PWMMR4S PWMMR5I PWMMR5R PWMMR5S PWMMR6I PWMMR6R PWMMR6S PWMSEL2 PWMSEL3 PWMSEL4 PWMSEL5 PWMSEL6 PWMENA1 PWMENA2 PWMENA3 PWMENA4 PWMENA5 PWMENA6 LER0_EN LER1_EN LER2_EN LER3_EN LER4_EN LER5_EN LER6_EN

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

<< << << << << << << << << << << << << << << << << << << << << << << << << << <<

12 13 14 15 16 17 18 19 20 2 3 4 5 6 9 10 11 12 13 14 0 1 2 3 4 5 6

extern uint32_t PWM_Init( uint32_t channelNum, uint32_t cycle ); extern void PWM_Set( uint32_t channelNum, uint32_t cycle, uint32_t offset ); extern void PWM_Start( uint32_t channelNum ); extern void PWM_Stop( uint32_t channelNum ); #endif /* end __PWM_H */ PWM.c: #include "lpc17xx.h" #include "pwm.h" volatile uint32_t match_counter0, match_counter1;

天下的人(红豆电子)与贞明电子协同打造

76

电子让生活更美好

/******************************************************************* ** Function name: PWM1_IRQHandler ** ** Descriptions: PWM1 interrupt handler ** For now, it only deals with PWM1 match 0 ** ** parameters: None ** Returned value: None ** *******************************************************************/ void PWM1_IRQHandler (void) { uint32_t regVal; regVal = LPC_PWM1->IR; if ( regVal & MR0_INT ) { match_counter1++; } LPC_PWM1->IR |= regVal; return; } /******************************************************************* ** Function name: PWM_Init ** ** Descriptions: PWM initialization, setup all GPIOs to PWM0~6, ** reset counter, all latches are enabled, interrupt ** on PWMMR0, install PWM interrupt to the VIC table. ** ** parameters: ChannelNum, Duty cycle ** Returned value: true or fase, if VIC table is full, return false ** *******************************************************************/ uint32_t PWM_Init( uint32_t ChannelNum, uint32_t cycle ) { if ( ChannelNum == 1 ) { LPC_SC->PCONP|=(1<<6); match_counter1 = 0; LPC_PINCON->PINSEL4 = 0x00001555; PWM0 */

/* clear interrupt flag on match 0 */

/* set GPIOs for all PWM pins on

天下的人(红豆电子)与贞明电子协同打造

77

电子让生活更美好

LPC_PWM1->TCR = TCR_RESET; /* Counter Reset */ LPC_PWM1->PR = 0x00; /* count frequency:Fpclk */ LPC_PWM1->MCR = PWMMR0I; /* interrupt on PWMMR0, reset on PWMMR0, reset TC if PWM0 matches */ LPC_PWM1->MR0 = cycle; /* set PWM cycle */ LPC_PWM1->MR1 = cycle * 4/5; LPC_PWM1->MR2 = cycle * 19/20; LPC_PWM1->MR3 = cycle * 39/40; LPC_PWM1->MR4 = cycle ; LPC_PWM1->MR5 = cycle * 1/20; LPC_PWM1->MR6 = 0; /* all PWM latch enabled */ LPC_PWM1->LER = LER0_EN | LER1_EN | LER2_EN | LER3_EN | LER4_EN | LER5_EN | LER6_EN; } else { return ( 0 ); /* Unknown channel number */ } NVIC_EnableIRQ(PWM1_IRQn); return (1); } /******************************************************************* ** Function name: PWM_Set ** ** Descriptions: PWM cycle setup ** ** parameters: Channel number, PWM cycle, and offset ** Returned value: None ** *******************************************************************/ void PWM_Set( uint32_t ChannelNum, uint32_t cycle, uint32_t offset ) { if ( ChannelNum == 1 ) { LPC_PWM1->MR0 = cycle; /* set PWM cycle */ LPC_PWM1->MR1 = cycle * 5/6 + offset; LPC_PWM1->MR2 = cycle * 2/3 + offset; LPC_PWM1->MR3 = cycle * 1/2 + offset; LPC_PWM1->MR4 = cycle * 1/3 + offset; LPC_PWM1->MR5 = cycle * 1/6 + offset;
天下的人(红豆电子)与贞明电子协同打造 78

电子让生活更美好

LPC_PWM1->MR6 = offset; /* The LER will be cleared when the Match 0 takes place, in order to load and execute the new value of match registers, all the PWMLERs need to reloaded. all PWM latch enabled */ LPC_PWM1->LER = LER0_EN | LER1_EN | LER2_EN | LER3_EN | LER4_EN | LER5_EN | LER6_EN; } return; } /******************************************************************* ** Function name: PWM_Start ** ** Descriptions: Enable PWM by setting the PCR, PTCR registers ** ** parameters: channel number ** Returned value: None ** ****************************************************************/ void PWM_Start( uint32_t channelNum ) { if ( channelNum == 1 ) { /* All single edge, all enable */ LPC_PWM1->PCR = PWMENA1 | PWMENA2 | PWMENA3 | PWMENA4 | PWMENA5 | PWMENA6; LPC_PWM1->TCR = TCR_CNT_EN | TCR_PWM_EN; /* counter enable, PWM enable */ } return; } /******************************************************************* ** Function name: PWM_Stop ** ** Descriptions: Stop all PWM channels ** ** parameters: channel number ** Returned value: None ** ******************************************************************/ void PWM_Stop( uint32_t channelNum )
天下的人(红豆电子)与贞明电子协同打造 79

电子让生活更美好

{ if ( channelNum == 1 ) { LPC_PWM1->PCR = 0; LPC_PWM1->TCR = 0x00; } return;

/* Stop all PWMs */

} 主函数: 主函数 #include "lpc17xx.h" #include "pwm.h" #include "uart.h" /*****************************************************/ extern volatile uint32_t match_counter1; //PWM 周期匹配中断 extern volatile uint32_t UART0Count; //UART0 接受计数 extern volatile uint8_t UART0Buffer[BUFSIZE]; //UART0 接受缓冲 unsigned char table[]={"UART TEST OK !!!"}; //UART 测试显示数组 /******************************************************/ int main(void) { uint32_t i,j=10000; SystemInit(); //系统初始化 UARTInit(0, 9600); //UART0 初始化 UARTSend( 0,table,17 ); //UART0 输出测试 if(PWM_Init(1,10000)==1) //初始化并判断是否初始化正确 UARTSend(0,"PWM_INIT_OK",12); PWM_Start(1); //启动 PWM while(1) { LPC_PWM1->MR4=j; LPC_PWM1->LER = LER0_EN | LER1_EN | LER2_EN | LER3_EN | LER4_EN | LER5_EN | LER6_EN; //加载刚刚更新的匹配寄存器值 使之有效 j=j-100; if(j==0) j=10000; for(i=0;i<500000;i++); } }
天下的人(红豆电子)与贞明电子协同打造 80


相关文章:
NXP Keil LPC1768 ARM Cortex-M3 MCU开发方案
NXP Keil LPC1768 ARM Cortex-M3 MCU开发方案_电子/电路_工程科技_专业资料。恩智浦 Keil LPC1768 ARM Cortex-M3 MCU开发方案NXP...
lpc1768
NXPLPC1768 便是基于 Cortex-M3 的处理器。 如同现在市场上多数控制器,LPC1768 只内建了 1 个带 8 通道的 12 位的模/数转换(少数芯片如 TMS320F2812...
NXP LPC ARM 必须知道的知识
NXP Cortex-M3 LPC1768基础... 63页 5财富值 LPC...解释:当 UART 中断产生时,Core latches the IRQ ...I2C 的资料在 http://www.semiconductors.philip ....
NXP LPC1766 CAN总线滤波设置
NXP LPC1768 CAN 总线滤波设置分享开发环境:集成开发环境 μVision4 IDE 版本 4.60.0.0 主机系统:Microsoft Windows XP 开发平台:旺宝 NXP LPC1768 开发板 1 ...
NXP LPC1788之UART用法
Cortex-M3 (NXP LPC1788)之 UART 用法分类: Cortex-M3(NXP LPC1788)2012-06-27 17:14 2460 人阅读 评论(7) 收藏 举报 dllc 工作平台 在工作中经常将平台...
mbed NXP LPC1768
mbed NXP LPC1768_信息与通信_工程科技_专业资料。...M3 Core running at 96MHz, with 512KB FLASH, ...
基于LPC1768的无线遥控小车
M3 嵌入式开发实例详解:基于 NXP LPC1768》 ,孙...core, mainly to complete wireless data reception....如果收到应答, 则认为此次通信成功, TX_DS 置高,...
NXP Cortex-M3 选型指南
NXP Cortex-M3 选型指南_IT/计算机_专业资料。帮助开发人员选择最适合项目的NXP系列Cortex处理器。低功耗,高成本效益的 LPC1700 系列 Cortex-M3 微控器提供同类最佳...
IAR使用手册
IAR使用手册_信息与通信_工程科技_专业资料。ARM 开发和调试工具的使用 (IAR ...选项卡 Target 设置 Core:ARM7TDMI-S/Cortex-M3 Device:NXP LPC21xx/ST STM...
STM32与LPC1700的应用比较
STM32与LPC1700的应用比较_电子/电路_工程科技_专业...不像我现在NXP LPC1768 那样,AD 和 UART ...
更多相关标签:
nxp lpc1768 | nxp lpc1768 使用手册 | mbed nxp lpc1768 | nxp1768 | lpc1768 | lpc1768官方例程 | lpc1768中文手册 | lpc1768fbd100 |