|
【EEWORLD】救火车和你一起学ARM系列活动之七
[复制链接]
----串行口实验
这回我们来研究一下一个重要的片内外设串行口。我相信大家都知道口串行口吧,我就不过多介绍它了。闲话少说,我们开始。
LPC2103有两个串行口。UART0和UART1,下面我们以UART0为例,介绍串行口。
管脚连接设置
需要设置IO口连接模块PINSEL0,设成连接到UART0. 请参考活动六的介绍。
PINSEL=0x05;
串行口波特率的设置
LPC2103具有内置的波特率发生器。
我们需要设置波特率分频寄存器(共16位)。U0DLM是高8位,U0DLL是低8位。
分频值 = Fpclk/16/波特率
Fpclk:我们在活动3中介绍过。我们的晶振是11.0592经过PLL的6倍频和VPB的4分频,供给片内外设的时钟是11.0592M*6/4=16.5888MHz
我们计算9600波特率的分频值 = 16588800/16/9600 =108 =0x006c
计算结果
U0DLM=0x00;
U0DLL=0x6c;
注:设置分频寄存器时还要将U0LCR的第7位置1
其他重要寄存器介绍
U0LCR:UART0控制寄存器
UOLCR
| 功能
| 描述
| 复位值
| 1:0
| 子长度选择
| 00:5位字符长度
01:6位字符长度
10:7位字符长度
11:8位字符长度
| 0
| 2
| 停止位选择
| 0: 1个停止位
1:2个停止位(如果U0LCR[1:0]=00则为1.5)
| 0
| 3
| 奇偶使能
| 0:禁止奇偶产生和校验
1:使能奇偶产生和校验
| 0
| 5:4
| 奇偶选择
| 00:奇数
01:偶数
10:强制为1
11:强制为0
| 0
| 6
| 间隔控制
| 0:禁止间隔发送
1:使能间隔发送
当U0LCR的bit6为1时,输出引脚UART0 TxD强制为逻辑0
| 0
| 7
| 除数锁存访问位
| 0:禁止访问除数锁存寄存器
1:使能访问除数锁存寄存器
| 0
|
U0IER 中断使能寄存器 = 0x07;
U0IER
| 功能
| 描述
| 复位值
| 第0位
| RBR中断使能
| 接收到数据或接收超时。0:禁止 1:使能
| 0
| 第1位
| THRE中断使能
| 发送缓冲为空
| 0
| 第2位
| Rx线状态中断使能
|
| 0
|
U0THR 发送寄存器。把需要向外发的数据直接赋值给它。
U0RBR 接收寄存器。从这个寄存器中读取接收到的数据。
U0IIR 中断标识寄存器
U0IIR[3:0]
| 优先级
| 中断类型
| 中断源
| 中断复位
| 0110
| 最高
| Rx线状态/错误
| OE,PE,FE,或BI
| U0LSR读操作
| 0100
| 第二
| Rx数据可用
| Rx数据可用或FIFO模式下(U0FCR0=1)到达触发点
| U0RBR读或UART0 FIFO低于触发值
| 1100
| 第二
| 字符超时指示
| Rx FIFO包含至少1个字符并且在一段时间内无字符输入或移出
| U0RBR读操作
| 0010
| 第三
| THRE
| THRE 发送缓冲为空中断
| U0IIR读或写操作
| 在定时器中断函数中,需要读取此寄存器,用来区分中断的来源。
程序例子:
我们采用中断方式,来实现串行口的收发动作。周立功的书中已给介绍了查询方式的收发,我们这里不再详述。中断方式的好处是占用的CPU时间少,CPU不必“等”着串行口的数据发完,而是利用收、发产生的中断再实现数据装入和读回。
源文件main.c和subuart0.c请到 www.qm999.cn 下载
//初始化UART0 中断方式
void Init_uart0()
{
U0LCR = 0x83; //使能访问除数寄存器
U0DLM = 0x00; //115200时为6 9600时为0x006c
U0DLL = 0x6c;
U0LCR = 0x03; //禁止访问除数寄存器
U0IER = 0x03; //允许接收数据可用中断[第0位]和发送缓冲为空中断[第1位]
//以下是中断设置 设置为中断通道0
VICIntSelect = 0x00000000;
VICVectCntl0 = 0x26; //第5位置1:向量使能,[4:0]中断源序号
VICVectAddr0 = (unsigned long)&IRQ_UART_0;
VICIntEnable = 0x00000040;
PINSEL0 |= 0x00000005;
}
//以下以串行口中断方式程序
// USART Receiver buffer
#define RX_BUFFER_SIZE_0 100
unsigned char rx_buffer_0[RX_BUFFER_SIZE_0];
unsigned char rx_wr_index_0=0,rx_rd_index_0=0,rx_counter_0=0;
// USART Transmitter buffer
#define TX_BUFFER_SIZE_0 100
unsigned char tx_buffer_0[TX_BUFFER_SIZE_0];
unsigned char tx_wr_index_0=0,tx_rd_index_0=0,tx_counter_0=0;
// USART Receiver interrupt service routine
__irq __arm void IRQ_UART_0(void)
{
unsigned char data;
switch(U0IIR&0x0e)
{
//case 0x06://011:1.接收线状态(RLS)
// data = U0LSR;
// break;
case 0x04://010:2a.接收数据可用(RDA)
data = U0RBR;
rx_buffer_0[rx_wr_index_0]=data;
if (++rx_wr_index_0 == RX_BUFFER_SIZE_0) rx_wr_index_0=0;
if (++rx_counter_0 == RX_BUFFER_SIZE_0) rx_counter_0=0;
break;
//case 0x0c://110:2b.字符超时指示(CTI)
// data = U0RBR;
// break;
case 0x02://001:3.THRE中断 发送缓冲为空中断
if (tx_counter_0)
{//1次写入FIFO最多16个字节
--tx_counter_0;
U0THR = tx_buffer_0[tx_rd_index_0];
if (++tx_rd_index_0 == TX_BUFFER_SIZE_0) tx_rd_index_0=0;
}
break;
default:
break;
}
VICVectAddr = 0x00;
}
//读取一个字节
unsigned char getchar_0(void)
{
unsigned char data;
while (rx_counter_0==0);
data=rx_buffer_0[rx_rd_index_0];
if (++rx_rd_index_0 == RX_BUFFER_SIZE_0) rx_rd_index_0=0;
VICIntEnable &= 0xffffffbf;
--rx_counter_0;
VICIntEnable |= 0x00000040;
return(data);
}
//发送一个字节
void putchar_0(unsigned char data)
{
while (tx_counter_0 == TX_BUFFER_SIZE_0);
VICIntEnable &= 0xffffffbf;
if (tx_counter_0 || ((U0LSR&0x40)==0))
{
tx_buffer_0[tx_wr_index_0]=data;
if (++tx_wr_index_0 == TX_BUFFER_SIZE_0) tx_wr_index_0=0;
++tx_counter_0;
}
else
{
U0THR = data;
}
VICIntEnable |= 0x00000040;
}
//主程序 功能是将接收到的数字,加1以后回发。
int main (void)
{
。。。。。。//其他程序略
Init_uart0();
while(1)
{
if (rx_counter_0>0)
{
while(rx_counter_0>0) putchar_0(getchar_0()+1);//加1 ,回发
}
}
}
硬件原理图如下:
实验板硬件图如下所示:
正面
背面
实验效果演示:
用串口调试工具发一串数,能够看到数据加1后,回发。
可以看到实上面的实验效果。电脑发出的数字,被加1,回发了回来。
我们在这次实验中启用了新制作的USB仿真器。下面是效果图。
下一次我们准备做IIC接口实验,请大家准备一个3.3V的24WC02或兼容芯片。
|
|