UART 串口协议详述
UART 串口协议详述
1. 通信简介
- 通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统。
- 通信协议:制定通信的规则,通信双方按照协议规则进行数据收发。
全双工就是指通信双方能够同时进行双向通信,有两根通信线,发送线路和接收线路互不影响。
半双工就只有一条数据线。
同步就是有单独的时钟线,接收方可以在时钟信号的指引下进行采样。
异步,没有时钟线,所以需要双方约定一个采样频率,并且还需要加一些帧头帧尾等,进行采样位置的对齐。
异步时序对发送方和接收方约定的传输速率是非常严格的,时钟不能有过大的偏差,且在传输过程中,若单片机进了中断,这个时序是不能暂停。若单片机一个字节发一半被暂停了,接收方是不知道的,仍然会按照原来那个约定的速率读取,就会导致传输出错。所以异步时序的缺点就是非常依赖硬件外设的支持。所以 USART 必须要有硬件电路才能方便地使用,如果没有硬件电路的支持,那么串口是很难用软件来模拟的。
同步时序是一条时钟线来指导对方读写,由于存在的时钟线,对传输的时间要求就不高,单片机也可以随时暂停传输,去处理其他事情。因为暂停传输的同时,时钟线也暂停了,所以传输双方都可以定格在传输的时刻,可以过一段时间再来继续,不会对传输造成影响。使用同步时序可以极大地降低单片机对硬件电路的依赖,也可以很方便地用软件手动翻转电平来实现通信。
单端信号就是设备的引脚高低电平都是对 GND 的电压差,所以单端信号通信的双方必须要共地,就是把 GND 接在一起。
差分信号是靠两个差分引脚的电压差来传输信号的。在通信时,可以不需要 GND。不过 USB 协议里有些地方需要单端信号,所以有时也是需要共地的。使用差分信号可以极大地提高抗干扰特性,所以差分信号一般传输速度和距离会比较快和远。
2. 串口通信
- 串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
- 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。
3. 硬件电路
- 简单双向串口通信有两根通信线(发送端TX和接收端RX);
- TX与RX要交叉连接;
- 当只需单向的数据传输时,可以只接一根通信线;
- 当电平标准不一致时,需要加电平转换芯片;
TX 和 RX 是单端信号,它们的高低电平都是相对于 GND 的。所以严格来说,GND 也算是通信线。串口通信,TX、RX 和 GND 是必须要接的,如果两个设备都有独立供电,那两个设备的 VCC 就不需要相连;但如果一个设备有独立供电,一个没有,就需要通过 VCC 相连,给未供电的设备供电,但是要符合该设备的供电要求。
从控制器里直接出来的电平一般都是 TTL 电平,相同的电平才能互相通信。不同的电平信号,需要加一个电平转换芯片,转接一下。
4. 电平标准
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系。
串口常用的电平标准有如下三种:
- TTL电平:+3.3V或+5V表示1,0V表示0;
- RS232电平:-3 ~ -15V表示1,+3 ~ +15V表示0;
- RS485电平:两线压差+2 ~ +6V表示1,-2 ~ -6V表示0(差分信号);通信距离可以达到上千米,上面两种最长只能传几十米。
5. UART 的软件部分
5.1 串口参数及时序
- 波特率:串口通信的速率;串口采用的是异步通信,所以需要双方约定一个通信速率。波特率是每秒传输码元的个数,单位是码元/s,或者直接叫波特(Baud)。另外还有一个速率表示叫比特率(每秒传输的比特数),单位是bit/s,或者叫bps。在二进制调制情况下,一个码元就是一个bit,此时波特率 = 比特率,如果是其他进制就不相等了。
- 起始位:标志一个数据帧的开始,固定为低电平;
- 数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行;
- 校验位:用于数据验证,根据数据位计算得来;
- 停止位:用于数据帧间隔,固定为高电平;
下图表示一个字节发送的时序:
UART 的空闲状态(没有数据传输的时候)是高电平,引脚必须要置高电平,作为空闲状态。在开始数据传输时,必须发送一个起始位,是低电平。打破空闲状态的高电平,产生一个下降沿。在一个字节数据发送完成后,必须要有一个停止位,作用是用于数据帧间隔,为下一个起始位做准备,固定位高电平。
校验可以选择三种方式,无校验、奇校验和偶校验。
上图使用的是9600波特率,0x55是 01010101,UART采用的是低位先行,所以传输时是按照 10101010 来发送的。S 表示起始位,P 表示停止位。UART的硬件外设可以自动根据字节数据翻转高低电平,当然,也可以软件模拟产生这样的波形,也就是按照波特率的速度定一个定时器,时间到之后,按照数据帧要求,把 GPIO 置高低电平。读取高低电平也可以由 UART 外设自动来完成。
总结一下就是,TX 引脚输出定时翻转的高低电平,RX 引脚定时读取引脚的高低电平。每个字节的数据加上起始位、停止位、可选的校验位,打包成数据帧,依次输出在 TX 引脚,另一端 RX 引脚依次接收,这样就完成了字节数据的传递。
6. USART 简介
- USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器;
- USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里;
- 自带波特率发生器,最高达4.5Mbits/s;波特率发送器就是用来配置波特率的,其实就是一个分频器,比如 APB2 总线给个 72 MHz的频率,然后波特率发生器进行一个分频,得到我们想要的波特率时钟,最后在这个时钟下,进行收发,就是我们指定的通信波特率。
- 可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2);
- 可选校验位(无校验/奇校验/偶校验);
- 支持同步模式、硬件流控制、DMA、智能卡、IrDA(用于红外通信,有一个红外发光管和红外接收管,靠闪烁红外光通信)、LIN;
STM32F103C8T6 USART资源: USART1、 USART2、 USART3;
注: UART 就是通用异步收发器,一般串口很少使用同步功能,所以 USART 和 UART 使用起来,也没有什么区别,USART 只是多了个时钟输出而已,且只支持时钟输出,不支持时钟输入,所以 USART 更多地是为了兼容别的协议或者特殊用途而设计的,并不支持两个 USART 之间进行同步通信。
硬件流控制,是指,比如 A 设备有个 TX 向 B 设备的 RX 发送数据,A 设备一直在发,发的太快了,B 处理不过来,如果没有硬件流控制,那 B 就只能抛弃新数据或者覆盖原数据了。如果有硬件流控制,在硬件电路上,会多出一根线,如果 B 没准备好接收,就置高电平,如果准备好了,就置低电平,A 接收到了 B 反馈的准备信号,就只会在 B 准备好的时候才发数据。硬件流控制可以防止因为 B 处理慢而导致数据丢失的问题。
7. USART 框图
- 引脚介绍:上面 TX 和 RX 是 USART 的发送和接收引脚,SW_RX、IRDA_OUT 和 IRDA_IN 是智能卡和IrDA通信的引脚。
- 数据寄存器:发送数据寄存器(TDR)和接收数据寄存器(RDR)这两个寄存器占用同一个地址,在程序上只表现为一个寄存器,就是数据寄存器(DR)。但实际硬件中是两个寄存器,TDR 是只写的,RDR 是只读的。当执行写操作时,数据就写到 TDR;当执行读操作时,数据就从 RDR 读出来。发送移位寄存器的作用就是把一个字节的数据一位一位地移出去,正好对应串口协议的波形的数据位。
- 发送数据寄存器和发送移位寄存器相互配合工作:比如在某时刻给 TDR 写入了 0x55 这个数据,此时硬件检测到你写入数据了,它就会检查,当前移位寄存器是不是有数据正在移位,如果没有,这个数据就会全部移动到发送移位寄存器中准备发送,当数据从 TDR 移动到移位寄存器时,会置一个标志位,叫 TXE(TX Empty),发送寄存器空,我们检查这个标志位,如果置 1 了, 我们就可以在 TDR 写入下一个数据了。注意,当 TXE 置 1 时,数据其实还没有发送出去,只要数据从 TDR 转移到发送移位寄存器,TXE就会被置 1,就可以写入新数据了。然后发送移位寄存器就会在下面的发送器控制的驱动下,向右移位,然后一位一位地把数据输出到 TX 引脚,向右移位正好和串口协议规定的低位先行是一致的。当数据移位完成后,新的数据就会再次自动地从 TDR 转移到发送移位寄存器里来;如果当前移位寄存器移位还没有完成,TDR 的数据就会进行等待,一旦移位完成,就会立刻转移进来。有了 TDR 和移位寄存器的双重缓存,可以保证连续发送数据的时候,数据帧之间不会有空闲,提高了工作效率。简单来说,就是数据一旦从 TDR 转移到移位寄存器了,不管有没有移位寄存器有没有移位完成,就立刻把下一个数据放在 TDR 等着。一旦移完了,新的数据就会立刻跟上。
- 接收数据寄存器和接收移位寄存器相互配合工作:数据从 RX 引脚发送到接收移位寄存器,在 接收器控制 的驱动下,接收移位寄存器会一位一位地读取 RX 电平,先放在最高位,然后向右移,移位八次之后就可以接收一个字节。这一个字节的数据就会整体地转移到接收数据寄存器 RDR 里来,在转移的过程中也会置一个标志位,叫 RXNE(RX Not Empty),接收数据寄存器非空,当我们检测到 RXNE 置 1 之后,就可以把数据读走。同样,这里也是两个寄存器进行缓存,当接收移位寄存器把一个字节的数据转移到 RDR 之后,就可以直接移位接收下一帧数据了。
上面就是 USART 工作的大致流程了,当然,发送数据时还需要加上帧头帧尾,接收时还需要剔除帧头帧尾。这些操作,内部有电路会自动执行。
发送器控制:用来控制发送移位寄存器工作的。
接收器控制:用来控制接收移位寄存器的工作。
硬件数据流控:有两个引脚,nRTS(Request To Send)是请求发送,是输出脚,也就是告诉别人当前能不能接收;nCTS(Clear To Send)是清除发送,是输入脚,也就是用于接收别人的 nRTS 信号。这里前面加个 n 是代表低电平有效。
两个具备流控的 USART 通过硬件流控进行数据交互时,当一方可以接收时,RTS 就会置低电平,请求对方发送,对方的 CTS 接收到之后,就可以一直发,当数据处理不过来时,RTS 就会置高电平,对方 CTS 接收到之后,就会暂停发送。直到 RDR 中的数据被读走了,才会重新将 nRTS置低电平,对方才会继续发送。SCLK 和 SCLK 控制:这部分电路用于产生同步的时钟信号,它是配合发送移位寄存器输出的,发送移位寄存器每移位一次,同步时钟电平就会跳变一个周期,时钟告诉对方,我移出去一位数据了,你看要不要让我这个时钟信号来指导你接收一下?当然,这个时钟只支持输出,不支持输入,所以两个 USART 之间不能实现同步的串口通信。那这个时钟信号有什么用呢?第一个用途就是兼容别的协议,比如串口加上时钟之后,就跟 SPI 协议很像,所以有了时钟输出的串口,就可以兼容 SPI。第二个用途就可以做自适应波特率,比如接收设备不确定发送设备给的什么波特率,那就可以测量一下这个时钟的周期,然后再计算得到波特率。
唤醒单位:作用是实现串口挂载多设备。之前说串口一般是点对点的通信,只支持两个设备互相通信,想发数据直接发就行,而多设备,在一条总线上,可以接多个从设备,每个设备分配一个地址,想跟某个设备通信就先进行寻址,确定通信对象,再进行数据收发。所以这个唤醒单元就可以用来实现多设备的功能,可以给串口分配一个地址,放在 USART地址 中。当收到该设备地址是,就唤醒开始工作。
USART 中断控制:配置中断是否可以通向NVIC;中断申请位就是状态寄存器 SR 中的各种标志位。
USART_BRR :波特率发生器。
以上介绍可以总结出一个基本结构:
最左边是波特率发生器,用于产生约定的通信速率。时钟来源经过波特率发生器分频后,产生的时钟通向发生控制器和接受控制器,发送控制器和接收控制器,用来控制发送移位和接收移位。由发送数据寄存器和发送移位寄存器这两个寄存器的配合,将数据一位一位地移出去,通过 GPIO 的复用输出,输出到 TX 引脚,产生串口协议规定的波形,当数据由数据寄存器转到移位寄存器时,会置一个 TEX 的标志位,判断这个标志位就可以知道是不是可以写下一个数据。接收的过程也是类似的,RX 引脚的波形,通过 GPIO 输入,在接收控制器的控制下,一位一位地移入接收移位寄存器,移完一帧数据后,数据就会统一转运到接收数据寄存器,在转移的同时,置一个 RXNE 标志位,检测这个标志位就可以知道是否收到数据了,同时这个标志位也可以申请中断,进入中断处理函数,快速地读取和保存数据。右边实际上有四个寄存器,但在软件层面上只有一个 DR 寄存器可以供我们读写。
8. 数据帧
这个图是在程序中配置8位字长和9位字长的波形对比,这里的字长就是前面说的数据位长度,包含校验位的。空闲高电平,然后起始位低电平,再根据写入的数据置 1 或者 0,依次发送位 0 到位 8,最后停止位 1,数据帧结束。最后一个数据都是可能的奇偶校验位,通过配置寄存器就可以配置成奇校验、偶校验或者无校验。一般如果是9位字长,会选择8个数据位+1个奇偶校验位;如果是8位字长的话就会选择8个位用来做数据位。
时钟,可以看到在每个数据位的中间都有一个时钟上升沿,时钟的频率和数据速率是一样,接收端可以在时钟上升沿进行采样,这样就可以精准定位每一位数据。
