0%

ARM-微控制器与接口技术代码分析

ARM-微控制器与接口技术代码分析

基于 open 1768 的单片机实验代码分析

open 1768 的硬件资源

硬件资源图示

【芯片简介】【1】 LPC1768

以下为 LPC1768FBD100 的核心资源参数:
内 核:Cortex-M3 32-bit RISC;
工作频率:100MHz Max;
工作电压:2.4-3.6V;(3.3V 典型值)
封 装:LQFP100;
I/O 口:70;
存储资源:512kB Flash,64kB RAM;
接口资源:2 x SPI,2 x SSP,4 x UART,3 x I2C,1 x I2S,6 x PWM,8 x ADC,1 x DAC;
调试下载:可通过 SWD 接口实现调试下载,可通过 UART接口实现 ISP。

【其他接口与器件】

仅介绍与实验有关的接口与器件

【6】用户 LED :便于 I/O 输出测试或显示程序运行状态
【25】8I/Os 接口(含 3 路 AD、1 路 DA):方便接入各类使用 I/O 控制的模块。 如 8 位按键模块,电机控制模块等。 同时,该接口具备了 AD/DA 功能,可以方便 AD/DA 测试
【26】ISP 接口(含 UART0 接口):方便接入 ISP 模块或使用 UART 接口的器件。 如 RS232、RS485、USB TO UART 模块等
【27】USB 接口:可与 PC 机进行 USB 通信
【28】5V DC 接口

单片机上的位操作

一般单片机不能够直接对寄存器的某一位进行操作,这时就需要通过一些间接的手段,即对所有位都进行操作,但是只改变某一位的值,对其他位没有影响

从 C 语言的位操作说起

首先得说明以下操作:

我们知道 C 语言的位操作,|【位或】&【位与】~【位取反】^【位异或】<<【位左移】>>【位右移】

那么下面这些操作也顺理成章

|=:【按位 “或” 后取值】

1
2
x = 0x02;
x |= 0x01;

0x 在 C 语言中表示这个数是一个十六进制数,我们将其转换为二进制数进行运算,一个十六进制位即对应四个二进制位
0x02 即 00000010
0x01 即 00000001
两个数进行 “或” 操作后,结果应为 00000011,即 0x03
我们看到,对 x 与 0x01 进行【按位 “或” 后取值】的操作后,相当于将 x 这个八位二进制数的最右边的一个二进制位,置为 “1”

&=:【按位 “与” 后取值】

1
2
x = 0x02;
x &= 0xFD;

十六进制中的 A~F(或 a~f)表示 1001(2) ~ 1111(2),即 9(10) ~ 15(10)
0x02 即 00000010
0xFD 即 11111101
两个数进行 “与” 操作后,结果应为 00000000,即 0x00
我们看到,对 x 与 0xFD 进行【按位 “与” 后取值】的操作后,相当于将 x 这个八位二进制数的从右往左数的的第二个二进制位,置为 “0”

^=:【按位 “异或” 后取值】

1
2
x = 0x03;
x ^= 0x01;

0x03 即 00000011
0x01 即 00000001
两个数进行 “异或” 操作后,结果应为 00000010,即 0x02
我们看到,对 x 与 0x01 进行【按位 “异或” 后取值】的操作后,相当于对 x 这个八位二进制数的最右边的一个二进制位,取反

这样,我们就有了对单片机上的寄存器进行位操作的方法

间接位操作

下面以 GPIO 端口方向寄存器 FIOxDIR 和 GPIO 管脚值寄存器 FIOxPIN 为例做演示,FIOxDIR 是一个32位的寄存器,作用是设定 GPIO 的方向,FIOxPIN 也是一个32位的寄存器,可以通过它获取管脚当前的电平状态
注:FIOxDIR 中的 x 即控制的引脚 Px.n 中的 x,FIOxPIN 同理

寄存器 32个二进制位
FIOxDIR Bit31 Bit30 Bit29 … Bit1 Bit0
FIOxPIN Bit31 Bit30 Bit29 … Bit1 Bit0
写位操作

置 1 使用 |= 操作,即按位 “或” 后取值

例如,我们需要设置 GPIO 方向,P0.0 为输出

1
FIO0DIR |= 0x00000001;

若是将 0x00000001 进行宏定义,程序将更加简洁

1
#define     BIT0        0x00000001

上面设置 GPIO 方向的操作可写为:

1
FIO0DIR |= BIT0;

可以使用加法进行批量操作

1
2
#define     BIT0        0x00000001
#define BIT4 0x00000010
1
FIO0DIR |= BIT0 + BIT4;

置 0 使用 &= ~ 操作,即取反后再按位 “或” 然后取值

可以直接使用 &= 操作吗,可以的,但是为了可以与置 1 操作共用宏定义,使用 &= ~ 更巧妙

例如,我们需要设置 GPIO 方向,P0.0 为输入

1
2
3
FIO0DIR &= 0xFFFFFFFE;          // 用 '&=' 置0
FIO0DIR &= ~0x00000001; // 用 '&= ~' 置0
FIO0DIR &= ~BIT0; // 共用宏定义

取反使用 ^= 操作,即按位 “异或” 后取值

反转 P0.0 的 GPIO 方向

1
2
FIO0DIR ^= 0x00000001;
FIO0DIR ^= BIT0;

这里要顺便补充一下左移 << 和右移 >>
操作的时候要考虑有符号数(signed number)和无符号数(unsigned number)的区别
对于有符号数:左移的时候右侧补0;右移的时候左侧补符号位(正数符号位为0,则补0;负数符号位为1,则补1)
对于无符号数:左移的时候右侧补0;右移的时候左侧也是补0

读位操作

如果我们想要通过 FIO0PIN 获取 P0.0 的当前电平状态

1
PinStat = FIO0PIN & 0x01;

利用 & 操作的性质将其他位都置为 0,对应 P0.0 的那一位为其当前电平状态

实验一及GPIO简介

GPIO简介

GPIO是通用型输入/输出(General Purpose I/O)的简称,主要用于工业现场需要用到数字量输入/输出的场合,例如:
继电器、 LED、蜂鸣器等的控制
传感器状态、高低电平等信息的输入等

GPIO特性描述

I/O结构
  • 大部分GPIO为推挽输出,具有完整I2C功能的是开漏结构
  • 正常拉出灌入电流为4mA,短时间极限值40mA;
通用输入输出
  • LPC1700 系列 Cortex-M3 有 5 组 GPIO,多达 70 个通用 I/O 管脚(100 管脚封装)
  • 所有 GPIO 寄存器位于 AHB 总线上,可以进行高性能的 CPU 快速访问,支持 Cortex-M3 位带操作
  • 可配置为上拉/下拉电阻、开漏和中继模式
  • GPIO 允许进行 DMA 数据操作
中断
  • LPC1700 系列 Cortex-M3 的 P0 和 P2 还具有中断功能,P0 和 P2 每个引脚都可配置为上升沿、下降沿或边沿中断

GPIO输入输出

I/O 相关寄存器与 I/O 功能框图
PINSELx 与 PINMODEx

图中首先涉及到了引脚连接模块中的引脚功能选择寄存器 PINSELx 与 引脚模式选择寄存器 PINMODEx

查用户手册可知:

仅当引脚选择 GPIO 功能时,GPIO 寄存器中的方向控制位才有效。对于其它功能来说,方
向是自动控制的

接着查到 P0.0 的配置方法:

PINSEL0 寄存器控制端口 0 低半部分的位功能。仅当引脚选择使用 GPIO 功能时,FIO0DIR
寄存器中的方向控制位才有效。对于其它功能来说,方向是自动控制的

据表可知,要想将 P0.0 设为 GPIO 功能,需要将 PINSEL0 中的 PINSEL0[1:0] 这两位都置零,即:

1
PINSEL0 &= 0xFFFFFFFC;

关于引脚模式选择寄存器 PINMODEx,这里不作过多解释

当引脚处于逻辑高电平时,中继模式使能上拉电阻;当引脚处于逻辑低电平时,使能下拉电
阻。当引脚配置为输入且不是通过外部驱动时,引脚将保持上一个已知状态。

FIOxDIR

FIOxDIR 为高速 GPIO 端口方向控制寄存器,该寄存器单独控制每个端口引脚的方向

当引脚被配置为 GPIO 功能时,该寄存器可用来控制引脚的方向。勿必根据引脚功能来设置
每个引脚的方向

符号 描述
31:1 FIOxDIR(FIO0DIR ~ FIO4DIR) 0/1 控制的引脚为输入引脚 / 控制的引脚为输出引脚
FIOxMASK

不作解释,可查询用户手册

FIOxSET 与 FIOxCLR
通用名称 描述 复位值
FIOSET 高速端口输出置位寄存器,该寄存器控制输出引脚的状态,写 1 使相应的端口引脚产生高电平,写 0 没有影响 0x0
FIOCLR 高速端口输出清零寄存器,该寄存器控制输出引脚的状态,写 1 使相应的端口引脚产生低电平。写 0 没有影响 0x0
FIOxPIN

高速端口引脚值寄存器,不管引脚方向或可选的功能选择如何,数字端口引脚的当前状态可从该寄存器中读出(只要引脚不配置为 ADC 的 输 入 )

I/O 操作流程
ZLG 操作实例
P0.0输出高电平
1
2
3
PINSEL0 &= 0xFFFFFFFC;      // 设置引脚连接模块,P0.0为GPIO
FIO0DIR |= 0x00000001; // 设置GPIO口方向,P0.0为输出
FIO0SET = 0x00000001; // 设置输出电平,P0.0为高电平
读P0.0管脚电平
1
2
3
4
uint32 PinStat;             // 定义变量
PINSEL0 &= 0xFFFFFFFC; // 设置引脚连接模块,P0.0为GPIO
FIO0DIR &= 0xFFFFFFFE; // 设置GPIO口方向,P0.0为输入
PinStat = FIO0PIN & 0x01; // 通过FIO0PIN获取P0.0当前电平状态

实验一代码分析

变量宏定义
1
2
3
#define LED3        (1 << 3)
#define LED3_OFF() FIO0SET |= LED3
#define LED3_ON() FIO0CLR |= LED3

这里为了方便操作,进行了变量的宏定义,显然 (1 << 3) 代表将 1 左移 3 位
相当于 LED3 即为 0x00000008,使得 Bit31 ~ Bit0 中的 Bit3 为 1,其余为 0

接着将端口 P0.3 产生高低电平宏定义为端口 P0.3 LED 灯的亮灭,特别注意,此处高电平对应 LED 灯灭,而低电平对应 LED 灯亮

延时函数

在跑马灯中,我们想要单片机做一个延时,即延长灯亮灯灭的时间。单片机通常有两种延时方式,分别是软件延时与硬件延时,硬件延时要用到定时器/计数器,这种方法可以提高 CPU 的工作效率,也能做到精确延时;而另一种是软件延时,这种方法主要采用循环体进行,即让单片机在一段时间内做一些空操作,使其在这段时间内输出端口的信号不发生任何的变化。我们这里采用软件延时

1
2
3
4
5
6
7
8
void myDelay (INT32U  ulTime)
{
INT32U i;
i = 0;
while (ulTime--) {
for (i = 0; i < 100000; i++); // 单片机在for循环中不做任何操作
}
}
main 函数
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
27
28
29
int main (void)
{

int i=0; /* 初始化要进行迭代的变量 */
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

FIO0DIR |= LED0 + LED1 + LED2 + LED3;
/* 初始化 P0 端口 GPIO 方向 */
LED0_OFF(); /* 使 LED 灯在初始状态下全灭 */
LED1_OFF();
LED2_OFF();
LED3_OFF();

while (1) /* while(1) 使得跑马灯程序一直运行 */
{
switch (i) /* 根据 i 的值判断哪个灯该亮,并在 case 中执行 */
{
case 0: LED0_ON();myDelay(50);LED0_OFF();myDelay(50); break;
case 1: LED1_ON();myDelay(50);LED1_OFF();myDelay(50); break;
case 2: LED2_ON();myDelay(50);LED2_OFF();myDelay(50); break;
case 3: LED3_ON();myDelay(50);LED3_OFF();myDelay(50); break;
default: break;
}
i++; /* 对 i 进行迭代 */
if(i > 3) i = 0; /* 限定 i 的范围 */
}

}

其中的 targetInit()pinInit() 函数在其他文件中进行了宏定义,此处只需知晓其抽象作用即可

实验一完整代码(main.c)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "..\config.h"

/******************** 变量宏定义 ********************/

#define LED0 (1 << 0)
#define LED0_OFF() FIO0SET |= LED0
#define LED0_ON() FIO0CLR |= LED0

#define LED1 (1 << 1)
#define LED1_OFF() FIO0SET |= LED1
#define LED1_ON() FIO0CLR |= LED1

#define LED2 (1 << 2)
#define LED2_OFF() FIO0SET |= LED2
#define LED2_ON() FIO0CLR |= LED2

#define LED3 (1 << 3)
#define LED3_OFF() FIO0SET |= LED3
#define LED3_ON() FIO0CLR |= LED3

/*****************************************************
** Function name: myDelay
** Descriptions: 软件延时
** input parameters: ulTime
** output parameters: 无
** Returned value: 无
*****************************************************/
void myDelay (INT32U ulTime)
{
INT32U i;
i = 0;
while (ulTime--) {
for (i = 0; i < 100000; i++);
}
}

int main (void)
{

int i=0;
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

FIO0DIR |= LED0 + LED1 + LED2 + LED3;

LED0_OFF();
LED1_OFF();
LED2_OFF();
LED3_OFF();

while (1)
{
switch (i)
{
case 0: LED0_ON();myDelay(50);LED0_OFF();myDelay(50); break;
case 1: LED1_ON();myDelay(50);LED1_OFF();myDelay(50); break;
case 2: LED2_ON();myDelay(50);LED2_OFF();myDelay(50); break;
case 3: LED3_ON();myDelay(50);LED3_OFF();myDelay(50); break;
default: break;
}
i++;
if(i > 3) i = 0;
}

}

GPIO 中断

由于实验中未使用到 GPIO 中断,此处简略地介绍一下

端口 P0 和 P2 引脚具有中断功能,GPIO 管脚的中断寄存器可分为两组:控制寄存器和状态寄存器

控制寄存器 状态寄存器
上升沿中断使能寄存器 IO0/2IntEnR 上升沿中断状态寄存器 IO0/2IntStatR
下降沿中断使能寄存器 IO0/2IntEnF 下降沿中断状态寄存器 IO0/2IntStatF
中断标志清零寄存器 IO0/2IntClr 整体中断状态寄存器 IOIntStatus

操作示例——设置P0.0下降沿中断
1
2
3
4
5
6
7
8
9
10
11
12
13
PINSEL0     &=  0xFFFFFFFC;                 /* 设置引脚连接模块 */
PINMODE0 &= 0xFFFFFFFC;
IO0IntEnF |= 0x01/* 设置下降沿中断 */
ISER0 |= (1 << 21); /* 使能 GPIO 中断 */
zyIrqEnable(); /* 打开全局中断 */

void GPIO_ISR (void)
{
if((IO0IntStatF & 0x01) != 0) { /* 判断是否为P0.0下降沿中断 */
IO0IntClr = 0x01; /* 清除中断标志 */
...... /* 其它代码 */
}
}

实验二与定时器简介

定时器/计数器概述

定时器/计数器本质上都是加法计数器
定时器是用来对固定周期的脉冲信号计数,如 CPU 内部的外设时钟 (PCLK)
计数器可以对脉冲长度不确定的信号进行计数,如微处理器外部 I/O 引脚的脉冲信号

定时器/计数器特性

注:4 个定时器/计数器,除了外设基址之外完全相同。4 个定时器最少有 2 个捕获输入和 2 个匹配输出,并且有多个引脚可以选择。定时器 2 引出了全部 4 个匹配输出。

  • 32 位的定时器/计数器,带有一个可编程的 32 位预分频器;
  • 计数器或定时器操作;
  • 每个定时器包含 2 个 32 位的捕获通道,当输入信号变化时捕捉定时器的瞬时值。也可以选择产生中断;
  • 4 个 32 位匹配寄存器,允许执行以下操作:
    • 匹配时连续工作,在匹配时可选择产生中断;
    • 在匹配时停止定时器运行,可选择产生中断;
    • 在匹配时复位定时器,可选择产生中断;
  • 有 4 个与匹配寄存器相对应的外部输出,这些输出具有以下功能:
    • 匹配时设为低电平;
    • 匹配时设为高电平;
    • 匹配时翻转电平;
    • 匹配时不执行任何操作。

内部结构,功能描述及部分寄存器介绍


通用寄存器名称 描述
IR(TxIR) 中断寄存器。可向 IR 写入相应的值来清除中断。也可读 IR 来确定 8 个中断源中哪个中断源被挂起
TCR(TxTCR) 定时器控制寄存器。TCR 用来控制定时器计数器功能。定时器计数器可以通过 TCR 来禁能或复位
PR(TxPR) 预分频寄存器。当预分频计数器的值与这个寄存器的值相等时,下个时钟 TC 加 1,PC 清零
TC(TxTC) 保存定时器计数器的计数值。32 位的 TC 每隔(PR+1)个 PCLK 周期递增一次。TC 通过 TCR 来控制
PC(TxPC) 预分频计数器。32 位的 PC 是一个计数器,它会增加到与 PR 中存放的值相等。当达到了 PR 的值时,TC 加 1,PC 清零。可以通过总线接口来观察和控制 PC
MCR(TxMCR) 匹配控制寄存器。MCR 用来控制在匹配出现时是否产生中断和是否复位 TC
MR(TxMRx) 匹配寄存器。MR 可通过 MCR 设定为在匹配时复位 TC,停止 TC 和 PC 和/或产生中断
CCR(TxCCR) 捕获控制寄存器。CCR 控制捕获时捕获输入边沿方式,以及在发生捕获时是否产生中断
CR(TxCRx) 捕获寄存器。当在 CAP 输入上产生捕获事件时,CR 装载 TC 的值
EMR(TxEMR) 外部匹配寄存器。EMR 控制外部匹配引脚 MATn.0-3(MAT0.0-3 和 MAT1.0-3)
CTCR(TxCTCR) 计数控制寄存器。CTCR 选择在定时器模式还是计数器模式工作,在计数器模式中选择计数的信号和边沿
计数功能模块


预分频器

定时器/计数器带有一个 32 位可编程预分频器,PC 每经过 PR+1 个 PCLK 周期 TC 就加 1

$定时器的计数频率 = \dfrac{F_{PCLK}}{PR + 1}$


计数外部脉冲

在计数器模式时,用户可以选择是在输入脉冲的上升沿、下降沿或者是边沿,实现对外部脉冲信号进行计数

匹配功能模块

定时器/计数器的当前计数值等于用户设定的“匹配值”时,根据相应设置,触发外部某个功能匹配输出,同时也可以产生中断信号

定时时间 t 与匹配值 MR 的计算关系:$t = \dfrac{MR \times (PR + 1)}{F_{PCLK}}$

捕获功能模块

当定时器/计数器运行时,在捕获引脚上,出现有效外部触发动作,此时定时器计数器的当前值保存到指定捕获寄存器中

部分寄存器用法

下面用一个定时器0初始化的例程,来说明部分寄存器的用法
这个例程利用定时器0的匹配功能,实现每秒产生一次中断的功能

ZLG 定时器0初始化例程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Time0Init(void)
{
T0TCR = 0x02; /* 定时器不使能,定时器复位 */
T0IR = 1; /* 清除匹配通道0的中断标志 */
T0CTCR = 0; /* 定时器模式 */
T0TC = 0; /* 计数器清零 */
T0PR = 0; /* 定时器时钟不分频 */
T0MR0 = FPCLK; /* 1s中断一次 */
T0MCR = 0x03; /* 匹配后产生中断,TC值复位 */

zyIsrSet(NVIC_TIMER0, /* 设置中断并使能 */
(INT32U)timer0Isr,
PRIO_TWO);
T0TCR = 0x01; /* 启动定时器 */
}
TxTCR 与 TxCTCR

定时器控制寄存器(TCR)用来控制定时器/计数器的操作,其拥有 0~7 八个二进制位,其中第 0 位为计数器使能位,第 1 位为计数器复位位,描述如下:

在上面的例程中,先使得定时器不使能、定时器复位,以便对定时器进行配置,在配置完成后即启动定时器

1
2
3
T0TCR  = 0x02;                  /*  定时器不使能,定时器复位     */
...... /* 配置过程 */
T0TCR = 0x01; /* 启动定时器 */

计数控制寄存器(CTCR)也拥有八个二进制位,用来在定时器模式和计数器模式之间进行选择,在计数器模式中选择计数的引脚和边沿


我们将其设置为定时器模式,只需使其 0 与 1 两位均为 0 即可

TxIR

中断寄存器(IR),拥有八个二进制位,0~3 位对应 MR0~MR3 的中断,即对应匹配通道 0~3 的中断标志,后面还有两位对应捕获中断,如果有中断产生,IR 中的对应位会置位,否则为 0。向对应的 IR 位写入 1 会复位中断。写入 0 无效

在例程中,我们需要使用匹配通道0,所以向对应位写入 1,复位匹配通道0的中断标志

TxTC

定时器计数器寄存器(TC)
当预分频计数器到达计数的上限时,32 位 TC 加 1。如果 TC 在到达计数器上限之前没有复位,它将一直计数到 0xFFFF FFFF,然后翻转到 0x0000 0000。该事件不会产生中断,如果需要,可用匹配寄存器检测溢出

在例程中,我们需要将其清零,然后才能够开始计数

TxPR 与 TxPC

预分频寄存器(PR)
32 位预分频寄存器指定了预分频计数器的最大值,例程中设置为 0
预分频计数器寄存器(PC)
32 位预分频计数器使用某个常量值来控制 PCLK 的分频,再使之输入 TC。预分频计数器
每个 PCLK 周期加 1。当其值到达预分频寄存器中保存的值时,定时器计数器 TC 加 1,预分频计数器在下个 PCLK 周期复位。例如,当 PR=0 时,定时器计数器每个 PCLK 周期加 1,当 PR=1 时定时器计数器每 2 个 PCLK 周期加 1,以此类推

TxMRx 与 TxMCR

匹配寄存器(TxMRx)
匹配寄存器值连续与定时器计数值相比较。当两个值相等时自动触发相应动作。这些动作
包括产生中断,复位定时器计数器或停止定时器。所执行的动作由 MCR 寄存器控制

匹配控制寄存器(TxMCR)
匹配控制寄存器用来控制发生匹配时所执行的操作


在例程中,我们需要 TC 值与 MR0 值匹配时产生一个中断,且此时 TC 复位,以便进行下一轮计数匹配

1
T0MCR  = 0x03;                  /*  匹配后产生中断,TC值复位     */

比较关键的是 MR0 值的确定,之前就给出了公式,在了解了这些寄存器的工作原理后,自己推出来应该没有问题

定时时间 t 与匹配值 MR 的计算关系:$t = \dfrac{MR \times (PR + 1)}{F_{PCLK}}$

为了定时一秒,我们将 PR 设为 $0$,将 MR 值设为 $F_{PCLK}$

这样,我们只要再设置中断并使能就完成了定时器0的初始化,使其每一秒产生一个中断

实验二代码分析

变量与宏定义

与实验一一致

定时器初始化函数

与上面定时器0的初始化例程基本一致,只是实验要求定时 0.5 秒,只需修改匹配寄存器 MR0 的值

1
T0MR0  = FPCLK / 2;
中断处理函数与 main 函数
1
2
3
4
5
6
7
8
int flag=0;
int x=1;

void timer0Isr (void)
{
T0IR = 0x01; /* 清除中断标志 */
flag=1;
}

中断处理函数中首先需要干一件非常重要的事,那就是将中断标志清除,即向对应的 IR 位写入 1,复位中断,干了这件事之后,再干其他的

这里利用之前设立的全局变量 flag,将其置为 1 来记录中断的发生,也就是要告诉 main 函数,一个定时周期已经过去了,该干啥干啥,同时在 main 函数中应该将 flag 重新置为 0,以等待下一次中断

main 函数非常之简单,此处略去分析过程

实验二完整代码(main.c)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
#include "..\config.h"

/******************************************* 变量与宏定义 ************************************************/

#define LED0 (1 << 0)
#define LED0_OFF() FIO0SET |= LED0
#define LED0_ON() FIO0CLR |= LED0

#define LED1 (1 << 1)
#define LED1_OFF() FIO0SET |= LED1
#define LED1_ON() FIO0CLR |= LED1

#define LED2 (1 << 2)
#define LED2_OFF() FIO0SET |= LED2
#define LED2_ON() FIO0CLR |= LED2

#define LED3 (1 << 3)
#define LED3_OFF() FIO0SET |= LED3
#define LED3_ON() FIO0CLR |= LED3

int flag=0;
int x=1;

/*********************************************************************************************************
* Function Name: timer0Isr
* Description: TIMER0 中断处理函数
* Input: 无
* Output: 无
* Return: 无
*********************************************************************************************************/
void timer0Isr (void)
{
T0IR = 0x01; /* 清除中断标志 */
flag=1;
}

/*********************************************************************************************************
** Function name: timer0Init
** Descriptions: 定时器0初始化程序
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void timer0Init (void)
{
T0TCR = 0x02;
T0IR = 1;
T0CTCR = 0;
T0TC = 0;
T0PR = 0;
T0MR0 = FPCLK / 2; /* 定时 0.5 秒 */
T0MCR = 0x03; /* 匹配后产生中断 */
zyIsrSet(NVIC_TIMER0, (unsigned long)timer0Isr, PRIO_TWO); /* 设置中断并使能 */
T0TCR = 0x01; /* 启动定时器 */
}

/*********************************************************************************************************
** Function name: main
** Descriptions: 定时器0中断实验。每1秒产生中断
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */
timer0Init(); /* 定时器0初始化 */

FIO0DIR |= LED0 + LED1 + LED2 + LED3;

LED0_OFF();
LED1_OFF();
LED2_OFF();
LED3_OFF();

while(1){
if(flag == 1){
flag = 0;
if(x == 1){ LED3_OFF(); LED0_ON(); }
else if(x == 2){ LED0_OFF(); LED1_ON(); }
else if(x == 3){ LED1_OFF(); LED2_ON(); }
else if(x == 4){ LED2_OFF(); LED3_ON(); }
x++;
if(x>4) x=1;
}
}
}

/********************************************* End Of File **********************************************/

实验三与UART串口简介

第三个实验的程序与第四个实验的程序展开来分析过于复杂,下面基本按照 ZLG 的 PPT 的思路来分析,很多图片也从 PPT 上直接截取

通用异步收发器(UART)

通用异步收发器(UART)是实现设备间异步串行通信的关键模块,LPC1700 系列 ARM 具有 4 个符合 16C550 工业标准的异步串口

  • 16 字节收发 FIFO;
  • 寄存器的存储单元符合’550 工业标准;
  • 接收器 FIFO 触发点可为 1、4、8 和 14 字节;
  • 内置波特率发生器;
  • 用于精确控制波特率的小数分频器,并拥有赖以实现软件流控制的自动波特率检测能
  • 力和机制;
  • 支持 DMA 发送和接收;
  • UART3 还包含一种支持红外通信的 IrDA 模式。

RS-232是PC机与设备通信里应用最广泛的一种串行接口。它被定义为一种在低速率串行通讯中增加通讯距离的单端标准,由于其最大通信距离的限制,因此它常用于本地设备之间的通信

RS-232特性

  • 最高速率约为 20 kb/s
  • 传输最大距离约为 15 m
  • 共模抑制比能力差

RS-485是一种常用远距离和多机通信的串行接口。RS-485只是定义电压和阻抗,编程方式和普通串口类似,与RS-232主要区别在于其特性

RS-485特性

  • 与 TTL 电平兼容
  • 传输距离实际达 1200 m
  • 共模抑制比能力强

LPC1700 系列 ARM 的 UART0/2/3 可以工作在 UART 模式,也可以工作在 IrDA 模式,这里只介绍 UART 模式

下图为结构框图


UARTn 部分寄存器映射

名称 描述
RBR(UxRBR)(DLAB=0)(只读) 接收缓冲寄存器。内含下一个要读取的已接收字符
THR(UxTHR)(DLAB=0)(只写) 发送保持寄存器。在此写入下一个要发送的字符
DLL(UxDLL)(DLAB=1) 除数锁存器 LSB。波特率除数值的最低有效字节
DLM(UxDLM)(DLAB=1) 除数锁存器 LSM。波特率除数值的最高有效字节。小数分频器是使用整个除数来产生波特率的
IER(UxIER)(DLAB=0) 中断使能寄存器。包含 7 个独立的中断使能位对应 7 个潜在的 UART1 中断
IIR(UxIIR)(只读) 中断 ID 寄存器。识别等待处理的中断
FCR(UxFCR)(只写) FIFO 控制寄存器。控制 UART1 FIFO 的使用和模式
LCR(UxLCR) 线控制寄存器。包含帧格式控制和间隔产生控制
LSR(UxLSR)(只读) 线状态寄存器。包含发送和接收的状态标志(包括线错误)

UARTn接收器缓冲寄存器

UnRBR([ 7:0 ])是 UARTn RX FIFO 的最高字节。它包含了最早接收到的字符,并且可通过总线接
口进行读取。LSB(位 0)表示最“早”接收的数据位。如果接收到的字符少于 8 位,未使用
的 MSB 则用 0 填充。
如果要访问 UnRBR,UnLCR 中的除数锁存器访问位(DLAB)必须为 0。UnRBR 为只读
寄存器。

UARTn发送保持寄存器

UnTHR([ 7:0 ])是 UARTn TX FIFO 的最高字节。它是 TX FIFO 中的最新字符,可通过总线接口进
行写入。LSB 代表第一个要发送出去的位。
如果要访问 UnTHR,UnLCR 中的除数锁存器访问位(DLAB)必须为 0。UnTHR 为只写
寄存器。

UARTn除数锁存器LSB和UARTn除数锁存器MSB寄存器

UARTn 除数锁存器是 UARTn 波特率发生器的一部分,它与小数分频器一同使用,保持产
生波特率时钟的APB时钟(PCLK)分频值,波特率时钟必须是波特率的16倍。UnDLL和UnDLM
寄存器一起构成了一个 16 位除数,其中 UnDLL 包含了除数的低 8 位而 UnDLM 包含了除数的高 8 位。分频值 0x0000 会被作为 0x0001 处理,因为除数不能为 0。如果要访问 UARTn 除数锁存寄存器,UnLCR 中的除数锁存器访问位(DLAB)必须为 1。

UART 基本操作

UART 初始化

手动波特率配置

波特率这里只介绍手动波特率

手动波特率配置模式:
UART波特率发生器的时钟源是APB时钟,APB时钟经过16分频后将该值保存在除数锁存寄存器DLM与DLL

目标波特率 $Baud = \dfrac{F_{PCLK}}{16 \times (UnDLM:UnDLL)}$

假设 APB 时钟为 24MHz,UART0 要得到的目标波特率为 9600

1
2
3
4
5
6
7
8
9
10
#define  FPCLK 24000000                   /*  24 MHz                    */
#define UART_BPS 9600

......

U0LCR = 0x83; /* 允许设置波特率 */
ulFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = ulFdiv / 256; /* 取高 8 位 */
U0DLL = ulFdiv % 256; /* 取低 8 位 */
U0LCR = 0x03; /* 锁定波特率 */

关于 U0LCR 可以看下面的帧格式设置

ulFdiv = (FPCLK / 16) / UART_BPS; 中计算结果小数部分被忽略掉,实际的波特率并不准确,为 9615

小数分频器寄存器(UnFDR)可以控制产生波特率的时钟预分频,大大降低了波特率因时钟整数分频所带来的误差,这里不作介绍

帧格式设置

UART通信时需保证收发两端的帧格式一致,否则会出现通信错误


UARTn 线控制寄存器 UnLCR 确定了发送或接收数据字符的格式


若要求UART0的工作模式为:8位字符长度,1个停止位,无奇偶校验

1
U0LCR = 0x03;

在手动配置波特率的时候,要先使能访问除数锁存器,即需置 DLAB 为 1,配置波特率完成后,再复位 DLAB

1
U0LCR = 0x83;                       /*  允许设置波特率              */
FIFO设置

FIFO的初始化比较简单,主要设置包括Rx的触发深度,Tx FIFO与Rx FIFO的复位,以及FIFO的使能

UARTn FIFO控制寄存器 UnFCR 控制 UARTn RX 和 TX FIFO 的操作


若要设 UART0 接收缓冲区触发点为 8 字节,同时使能并复位发送和接收 FIFO

1
U0FCR  = 0x87;
UART 数据收发

在数据收发的过程中,通常采用查询和中断两种方式来进行。它们的基本原理如下:

  • 查询方式:通过查询线状态寄存器(UnLSR)来获得数据发送和接收的状态,然后进行相应操作
  • 中断方式:通过中断实现对数据的收发,然后查询中断标志寄存器(UnIIR)来进行不同处理
线状态寄存器

UARTn 线状态寄存器 UnLSR 是一个只读寄存器,提供 UARTn TX 和 RX 模块的状态信息



中断

UARTn 中断使能寄存器 UnIER 用于使能 3 个 UARTn 中断源

1
U0IER  = 0x01;                        /*  使能接收中断(RDA 中断)       */

UnIER [0] 可以使能 UARTn 的接收数据可用中断,它还控制着字符接
收超时中断

UARTn 中断标识寄存器 UnIIR 提供状态代码用于指示一个挂起处理中断的优先级别和中断源。在访问 UnIIR 过程中,中断被冻结。如果在访问 UnIIR 过程中产生了中断,该中断会被记录,下次访问 UnIIR 时可读出该中断


判断接收数据可用(发生 RDA 中断)

1
U0IIR & 0x0E == 0x04

若上式逻辑值为真,则发生了 RDA 中断,同理,判断字符超时的方法为

1
U0IIR & 0x0E == 0x0C

UARTn RDA 中断(UnIIR[3:1]=010)与 CTI 中断(UnIIR[3:1]=110)共用第二优先级。当
UARTn Rx FIFO 深度到达 U1FCR[7:6]所定义的触发点时,RDA 就会被激活;当 UARTn Rx FIFO深度低于触发点时,RDA 复位。当 RDA 中断激活时,CPU 可读出由触发点所定义的数据块。
CTI 中断(UnIIR[3:1]=110)是一个第二优先级中断,当 UARTn Rx FIFO 内含有至少一个
字符并且在接收到 3.5 到 4.5 字符的时间内没有发生 UARTn Rx FIFO 动作时,该中断激活。任何 UARTn Rx FIFO 动作(UARTn RSR 的读取或写入)将会清除该中断。当接收到的信息不是触发点值的倍数时,CTI 中断将会清空 UARTn RBR。例如:如果外围设备想要发送一个长度为 105 个字符的信息,而触发值为 10 个字符,那么前 100 个字符将使 CPU 接收 10 个 RDA 中断,而剩下的 5 个字符使 CPU 收到 1 到 5 个 CTI 中断(取决于服务程序)。

ZLG UART0 中断例程与实验三

实验三是在 ZLG UART0 中断例程的基础上进行的改进,增加了一个数组,便于发送,在 uart0Isr 即 UART0 中断函数中要做一些修改

ZLG UART0 中断例程
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "..\config.h"

extern volatile INT8U GucRcvNew; /* 串口接收新数据的标志 */
extern INT8U GucRcvBuf[10] ; /* 串口接收数据缓冲区 */
extern INT32U GulNum; /* 串口接收数据的个数 */

#define UART_BPS 9600 /* 串口通信波特率 */
volatile INT8U GucRcvNew; /* 串口接收新数据的标志 */
INT8U GucRcvBuf[10] ; /* 串口接收数据缓冲区 */
INT32U GulNum; /* 串口接收数据的个数 */

/*********************************************************************************************************
** Function name: delayNS
** Descriptions: 延时函数
** input parameters: uiDly: 值越大,延时时间越长
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void delayNS (INT32U ulDly)
{
INT32U i;

for (; ulDly > 0; ulDly--) {
for(i = 0; i < 50000; i++);
}
}

/*********************************************************************************************************
* Function Name: uart0Isr
* Description: UART0 中断处理函数
* Input: None
* Output: None
* Return: None
*********************************************************************************************************/
void uart0Isr (void)
{
GulNum = 0;

while ((U0IIR & 0x01) == 0){ /* 判断是否有中断挂起 */
switch (U0IIR & 0x0E){ /* 判断中断标志 */

case 0x04: /* 接收数据中断 */
GucRcvNew = 1; /* 置接收新数据标志 */
for (GulNum = 0; GulNum < 8; GulNum++){ /* 连续接收8个字节 */
GucRcvBuf[GulNum] = U0RBR;
}
break;

case 0x0C: /* 字符超时中断 */
GucRcvNew = 1;
while ((U0LSR & 0x01) == 0x01){ /* 判断数据是否接收完毕 */
GucRcvBuf[GulNum] = U0RBR;
GulNum++;
}
break;

default:
break;
}
}
}

/*********************************************************************************************************
** Function name: uartInit
** Descriptions: 串口初始化,设置为8位数据位,1位停止位,无奇偶校验,波特率为9600
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uartInit (void)
{
INT16U ulFdiv;

U0LCR = 0x83; /* 允许设置波特率 */
ulFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = ulFdiv / 256;
U0DLL = ulFdiv % 256;
U0LCR = 0x03; /* 锁定波特率 */
U0FCR = 0x87; /* 使能FIFO,设置8个字节触发点 */
U0IER = 0x01; /* 使能接收中断 */
}

/*********************************************************************************************************
** Function name: uart0SendByte
** Descriptions: 向串口发送子节数据,并等待数据发送完成,使用查询方式
** input parameters: uiDat: 要发送的数据
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendByte (INT8U ucDat)
{
U0THR = ucDat; /* 写入数据 */
while ((U0LSR & 0x20) == 0); /* 等待数据发送完毕 */
}

/*********************************************************************************************************
** Function name: uart0SendStr
** Descriptions: 向串口发送字符串
** input parameters: pucStr: 要发送的字符串指针
** ulNum: 要发送的数据个数
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendStr (INT8U const *pucStr, INT32U ulNum)
{
INT32U i;

for (i = 0; i < ulNum; i++) { /* 发送指定个字节数据 */
uart0SendByte(*pucStr++);
}
}

/*********************************************************************************************************
** Function name: main
** Descriptions: 以中断方式接收上位机数据并将接收的数据回送给上位机。短接JP14,借助串口调试软件,
** 并设置波特率为9600,8位数据位,1位停止位,注意不要选中"HEX显示"
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

GucRcvNew = 0;
uartInit (); /* 串口初始化 */

zyIsrSet(NVIC_UART0,(unsigned long)uart0Isr,PRIO_ONE);
while (1){
if (GucRcvNew == 1){ /* 判断是否有新数据 */
GucRcvNew = 0; /* 清除标志 */
uart0SendStr (GucRcvBuf, GulNum); /* 向串口发送数据 */
}
}
}

/*********************************************************************************************************
End Of File
*********************************************************************************************************/
实验三完整代码(main.c)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "..\config.h"

#define UART_BPS 9600 /* 串口通信波特率 */
volatile INT8U GucRcvNew; /* 串口接收新数据的标志 */
INT8U GucRcvBuf[128]; /* 串口接收数据缓冲区 */
INT32U GulNum = 0; /* 串口接收数据的个数 */
INT32U GucRcvLen;
INT8U GucProcessBuf[128];
INT8U GucRcvfinishFlag = 0;

/*********************************************************************************************************
** Function name: delayNS
** Descriptions: 延时函数
** input parameters: uiDly: 值越大,延时时间越长
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void delayNS (INT32U ulDly)
{
INT32U i;
for (; ulDly > 0; ulDly--) {
for(i = 0; i < 50000; i++);
}
}

/*********************************************************************************************************
* Function Name: uart0Isr
* Description: UART0 中断处理函数
* Input: None
* Output: None
* Return: None
*********************************************************************************************************/
void uart0Isr (void)
{
INT8U i;
while ((U0IIR & 0x01) == 0){ /* 判断是否有中断挂起 */
switch (U0IIR & 0x0E){ /* 判断中断标志 */

case 0x04: /* 接收数据中断 */
for (i = 0; i < 7; i++){ /* 连续接收8个字节 */
GucRcvBuf[GulNum] = U0RBR;
GulNum++;
}
break;

case 0x0C: /* 字符超时中断 */

while ((U0LSR & 0x01) == 0x01){ /* 判断数据是否接收完毕 */
GucRcvBuf[GulNum] = U0RBR;
GulNum++;
if(GulNum >= 128){
GulNum = 0;
}
}
for (i = 0; i < GulNum; i++){
GucProcessBuf[i] = GucRcvBuf[i];
}

GucRcvfinishFlag = 1;
GucRcvLen = GulNum;
GulNum = 0;
break;

default:
break;
}
}
}

/*********************************************************************************************************
** Function name: uartInit
** Descriptions: 串口初始化,设置为8位数据位,1位停止位,无奇偶校验,波特率为9600
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uartInit (void)
{
INT16U ulFdiv;

U0LCR = 0x83; /* 允许设置波特率 */
ulFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = ulFdiv / 256;
U0DLL = ulFdiv % 256;
U0LCR = 0x03; /* 锁定波特率 */
U0FCR = 0x87; /* 使能FIFO,设置8个字节触发点 */
U0IER = 0x01; /* 使能接收中断 */
}

/*********************************************************************************************************
** Function name: uart0SendByte
** Descriptions: 向串口发送子节数据,并等待数据发送完成,使用查询方式
** input parameters: uiDat: 要发送的数据
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendByte (INT8U ucDat)
{
U0THR = ucDat; /* 写入数据 */
while ((U0LSR & 0x20) == 0); /* 等待数据发送完毕 */
}

/*********************************************************************************************************
** Function name: uart0SendStr
** Descriptions: 向串口发送字符串
** input parameters: pucStr: 要发送的字符串指针
** ulNum: 要发送的数据个数
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendStr (INT8U const *pucStr, INT32U ulNum)
{
INT32U i;

for (i = 0; i < ulNum; i++) { /* 发送指定个字节数据 */
uart0SendByte(*pucStr++);
}
}

/*********************************************************************************************************
** Function name: main
** Descriptions: 以中断方式接收上位机数据并将接收的数据回送给上位机。短接JP14,借助串口调试软件,
** 并设置波特率为9600,8位数据位,1位停止位,注意不要选中"HEX显示"
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

uartInit (); /* 串口初始化 */

zyIsrSet(NVIC_UART0,(unsigned long)uart0Isr,PRIO_ONE);
while (1){
if (GucRcvfinishFlag == 1){ /* 判断是否有新数据 */
GucRcvfinishFlag = 0; /* 清除标志 */
uart0SendStr (GucRcvBuf, GucRcvLen); /* 向串口发送数据 */
}
}
}

/*********************************************************************************************************
End Of File
*********************************************************************************************************/

实验四与ADC简介

ADC简介

LPC1700系列Cortex-M3具有1个12位的逐次逼近式的ADC,并可以根据应用进行灵活配置。可应用于工业现场的模拟信号到数字信号转换

ADC功能特性

  • 具有掉电模式;
  • 12位转换时间达200KHz;
  • 一个或多个输入的Burst模式;
  • 可选由输入跳变或定时器匹配信号触发转换。
  • 12 位主次逼近式模数转换器;
  • 8 个引脚复用为 A/D 输入脚;
  • 测量范围:0~VREFP(通常为 3V;不超过 VDDA);


ADC 基本操作
引脚、电源配置

电源控制:通过置位PCONP.PADC位使能ADC时钟源

引脚配置:当使用ADC的模拟引脚测量电压时,可不理会引脚在PINSEL寄存器中的设置,但是这样会影响测量精度。可通过选择AIN功能改善测量精度


ADC初始化配置

ADC的初始化主要通过写AD0CR配置ADC转换所需的时钟、工作模式、转换速率等完成

1
2
3
4
5
6
7
PCONP  |= 1 << PADC;                    // (1) 打开ADC功率控制位
PISEL3 |= ((unsigned)0x03) << 30; // (2) 配置引脚为AIN功能
AD0CR = (1 << 5) // (3) 设置转换通道,通道5
| ((Fpclk/1000000-1) << 8) // (4) 设置转换时钟,1MHz
| (0 << 16) // (5) 设置转换模式,软件模式
| (1 << 21) // (6) 设置工作模式,正常
| (1 << 24); // (7) 设置启动方式,直接启动

参考 ADxCR 寄存器


ADC转换结果处理

A/D转换完成后,转换结果保存在ADDRx和AD0GDR中。但该结果只是转换后的数字量,必须进行转换。假定要读取通道x的电压值,A/D的参考电压为VREF

则实际转换结果为:$实际电压 = \dfrac{ADDRx \times V_{REF}}{4096}$

转换参考代码:

1
2
3
ulADCbuf = ADDRx;
ulADCbuf = (ulADCbuf >> 4) & 0xfff;
ulADCData = (ulADCData * Vref)/4096;
实验四 ADC 初始化函数
1
2
3
4
5
6
7
8
9
10
11
void adcInit (void)
{
INT32U ulTemp;
ulTemp = (24000000 / (13000000));
ulTemp = (1 << 1) /* 选择AD0.1为AD输入引脚 */
|((ulTemp) << 8) /* 转换时钟为13MHz */
|(0 << 16) /* BURST = 0,软件控制转换操作 */
|(1 << 21) /* PDN = 1,正常工作模式 */
|(1 << 24) /* 设置直接启动模式 */
AD0CR = ulTemp;
}

实验四完整代码(main.c)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "..\config.h"

/*********************************************************************************************************
宏定义
*********************************************************************************************************/
#define UART_BPS 9600 /* 串口通信波特率 */
char GcRcvBuf[20]; /* AD采集到的数据 */

/*********************************************************************************************************
** Function name: myDelay
** Descriptions: 软件延时
** input parameters: ulTime
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void myDelay (INT32U ulTime)
{
INT32U i;

i = 0;
while (ulTime--) {
for (i = 0; i < 5000; i++);
}
}

/*********************************************************************************************************
** Function name: uart0Init
** Descriptions: 按默认值初始化串口0的引脚和通讯参数。设置为8位数据位,1位停止位,无奇偶校验
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0Init (void)
{
INT16U usFdiv;

U0LCR = 0x83; /* 允许设置波特率 */
usFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = usFdiv / 256;
U0DLL = usFdiv % 256;
U0LCR = 0x03; /* 锁定波特率 */
U0FCR = 0x06;
}

/*********************************************************************************************************
** Function name: uart0SendByte
** Descriptions: 从串口0发送数据
** input parameters: data: 发送的数据
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendByte (INT8U ucData)
{
U0THR = ucData;
while ( (U0LSR & 0x40) == 0 );
}

/*********************************************************************************************************
** Function name: uart0SendStr
** Descriptions: 向串口发送字符串
** input parameters: pucStr: 要发送的字符串指针
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendStr (INT8U const *pucStr)
{
while (1) {
if (*pucStr == '\0')break; /* 遇到结束符,退出 */
uart0SendByte (*pucStr++);
}

}

/*********************************************************************************************************
* Function name: adcInit
* Descriptions: ADC初始化
* input parameters: 无
* output parameters: 无
* Returned value: 无
*********************************************************************************************************/
void adcInit (void)
{
INT32U ulTemp;
ulTemp = (24000000 / (13000000));
ulTemp = (1 << 1) /* 选择AD0.1为AD输入引脚 */
|((ulTemp) << 8) /* 转换时钟为13MHz */
|(0 << 16) /* BURST = 0,软件控制转换操作 */
|(1 << 21) /* PDN = 1,正常工作模式 */
|(1 << 24) /* 设置直接启动模式 */
AD0CR = ulTemp;
}

/*********************************************************************************************************
** Function name: main
** Descriptions: AD采集数据例程,需将跳线一端连到JP22的P0.24脚,另一端连接待测电压端。同时将PC机的
** 串口线连接到开发板UART0,然后短接JP14跳线组,打开Easyarm串口调试软件,观察采样结果
** 注意:由于AD参考电压是3.0V,若直接采用P0.23采集电压,电压不得高于3.0V。若经过开发板
** 的采集电路后,JP16端输入电压范围为-5V~+5V
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
static INT32U ulADCbuf; /* AD采集数据缓冲区 */
static INT32U ulADCData;
static INT8U i;

targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

uart0Init();

PCONP |= 1 << 12; /* 打开ADC电源 */
adcInit();

while (1) {
ulADCData = 0;
for(i = 0;i < 8; i++)
{
AD0CR |= 1 << 24; /* 立即转换 */
while ((ADSTAT & (1 << 1)) == 0); /* 读取AD0STAT的通道1的Done */
AD0CR |= (1 <<24); /* 第一次转换结果丢弃 */
while ((ADSTAT & (1 << 1)) == 0); /* 读取AD0STAT的通道1的Done */
ulADCbuf = ADDR1; /* 只有一路,则读取全局寄存器 */
ulADCbuf = (ulADCbuf >> 4) & 0xfff;
ulADCData += ulADCbuf;
}
ulADCData = (ulADCData/8); /* 采样8次进行滤波处理 */
ulADCData = (ulADCData*3300)/4096;
sprintf(GcRcvBuf,"VIN1 = %4d mv",ulADCData);
uart0SendStr(GcRcvBuf);

myDelay(1000);
}
}

/*********************************************************************************************************
End Of File
*********************************************************************************************************/

附录

LPC1700 系列概述

以下内容摘自《LPC1700 用户手册 - 广州周立功单片机发展有限公司》

简介

LPC1700 系列 Cortex-M3 微控制器用于处理要求高度集成和低功耗的嵌入式应用。ARM Cortex-M3 是下一代新生内核,它可提供系统增强型特性,例如现代化调试特性和支持更高级别的块集成。

LPC1700 系列 Cortex-M3 微控制器的操作频率可达 100MHz。ARM Cortex-M3 CPU 具有 3 级流水线和哈佛结构,带独立的本地指令和数据总线以及用于外设的稍微低性能的第三条总线。ARM Cortex-M3 CPU 还包含一个支持随机跳转的内部预取指单元。

LPC1700 系列 Cortex-M3 微控制器的外设组件包含高达 512KB 的 Flash 存储器、64KB 的数据存储器、以太网 MAC、USB 主机/从机/OTG 接口、8 通道的通用 DMA 控制器、4 个 UART、 2 条 CAN 通道、2 个 SSP 控制器、SPI 接口、3 个 I2C 接口、2-输入和 2-输出的 I2S 接口、8 通道的 12 位 ADC、10 位 DAC、电机控制 PWM、正交编码器接口、4 个通用定时器、6-输出的通用 PWM、带独立电池供电的超低功耗 RTC 和多达 70 个的通用 I/O 管脚。

特性

  • ARM Cortex-M3 处理器,可在高至 100MHz 的频率下运行,并包含一个支持 8 个区的存储器保护单元(MPU);
  • ARM Cortex-M3 内置了嵌套的向量中断控制器(NVIC);
  • 具有在系统编程(ISP)和在应用编程(IAP)功能的 512KB 片上 Flash 程序存储器。把增强型的 Flash 存储加速器和 Flash 存储器在 CPU 本地代码/数据总线上的位置进行整合,则 Flash 可提供高性能的代码;
  • 64KB 片内 SRAM 包括:
    • 32KB SRAM 可供高性能 CPU 通过本地代码/数据总线访问;
    • 2 个 16KB SRAM 模块,带独立访问路径,可进行更高吞量的操作。这些 SRAM 模块可用于以太网、USB、DMA 存储器,以及通用指令和数据存储;
  • AHB 多层矩阵上具有 8 通道的通用 DMA 控制器,它可结合 SSP、I2S、UART、模数和数模转换器外设、定时器匹配信号和 GPIO 使用,并可用于存储器到存储器的传输;
  • 多层 AHB 矩阵内部连接,为每个 AHB 主机提供独立的总线。AHB 主机包括 CPU、通用 DMA 控制器、以太网 MAC 和 USB 接口。这个内部连接特性提供无仲裁延迟的通信,除非 2 个主机尝试同时访问同一个从机;
  • 分离的 APB 总线允许在 CPU 和 DMA 之间提供更多的带宽,更少的延迟。CPU 无须等待 APB 写操作完成;
  • 串行接口
    • 以太网 MAC 带 RMII 接口和相关的 DMA 控制器;
    • USB 2.0 全速从机/主机/OTG 控制器,带有用于从机、主机功能的片内 PHY 和相关的 DMA 控制器;
    • 4 个 UART,带小数波特率发生功能、内部 FIFO、DMA 支持和 RS-485 支持。1 个 UART 带有 modem 控制 I/O 并支持 RS-485/EIA-485,全部的 UART 都支持 IrDA;
    • CAN 控制器,带 2 个通道;
    • SPI 控制器,具有同步、串行、全双工通信和可编程的数据长度;
    • 2 个 SSP 控制器,带有 FIFO,可按多种协议进行通信。其中一个可选择用于 SPI,并且和 SPI 共用中断。SSP 接口可以与 GPDMA 控制器一起使用;
    • 3 个增强型的 I2C 总线接口,其中 1 个具有开漏输出功能,支持整个 I2C 规范和数据速率为 1Mbit/s 的快速模式,另外 2 个具有标准的端口管脚。增强型特性包括多个地址识别功能和监控模式;
    • I2S(Inter-IC Sound)接口,用于数字音频输入或输出,具有小数速率控制功能。I2S接口可与 GPDMA 一起使用。I2S 接口支持 3-线的数据发送和接收或 4-线的组合发送和接收连接,以及主机时钟输入/输出;
  • 其它外设:
    • 70 个(100 个管脚封装)通用 I/O(GPIO)管脚,带可配置的上拉/下拉电阻。AHB总线上的所有 GPIO 可进行快速访问,支持新的、可配置的开漏操作模式;GPIO 位于存储器中,它支持 Cortex-M3 位带宽并且由通用 DMA 控制器使用;
    • 12 位模数转换器(ADC),可在 8 个管脚间实现多路输入,转换速率高达 1MHz,并具有多个结果寄存器。12 位 ADC 可与 GPDMA 控制器一起使用;
    • 10 位数模转换器(DAC),具有专用的转换定时器,并支持 DMA 操作;
    • 4 个通用定时/计数器,共有 8 个捕获输入和 10 个比较输出。每个定时器模块都具有一个外部计数输入。可选择特定的定时器事件来产生 DMA 请求;
    • 1 个电机控制 PWM,支持三相的电机控制;
    • 正交编码器接口,可监控一个外部正交编码器;
    • 1 个标准的 PWM/定时器模块,带外部计数输入;
    • 实时时钟(RTC)带有独立的电源域。RTC 通过专用的 RTC 振荡器来驱动。RTC模块包括 20 字节电池供电的备用寄存器,当芯片的其它部分掉电时允许系统状态存储在该寄存器中。电池电源可由标准的 3V 锂电池供电。当电池电压掉至 2.1V 的低电压时,RTC 仍将会继续工作。RTC 中断可将 CPU 从任何低功率模式中唤醒;
    • 看门狗定时器(WDT),该定时器的时钟源可在内部 RC 振荡器、RTC 振荡器或 APB时钟三者间进行选择;
    • 支持 ARM Cortex-M3 系统节拍定时器,包括外部时钟输入选项;
    • 重复性的中断定时器提供可编程和重复定时的中断;
  • 标准 JTAG 测试/调试接口以及串行线调试和串行线跟踪端口选项;
  • 仿真跟踪模块支持实时跟踪;
  • 4 个低功率模式:睡眠、深度睡眠、掉电、深度掉电;
  • 单个 3.3V 电源(2.4V – 3.6V)。温度范围为-40°C - 85°C;
  • 4 个外部中断输入,可配置为边沿/电平触发。PORT0 和 PORT2 上的所有管脚都可用作边沿触发的中断源;
  • 不可屏蔽中断(NMI)输入;
  • 时钟输出功能,可反映主振荡器时钟、IRC 时钟、RTC 时钟、CPU 时钟或 USB 时钟的输出状态;
  • 当处于掉电模式时,可通过中断(包括外部中断、RTC 中断、USB 活动中断、以太网唤醒中断、CAN 总线活动中断、PORT0/2 管脚中断和 NMI)将处理器从掉电模式中唤醒;
  • 每个外设都自带时钟分频器,以进一步节省功耗;
  • 带掉电检测功能,可对掉电中断和强制复位分别设置阀值;
  • 片内有上电复位电路;
  • 片内晶振工作频率为 1MHz 到 24MHz;
  • 4MHz 内部 RC 振荡器可在±1%的精度内调整,可选择用作系统时钟;
  • 通过片内 PLL,没有高频晶振,CPU 也可以最高频率运转。用户可从主振荡器、内部 RC 振荡器或 RTC 振荡器三者中选择一个作为 PLL 时钟源;
  • 第二个专用的 PLL 可用于 USB 接口,以允许增加主 PLL 设置的灵活性;
  • 用户可在管脚对应的多种功能中进行选择;
  • 可采用 100 脚和 80 脚 LQFP 封装(14×14×1.4mm)。

完整实验程序(main.c 文件)

实验一、GPIO例程之跑马灯

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "..\config.h"

/******************** 变量宏定义 ********************/

#define LED0 (1 << 0)
#define LED0_OFF() FIO0SET |= LED0
#define LED0_ON() FIO0CLR |= LED0

#define LED1 (1 << 1)
#define LED1_OFF() FIO0SET |= LED1
#define LED1_ON() FIO0CLR |= LED1

#define LED2 (1 << 2)
#define LED2_OFF() FIO0SET |= LED2
#define LED2_ON() FIO0CLR |= LED2

#define LED3 (1 << 3)
#define LED3_OFF() FIO0SET |= LED3
#define LED3_ON() FIO0CLR |= LED3

/*****************************************************
** Function name: myDelay
** Descriptions: 软件延时
** input parameters: ulTime
** output parameters: 无
** Returned value: 无
*****************************************************/
void myDelay (INT32U ulTime)
{
INT32U i;
i = 0;
while (ulTime--) {
for (i = 0; i < 100000; i++);
}
}

int main (void)
{

int i=0;
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

FIO0DIR |= LED0 + LED1 + LED2 + LED3;

LED0_OFF();
LED1_OFF();
LED2_OFF();
LED3_OFF();

while (1)
{
switch (i)
{
case 0: LED0_ON();myDelay(50);LED0_OFF();myDelay(50); break;
case 1: LED1_ON();myDelay(50);LED1_OFF();myDelay(50); break;
case 2: LED2_ON();myDelay(50);LED2_OFF();myDelay(50); break;
case 3: LED3_ON();myDelay(50);LED3_OFF();myDelay(50); break;
default: break;
}
i++;
if(i > 3) i = 0;
}

}

实验二、定时器例程之跑马灯

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
#include "..\config.h"

/******************************************* 变量与宏定义 ************************************************/

#define LED0 (1 << 0)
#define LED0_OFF() FIO0SET |= LED0
#define LED0_ON() FIO0CLR |= LED0

#define LED1 (1 << 1)
#define LED1_OFF() FIO0SET |= LED1
#define LED1_ON() FIO0CLR |= LED1

#define LED2 (1 << 2)
#define LED2_OFF() FIO0SET |= LED2
#define LED2_ON() FIO0CLR |= LED2

#define LED3 (1 << 3)
#define LED3_OFF() FIO0SET |= LED3
#define LED3_ON() FIO0CLR |= LED3

int flag=0;
int x=1;

/*********************************************************************************************************
* Function Name: timer0Isr
* Description: TIMER0 中断处理函数
* Input: 无
* Output: 无
* Return: 无
*********************************************************************************************************/
void timer0Isr (void)
{
T0IR = 0x01; /* 清除中断标志 */
flag=1;
}

/*********************************************************************************************************
** Function name: timer0Init
** Descriptions: 定时器0初始化程序
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void timer0Init (void)
{
T0TCR = 0x02;
T0IR = 1;
T0CTCR = 0;
T0TC = 0;
T0PR = 0;
T0MR0 = FPCLK / 2; /* 定时 0.5 秒 */
T0MCR = 0x03; /* 匹配后产生中断 */
zyIsrSet(NVIC_TIMER0, (unsigned long)timer0Isr, PRIO_TWO); /* 设置中断并使能 */
T0TCR = 0x01; /* 启动定时器 */
}

/*********************************************************************************************************
** Function name: main
** Descriptions: 定时器0中断实验。每1秒产生中断
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */
timer0Init(); /* 定时器0初始化 */

FIO0DIR |= LED0 + LED1 + LED2 + LED3;

LED0_OFF();
LED1_OFF();
LED2_OFF();
LED3_OFF();

while(1){
if(flag == 1){
flag = 0;
if(x == 1){ LED3_OFF(); LED0_ON(); }
else if(x == 2){ LED0_OFF(); LED1_ON(); }
else if(x == 3){ LED1_OFF(); LED2_ON(); }
else if(x == 4){ LED2_OFF(); LED3_ON(); }
x++;
if(x>4) x=1;
}
}
}

/********************************************* End Of File **********************************************/

实验三、UART串口

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "..\config.h"

#define UART_BPS 9600 /* 串口通信波特率 */
volatile INT8U GucRcvNew; /* 串口接收新数据的标志 */
INT8U GucRcvBuf[128]; /* 串口接收数据缓冲区 */
INT32U GulNum = 0; /* 串口接收数据的个数 */
INT32U GucRcvLen;
INT8U GucProcessBuf[128];
INT8U GucRcvfinishFlag = 0;

/*********************************************************************************************************
** Function name: delayNS
** Descriptions: 延时函数
** input parameters: uiDly: 值越大,延时时间越长
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void delayNS (INT32U ulDly)
{
INT32U i;
for (; ulDly > 0; ulDly--) {
for(i = 0; i < 50000; i++);
}
}

/*********************************************************************************************************
* Function Name: uart0Isr
* Description: UART0 中断处理函数
* Input: None
* Output: None
* Return: None
*********************************************************************************************************/
void uart0Isr (void)
{
INT8U i;
while ((U0IIR & 0x01) == 0){ /* 判断是否有中断挂起 */
switch (U0IIR & 0x0E){ /* 判断中断标志 */

case 0x04: /* 接收数据中断 */
for (i = 0; i < 7; i++){ /* 连续接收8个字节 */
GucRcvBuf[GulNum] = U0RBR;
GulNum++;
}
break;

case 0x0C: /* 字符超时中断 */

while ((U0LSR & 0x01) == 0x01){ /* 判断数据是否接收完毕 */
GucRcvBuf[GulNum] = U0RBR;
GulNum++;
if(GulNum >= 128){
GulNum = 0;
}
}
for (i = 0; i < GulNum; i++){
GucProcessBuf[i] = GucRcvBuf[i];
}

GucRcvfinishFlag = 1;
GucRcvLen = GulNum;
GulNum = 0;
break;

default:
break;
}
}
}

/*********************************************************************************************************
** Function name: uartInit
** Descriptions: 串口初始化,设置为8位数据位,1位停止位,无奇偶校验,波特率为9600
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uartInit (void)
{
INT16U ulFdiv;

U0LCR = 0x83; /* 允许设置波特率 */
ulFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = ulFdiv / 256;
U0DLL = ulFdiv % 256;
U0LCR = 0x03; /* 锁定波特率 */
U0FCR = 0x87; /* 使能FIFO,设置8个字节触发点 */
U0IER = 0x01; /* 使能接收中断 */
}

/*********************************************************************************************************
** Function name: uart0SendByte
** Descriptions: 向串口发送子节数据,并等待数据发送完成,使用查询方式
** input parameters: uiDat: 要发送的数据
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendByte (INT8U ucDat)
{
U0THR = ucDat; /* 写入数据 */
while ((U0LSR & 0x20) == 0); /* 等待数据发送完毕 */
}

/*********************************************************************************************************
** Function name: uart0SendStr
** Descriptions: 向串口发送字符串
** input parameters: pucStr: 要发送的字符串指针
** ulNum: 要发送的数据个数
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendStr (INT8U const *pucStr, INT32U ulNum)
{
INT32U i;

for (i = 0; i < ulNum; i++) { /* 发送指定个字节数据 */
uart0SendByte(*pucStr++);
}
}

/*********************************************************************************************************
** Function name: main
** Descriptions: 以中断方式接收上位机数据并将接收的数据回送给上位机。短接JP14,借助串口调试软件,
** 并设置波特率为9600,8位数据位,1位停止位,注意不要选中"HEX显示"
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

uartInit (); /* 串口初始化 */

zyIsrSet(NVIC_UART0,(unsigned long)uart0Isr,PRIO_ONE);
while (1){
if (GucRcvfinishFlag == 1){ /* 判断是否有新数据 */
GucRcvfinishFlag = 0; /* 清除标志 */
uart0SendStr (GucRcvBuf, GucRcvLen); /* 向串口发送数据 */
}
}
}

/*********************************************************************************************************
End Of File
*********************************************************************************************************/

实验四、ADC实验

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "..\config.h"

/*********************************************************************************************************
宏定义
*********************************************************************************************************/
#define UART_BPS 9600 /* 串口通信波特率 */
char GcRcvBuf[20]; /* AD采集到的数据 */

/*********************************************************************************************************
** Function name: myDelay
** Descriptions: 软件延时
** input parameters: ulTime
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void myDelay (INT32U ulTime)
{
INT32U i;

i = 0;
while (ulTime--) {
for (i = 0; i < 5000; i++);
}
}

/*********************************************************************************************************
** Function name: uart0Init
** Descriptions: 按默认值初始化串口0的引脚和通讯参数。设置为8位数据位,1位停止位,无奇偶校验
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0Init (void)
{
INT16U usFdiv;

U0LCR = 0x83; /* 允许设置波特率 */
usFdiv = (FPCLK / 16) / UART_BPS; /* 设置波特率 */
U0DLM = usFdiv / 256;
U0DLL = usFdiv % 256;
U0LCR = 0x03; /* 锁定波特率 */
U0FCR = 0x06;
}

/*********************************************************************************************************
** Function name: uart0SendByte
** Descriptions: 从串口0发送数据
** input parameters: data: 发送的数据
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendByte (INT8U ucData)
{
U0THR = ucData;
while ( (U0LSR & 0x40) == 0 );
}

/*********************************************************************************************************
** Function name: uart0SendStr
** Descriptions: 向串口发送字符串
** input parameters: pucStr: 要发送的字符串指针
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
void uart0SendStr (INT8U const *pucStr)
{
while (1) {
if (*pucStr == '\0')break; /* 遇到结束符,退出 */
uart0SendByte (*pucStr++);
}

}

/*********************************************************************************************************
* Function name: adcInit
* Descriptions: ADC初始化
* input parameters: 无
* output parameters: 无
* Returned value: 无
*********************************************************************************************************/
void adcInit (void)
{
INT32U ulTemp;
ulTemp = (24000000 / (13000000));
ulTemp = (1 << 1) /* 选择AD0.1为AD输入引脚 */
|((ulTemp) << 8) /* 转换时钟为13MHz */
|(0 << 16) /* BURST = 0,软件控制转换操作 */
|(1 << 21) /* PDN = 1,正常工作模式 */
|(1 << 24) /* 设置直接启动模式 */
|(0 << 27 ); /* 设置模式,直接启动模式下无效 */
AD0CR = ulTemp;
}

/*********************************************************************************************************
** Function name: main
** Descriptions: AD采集数据例程,需将跳线一端连到JP22的P0.24脚,另一端连接待测电压端。同时将PC机的
** 串口线连接到开发板UART0,然后短接JP14跳线组,打开Easyarm串口调试软件,观察采样结果
** 注意:由于AD参考电压是3.0V,若直接采用P0.23采集电压,电压不得高于3.0V。若经过开发板
** 的采集电路后,JP16端输入电压范围为-5V~+5V
** input parameters: 无
** output parameters: 无
** Returned value: 无
*********************************************************************************************************/
int main (void)
{
static INT32U ulADCbuf; /* AD采集数据缓冲区 */
static INT32U ulADCData;
static INT8U i;

targetInit(); /* 初始化目标板,切勿删除 */
pinInit(); /* 引脚初始化 */

uart0Init();

PCONP |= 1 << 12; /* 打开ADC电源 */
adcInit();

while (1) {
ulADCData = 0;
for(i = 0;i < 8; i++)
{
AD0CR |= 1 << 24; /* 立即转换 */
while ((ADSTAT & (1 << 1)) == 0); /* 读取AD0STAT的通道1的Done */
AD0CR |= (1 <<24); /* 第一次转换结果丢弃 */
while ((ADSTAT & (1 << 1)) == 0); /* 读取AD0STAT的通道1的Done */
ulADCbuf = ADDR1; /* 只有一路,则读取全局寄存器 */
ulADCbuf = (ulADCbuf >> 4) & 0xfff;
ulADCData += ulADCbuf;
}
ulADCData = (ulADCData/8); /* 采样8次进行滤波处理 */
ulADCData = (ulADCData*3300)/4096;
sprintf(GcRcvBuf,"VIN1 = %4d mv",ulADCData);
uart0SendStr(GcRcvBuf);

myDelay(1000);
}
}

/*********************************************************************************************************
End Of File
*********************************************************************************************************/