UART协议简介
UART(Universal Asynchronous Receiver/Transmitter),通用异步收发器。UART在一开始发明出来的时候用作电脑硬件的一部分,主要作用是将数据通过串行通信和并行通信间作传输转换,后来UART作为微处理器的外设应用非常广泛,同时在UART上追加同步的时钟信号,称为USART(Universal Synchronous Asynchronous Receiver Transmitter)。UART它包括RS232、RS449、RS422和RS485等接口标准规范和总线规范,是异步串行通信口的总称。可以理解为UART通信协议是软件上的通信网络中的数据链路层,表示数据传输协议。而RS232、RS485是通信接口的电器特性和连接特性、机械特性等硬件上的范畴,属于物理层
UART协议特点
UART通信可以是半双工、全双工,在空闲状态(没有数据传输期间)保持高电平,表示传输线路正常。每一个字符为一帧数据,以逻辑低电平为开始比特,然后是数据比特,可选的奇偶校验比特,最后是一个或多个停止比特(逻辑高电平)。大部分的应用都是先传输低位数据比特
UART协议应用
UART应用是非常广泛的,在早期的电脑中都会带一个RS232的接口,后来变为USB口。目前市场上绝大部分的微处理器(MCU)都带有UART硬件,可用于通信或应用程序下载。需要注意的是MCU上的UART是TTL电平
UART协议时序
UART时序包含:起始位、数据位、奇偶校验位(可选)、停止位。在无数据传输的期间(空闲状态下),数据线保持高电平;通信过程中,先发送1bit起始位(低电平),接着发送数据位(数据位多少由用户配置决定,通常为8bit,也就是1Byte),发送完数据位后接着发送1bit奇偶校验位1bit(根据通信决定可选择不发送,一般都配置为无奇偶校验),最后发送停止位(通常位1bit)。数据位选择、奇偶校验位选择和停止位选择如下表
起始位 | 数据位 | 奇偶校验位 | 停止位 |
---|---|---|---|
1(bit) | 5、6、7、8(bit) | 奇校验或偶校验(1bit)、无 | 1、1.5、2(bit) |
注:奇偶校验位-当配置为奇校验时,数据位中数据‘1’的个数+奇偶校验位 = 奇数;偶校验同理
数据帧结构
UART通信配置:起始位1bit+数据位8bit+无奇偶校验+停止位1bit。通信数据帧如下图:
通信速率
UART的通信速率是以波特率位单位衡量的,UART一般通信速率使用9600、115200。需要特别说明的是:UART通信中,比如波特率是9600bps,但是不意味着是9600bit/s,因为使用的波特率单位bps与平常的比特率单位bit/s是不一样的,波特率指的是每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示,比特率指的是每秒传送的比特(bit)数
UART通信中,1个bit表现为高电平或低电平,在这种情况下是9600bps = 9600bit的,一帧数据 = 起始位1bit+数据位8bit+无奇偶校验+停止位1bit = 10bit,9600bps的实际有效数据就是9600/10 = 960Byte
注:当一个一个码元符号表示两个bit时,比特率 = 波特率 x 2
UART协议在MCU中的应用
目前市场上大部分的MCU都带有UART外设,以STM32F103RCT6型号为例,该型号MCU带有数个USART(Universal Synchronous Asynchronous Receiver Transmitter),比UART多了一个时钟同步信号线(该功能比较少用),还有有CTS与RTS信号引脚,可用于流控[^有软件和硬件两种]。UART大量应用在数据收发的通信场合,因此一个好的算法处理收发过程的数据是很必要的,下面介绍一个常用的队列结构在UART收发上的应用
下面例子使用的环境如下:
- Windows10
- ARM KEIL MDK V5.25
- Thermal Printer MainBoard V1.0(STM32F103RC开发板也可以直接使用)
- DAPLink(或其他支持SWD下载方式的下载器,如ST-LINK)
- 友善串口调试助手(支持串口调试的终端都可以)
注:如果选择非DAPLink下载器(DAPLink自带虚拟串口),则还需要一个USB转TTL来连接PC与开发板
UART基础配置
例程使用STM32F103RCT6中的USART1口,基本配置为(起始位时通讯中必须存在的):
- 波特率115200
- 8位数据位
- 一位停止位
- 无奇偶校验
- 无流控
- 全双工模式
- 开启接收中断
代码实现如下:
1 | /** |
环形队列应用
USART配置完毕后,开始实现队列结构,队列结构由五部分组成:
1 | typedef struct Circular_Queue_Str |
在实际使用队列前,需要初始化队列,收发数据过程也伴随着不断入队和出队过程,相关队列函数实现如下:
1 | /** |
相关队列函数实现后,开始初始化队列。初始化队列需要由一个数据缓冲区,以及缓冲区大小和一个队列结构体三个参数,可以定义在USART配置的文件中:
1 |
|
然后对USART和QUEUE进行初始化:
1 | /** |
当接收到数据时,会引发USART的接收中断,在中断中把数据入队:
1 | /** |
最后在主函数中判断队列是否存在数据,存在数据则发送出去:
1 | /** |
效果如下所示: