4、UART协议深度解析:帧格式、波特率误差、校验与流控

UART,说白了就是串口。搞嵌入式的人,没人敢说自己没碰过它。但说实话,很多人用了好几年,遇到干扰时照样抓瞎。今天我就把这层窗户纸捅破,从帧格式讲到流控,把那些容易踩坑的地方都拎出来说说。

4.1 UART帧格式:一个字节怎么飞过去的?

UART是异步通信,没有时钟线。那收发双方怎么对齐?靠的是帧格式里的起始位和停止位。

一个标准的UART帧长这样:

空闲(高电平) | 起始位(低) | 数据位(LSB→MSB) | 奇偶校验位(可选) | 停止位(高) | 空闲(高)

我习惯把帧拆成几个关键部分:

  • 起始位:1位,固定为低电平。告诉接收方“我要发数据了”。
  • 数据位:5~9位,常用8位。注意发送顺序是LSB在前,MSB在后。
  • 奇偶校验位:0或1位,可选。后面细讲。
  • 停止位:1、1.5或2位,固定为高电平。给接收方时间处理刚收到的字节。

关键点:起始位的下降沿是双方的时间基准。接收方从这个下降沿开始,按约定的波特率采样后续数据位。如果这个沿被干扰了,整帧就废了。

我在项目中遇到过一件事:某款传感器在强电磁环境下频繁丢字节。后来用示波器一看,起始位前面多了个毛刺,接收方误判了下降沿位置。解决办法是在软件里加了个去毛刺滤波,采样点避开边沿附近。

4.2 波特率误差分析:差多少会翻车?

波特率就是每秒传输的符号数。UART没有时钟线,全靠双方约定速率。但晶振有误差,分频有舍入,两边不可能完全一样。

那误差容忍度是多少?

数据位长度 理论最大误差(%) 工程建议上限(%)
8位 + 无校验 ±4.5 ±2.0
8位 + 奇偶校验 ±4.0 ±1.5
9位 + 奇偶校验 ±3.5 ±1.0

为什么会这样?因为误差是累积的。起始位对齐后,每采一位,误差就多一分。采到最后一位停止位时,误差最大。如果采样点漂出了位中间区域,就会采错。

我的经验:设计时尽量选整数分频的波特率。比如用11.0592MHz晶振配9600bps,误差几乎为零。用12MHz晶振配9600bps,误差就有0.16%,虽然能用,但心里不踏实。

我曾经在一个项目里,两边晶振分别是16MHz和8MHz,都配115200bps。结果16MHz那边误差0.16%,8MHz那边误差0.32%,加起来0.48%,还在容忍范围内。但如果两边都用12MHz配115200,误差直接飙到0.8%,高温下就翻车了。

4.3 奇偶校验:能防住什么?防不住什么?

奇偶校验分两种:

  • 奇校验:数据位+校验位里,1的个数为奇数。
  • 偶校验:数据位+校验位里,1的个数为偶数。

接收方收到数据后,重新计算1的个数,跟校验位比对。不一致就报错。

但这里有个坑:奇偶校验只能检测奇数个比特翻转。如果两个比特同时翻转,校验结果不变,错误就漏过去了。

注意:在强干扰环境下,比如电机驱动附近,经常出现连续多位翻转。这时候奇偶校验形同虚设。我建议配合校验和或CRC使用,别单靠奇偶校验保命。

我记得有一次调试一个工业控制器,UART通信偶尔出现乱码。打开奇偶校验后,错误帧能被检测到了,但重传率高达15%。后来发现是电源纹波太大,导致接收器采样抖动。加了滤波电容后,重传率降到0.1%以下。

4.4 流控制(RTS/CTS):什么时候必须用?

流控制解决的是“发送方太快,接收方来不及处理”的问题。UART的流控制分两种:

  • 硬件流控(RTS/CTS):用两根专用引脚。接收方准备好时,拉高CTS;缓冲区快满时,拉低CTS让发送方暂停。
  • 软件流控(XON/XOFF):在数据线上发特殊字符。接收方发0x13(XOFF)让发送方暂停,发0x11(XON)让发送方继续。

我个人强烈推荐硬件流控,原因有三:

  1. 软件流控的XON/XOFF字符不能出现在数据里,否则会误触发。虽然可以用转义,但麻烦。
  2. 软件流控在干扰环境下,控制字符本身可能被篡改,导致死锁。
  3. 硬件流控的响应速度更快,适合高速通信。

什么时候必须用流控? 当发送方是连续数据流(比如GPS模块每秒输出10条NMEA语句),而接收方需要处理中断、写日志、刷屏幕时。没有流控,缓冲区一满,数据就丢了。

我曾经在一个项目里,用STM32的UART接收激光雷达数据,波特率921600。接收方每帧还要做坐标变换,处理时间不稳定。不加流控时,每10秒丢一帧。加了RTS/CTS后,一帧都不丢。

4.5 UART帧结构与抗干扰要点

下面这张图把UART帧的完整结构和抗干扰的关键点串起来了:

UART帧结构与抗干扰要点 空闲(高) 起始位(低) 数据位(8位) 校验位(可选) 停止位(高) 空闲(高) 抗干扰关键点 起始位下降沿去毛刺 采样点避开边沿 波特率误差控制在±1.5%以内 优先选整数分频晶振 奇偶校验+CRC双重保险 强干扰下别单靠奇偶 硬件流控RTS/CTS 响应快,不依赖数据内容 电源纹波控制 纹波大→采样抖动→误码 差分UART(RS-422/485) 长距离强干扰首选 核心原则:UART抗干扰要从帧结构、时钟精度、校验机制、流控策略、物理层五个维度综合设计 单一措施无法应对复杂干扰环境,必须组合使用

4.6 避坑指南:我踩过的几个坑

最后分享几个实战教训:

  • 坑一:波特率误差在常温下没问题,高温下就翻车。晶振的频率温度系数是ppm/°C,高温下误差会变大。我建议留足余量,别卡着理论极限。
  • 坑二:RTS/CTS接线接反。RTS是发送方请求发送,CTS是接收方允许发送。接反了流控完全失效。我习惯用万用表量一下电平再确认。
  • 坑三:奇偶校验位算错了位置。有些MCU的UART外设,校验位是自动插入的,但数据位长度设置不对时,校验位位置会偏移。我建议用示波器抓一帧,数一下位宽确认。
  • 坑四:停止位用1.5位时,接收方不支持。1.5位停止位在低速场景下有用,但不是所有UART外设都支持。用之前查一下数据手册。

我的习惯:新板子调UART时,先发0x55(二进制01010101),用示波器看波形。每个数据位宽度应该一致,起始位下降沿干净,停止位高电平稳定。波形没问题了,再调软件。

UART看似简单,但干扰环境下处处是坑。把帧结构吃透,波特率算准,校验和流控配好,物理层选对,才能做出靠谱的通信系统。