UART协议简述及编程
UART原理简述
通用异步收发器简称UART(universal asynchronous receiver transmitter)。他的用途很广泛,一般常用的就是用来输出打印的信息,也可以外接各种模块,例如GPS和蓝牙等。
正是因为这种协议非常的简单可靠,所以才那么的受欢迎。它只需要三条线,TxD用来发送数据,RxD用来接收数据,以及一根接地线Gnd。UART使用双方只要使用三根线就能进行通信。
一般在发送之前,收发双方都要先约定好一定的规则:传输数据的速率(每位所占据的时间,其倒数就是波特率);数据格式(每帧包含多少位数据,包含开始位、数据位(5~8 bit)、校验位(可有可无)和停止位(1~2 bit))。
UART使用标准的TTL/CMOS逻辑电平(0~5V,0~3.3V,0~2.5V或0~1.8V)来表示数据,1表示高电平,0表示低电平。为了提高抗干扰能力、提高传输的距离,通常也会TTL/CMOS逻辑电平转换为RS-232逻辑电平,3~12V表示0,-3~-12V表示1。
下面以传输字符‘A’的过程来了解一下UART协议传输数据的流程:
(1)一开始保持高电平(芯片内部使用上拉电阻),等待数据传输开始发出的开始位
(2)当要开始传输数据后,TxD数据线的由1变为0,并保持一位的时间,以便接收方能检测到,并等待1.5位的时间后开始接收数据
(3)之后便是传输的数据(上图是7位数据)
(4)如果有校验位的话,数据位之后便是1位的校验位。不过现在一般不使用了
(5)最后就是拉高电平,保持1、1.5或者2位的停止位,表示一帧的结束
S3C2440芯片的UART
下面是我使用的S3C2440的UART流程框图:
发送数据的时候,先把数据放入64字节的FIFO寄存器(如果开启了FIFO模式),然后才会把数据放到发送移位器,串行的发送给接收方。类似的,接收数据的时候是先放到接收移位器,然后放到FIFO寄存器,CPU就是从FIFO寄存器取数据的。
至于什么时候能发送数据,什么时候能从FIFO寄存器中取数据呢?芯片提供了状态寄存器UTRSTATn,后面编程我们将会看到怎么使用这个寄存器。
S3C2440的UART模块初始化
虽然上面对于UART协议的描述有很多,但是真正初始化UART,只是简单设置一些寄存器而已,下面我们还是以JZ2440芯片为例。
(1)配置GPIO引脚
上面是芯片原理图中对于UART所使用的GPIO。芯片有3个串口,一般用串口0用于调试,其他两个有它用,也就是配置TXD0/GPH2和RXD0/GPH3为10就可以了。
因为空闲状态时,TXD0和RXD0是高电平,所以我们要拉高相关GPIO,也就是把GPH[2]和GPH[3]配置为0
(2)设置波特率
芯片手册已经给出了计算波特率的公式,如上所示。我们一般使用115200的波特率,所以相关寄存器的值就可以这么得到:
UART clock = PCLK = 50M (这个是我已经配置好的时钟频率,根据自己的实际情况设置)
UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
可以直接把值26写入到寄存器UBRDIV0
(3)设置UART控制寄存器
这个控制寄存器UCONn一共16位,不过我们简单的设置前4位就能满足我们需求了,都设置为中断模式,所以设置UCON0=0x00000005
(4)设置数据格式
我这里设置的数据格式为:8N1 -> 8个数据位,没有校验位,1个停止位。
所以寄存器的值为: ULCON0 = 00000011 = 0x00000003
初始化UART部分的代码:
void uart0_init()
{
/*设置引脚用于串口*/
/*GPH2,3 用于TxD0, RxD0*/
GPHCON &= ~( (3<<4) | (3<<6) );
GPHCON |= ( (2<<4) | ((2<<6)) );
GPHUP &= ~( (1<<2) | (1<<3) );
/*设置波特率*/
/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1 */
/*
UART clock = PCLK = 50M
UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
*/
UCON0 = 0x00000005; //PCLK, 终端或者查询模式
UBRDIV0 = 26;
/*设置数据格式*/
ULCON0 = 0x00000003; //8N1: 8个数据位,没有校验位,1个停止位
}
(6)发送和接收数据
上面我们已经提到过,可以根据UTRSTAT0寄存器进行判断,什么时候可以写数据到发送buffer,什么时候可以从接收buffer中取数据。
上图翻译成中文就是:
所以当我们想发送数据时,可以循环等待UTRSTAT0[2]是否为1,如果为1证明buffer中的数据都发送完了,我们可以继续往buffer中写数据。
类似的,我们想读取数据时,可以循环等待UTRSTAT0[0]是否为1,如果为1,证明已经接收到数据了,我们就可以到相应的寄存器读取数据。
写数据的寄存器:
读数据寄存器:
我们这里使用小端模式。
收发数据的示例代码如下:
int putchar(int c)
{
/*UTXH0*/
while ( !(UTRSTAT0 & (1<<2)) ); //为0代表上次的数据还没发送
UTXH0 = (unsigned char)c;
}
int getchar(void)
{
/*read URXH0*/
while ( !(UTRSTAT0 & (1<<0)) );
return URXH0;
}
int puts(const char *s) //发送字符串
{
while(*s)
{
putchar(*s);
s++;
}
}
上一篇: linux系统下如何部署php项目环境
下一篇: UART串口简介
推荐阅读