3. UART 帧格式详解

说实话,搞 UART 这么多年,最基础也最容易出错的,就是帧格式。很多人一上来就调波特率,结果数据死活不对,回头一看——校验位配错了,或者停止位少了一位。我自己的习惯是:先把帧格式画在纸上,再动手写代码。这一节咱们就把四个基本部分掰开揉碎了讲清楚。

起始位 —— 同步的起点

空闲时,TX 线一直保持高电平(逻辑 1)。接收方怎么知道什么时候开始一帧?靠的是起始位。发送方把 TX 线拉低,保持一个位的时间。这个下降沿就是同步信号。

你想想看,如果线上有毛刺,下降沿过早或者过晚,整帧就全歪了。我在一个电机控制项目里就碰到过:电机一启动,电源干扰在 RX 线上制造了几十纳秒的毛刺,接收方误以为收到了起始位,结果后面数据全乱了。后来在接收中断里加了连续三次采样确认才稳住。

⚠️ 注意:起始位检测通常需要至少采样到低电平持续半个位周期以上,才能确认是真的起始位,不是噪声。

数据位 —— 真正的信息载体

起始位之后就是数据位。通常 5~9 位可选,最常用 8 位。注意传输顺序:LSB 先发(最低有效位最先)。比如你要发 0x55 (二进制 01010101),先发的不是最高位的 0,而是最低位的 1(LSB)。

为什么要 LSB first?历史原因——早期电传打字机就是这样的。后来所有 UART 都沿用了这个习惯。你只要记住:发送顺序是反直觉的就行。我曾经教过一个新人,他死活不理解为什么用示波器抓到的数据顺序跟程序里赋的值不一样,那就是没搞明白 LSB 优先。

发送 0x55 (01010101) 的位顺序
位序号0 (LSB)1234567 (MSB)
线电平10101010

看到没?实际线上先出现的是 1,然后 0,然后 1…… 跟二进制数值 0x55 从左到右看完全反着。

校验位 —— 错误检测的选择

数据位后面可以跟一个校验位(也可以没有)。校验位分三种:无校验、奇校验、偶校验。说白了就是让数据位加上校验位里“1”的个数凑成奇数或偶数。接收方收到后自己算一遍,对不上就报错。

我用过最多的场景是:短距离板内通信,直接关校验,省一个位的时间。但如果是工业现场、长线传输,我建议至少开偶校验——因为大部分噪声会引入奇数个错误,偶校验正好能抓住。曾经在一个 RS-485 项目里,现场有变频器干扰,我选了奇校验,结果丢帧率比偶校验高了一倍。为什么?因为干扰经常翻转两个位,奇校验反而漏检了。

校验模式对数据“10101010”(4个1)的影响
模式计算规则校验位值
无校验不发送校验位—
偶校验1的个数加校验位应为偶数0 (4个1已经是偶数)
奇校验1的个数加校验位应为奇数1 (4+1=5,奇数)

停止位 —— 帧结束的标志

校验位(如果有)之后,发送方把 TX 线拉高,保持 1 位、1.5 位或 2 位的时间。这就是停止位。它在告诉接收方:这一帧完事了,准备下一帧吧。

为什么要有不同长度?早期机械 UART 处理速度慢,需要更长的停止位让接收器复位。现在虽然芯片快多了,但两线异步通信中,停止位还承担着“帧间隔”的角色。如果你数据量不大,我建议用 1 位停止位,节省开销;如果波特率很高(比如 115200 以上),或者你要连接多个从机,可以考虑 2 位停止位,给接收方更多处理时间。

💡 小技巧:实际调试时,如果遇到“帧错误”中断频繁触发,先检查停止位设置是否匹配。我曾遇到过发送端是 1 位停止,接收端设成了 2 位,结果每帧最后一位都被当成毛刺——怎么调波特率都没用。

一张图说清帧结构

下面这个 SVG 把一帧完整的 UART 数据画出来了。从左到右看,你会发现其实就五个部分:空闲→起始→数据(LSB→MSB)→校验(可选)→停止→回到空闲。

UART 帧结构(一帧) 空闲位 高电平 起始位 1位低 Bit0 LSB Bit1 Bit2 ... Bit7 MSB 校验位 可选 停止位 1/1.5/2位高 空闲位 高电平 帧格式关键说明 ① 空闲位数量不限,通常至少 1 位高电平 ② 数据位 LSB first,8 位数据中 Bit0 最先发送 ③ 校验位可选,奇偶校验仅能检测奇数个错误 ④ 停止位=1 位最常用,高波特率建议 2 位

帧格式参数总结

如果要用一句话概括:一帧 = 1 位起始 + 5~9 位数据 + 0/1 位校验 + 1~2 位停止。所有参数必须收发双方完全一致,否则就是“鸡同鸭讲”。

字段长度电平作用
起始位1 bit低(逻辑0)提供帧同步下降沿
数据位5~9 bitLSB first传输有效负载
校验位0 或 1 bit奇/偶计算结果简单错误检测
停止位1 / 1.5 / 2 bit高(逻辑1)帧结束并准备下一帧
📌 核心习惯:调试 UART 时,第一个检查点就是帧格式配置。先用示波器看一帧的实际波形,数一数起始位、数据位、停止位的个数和电平,跟程序配置对比。这比翻代码快得多。