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位的校验位。不过现在一般不使用了

扫描二维码关注公众号,回复: 3667760 查看本文章

(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++;
	}
}

猜你喜欢

转载自blog.csdn.net/lee_jimmy/article/details/81607472