3. UART数据帧结构:起始位、数据位、校验位、停止位详解
UART通信说白了就是按“帧”来传数据。每一帧就像一封信,有固定的格式:起始位、数据位、校验位、停止位。我刚开始学的时候总觉得这些位很抽象,直到在项目里用逻辑分析仪抓波形,才真正看明白它们是怎么配合的。
咱们先看一张完整的帧结构图,心里有个整体印象:
3.1 起始位——通信的“发令枪”
起始位是UART帧的起点。它的作用很简单:告诉接收方“我要开始发数据了”。
具体怎么做的?发送方把TX线从空闲的高电平拉低,持续一个位时间。接收方检测到这个下降沿,就知道数据来了。
起始位核心特征:
- 长度:固定1位
- 电平:逻辑0(低电平)
- 作用:同步接收方时钟,提供采样基准
- 检测方式:下降沿触发
我在一个项目中遇到过接收端时钟漂移的问题。当时波特率设的是115200,但接收端的晶振精度不够,导致采样点偏移。后来我加了起始位重同步机制,每次检测到下降沿都重新校准采样时钟,问题就解决了。
实战技巧:接收端检测起始位时,建议在下降沿后的1/2位时间处采样一次确认。这样可以避免毛刺误触发。我习惯在驱动里加一个“去抖”逻辑,连续采样两次低电平才确认起始位有效。
3.2 数据位——真正的“干货”
数据位就是你要传的实际数据。UART支持5到9位数据位,最常用的是8位。为什么?因为一个字节正好8位,方便和内存、寄存器对接。
数据位的发送顺序是LSB(最低有效位)在前,MSB(最高有效位)在后。举个例子,你要发送0x55(二进制01010101),发送顺序是:1→0→1→0→1→0→1→0。
| 数据位配置 | 常见场景 | 说明 |
|---|---|---|
| 5位 | 老式电传机 | 基本淘汰,很少用 |
| 6位 | 某些ASCII设备 | 仅传部分字符集 |
| 7位 | 纯ASCII通信 | 高位不用,节省带宽 |
| 8位 | 绝大多数场景 | 标准字节传输,推荐使用 |
| 9位 | 多机通信/地址帧 | 第9位做地址/数据标志 |
注意:发送方和接收方的数据位长度必须一致。我曾经调试过一个设备,发送端配了8位数据,接收端配了7位,结果收到的数据全是乱的。用示波器一看才发现是数据位长度不匹配。
3.3 校验位——数据的“体检医生”
校验位用来检测数据传输过程中有没有出错。UART支持三种校验模式:无校验、奇校验、偶校验。
校验位的计算规则很简单:
- 偶校验:数据位中1的个数 + 校验位 = 偶数
- 奇校验:数据位中1的个数 + 校验位 = 奇数
举个例子,数据0x55(二进制01010101)有4个1:
- 偶校验:校验位=0(4个1已经是偶数)
- 奇校验:校验位=1(需要凑成奇数个1)
| 校验模式 | 校验位值 | 检测能力 | 适用场景 |
|---|---|---|---|
| 无校验(N) | 无 | 无 | 短距离、高可靠性链路 |
| 奇校验(O) | 使总1数为奇数 | 检测奇数位错误 | 对数据完整性要求高 |
| 偶校验(E) | 使总1数为偶数 | 检测奇数位错误 | 工业现场总线常用 |
我的经验:校验位只能检测奇数个位的翻转错误。如果两个位同时翻转(比如00变成11),校验位是检测不出来的。所以对数据完整性要求极高的场景,建议在应用层再加CRC校验。
3.4 停止位——帧的“句号”
停止位标志一帧数据的结束。发送方把TX线拉回高电平,持续1位、1.5位或2位的时间。
停止位的作用有两个:
- 帧间隔:给接收方时间处理收到的数据
- 同步恢复:让总线回到空闲状态,准备接收下一帧
| 停止位长度 | 特点 | 推荐场景 |
|---|---|---|
| 1位 | 标准配置,效率最高 | 大多数通用场景 |
| 1.5位 | 仅用于5位数据位 | 老式设备兼容 |
| 2位 | 容错性好,效率低 | 噪声环境、低速设备 |
避坑指南:我曾经在一条长距离(约50米)的RS232链路上遇到过停止位过短导致帧错位的问题。当时环境干扰大,1位停止位不够稳定。换成2位停止位后,通信就正常了。如果你的通信环境噪声大,不妨试试2位停止位。
3.5 帧格式速查表
实际项目中,帧格式通常写成类似“8N1”这样的简写。我来解释一下:
| 简写 | 数据位 | 校验位 | 停止位 | 总位数 |
|---|---|---|---|---|
| 8N1 | 8 | 无 | 1 | 10 |
| 8E1 | 8 | 偶校验 | 1 | 11 |
| 8O1 | 8 | 奇校验 | 1 | 11 |
| 7E2 | 7 | 偶校验 | 2 | 11 |
| 9N1 | 9 | 无 | 1 | 11 |
你想想看,8N1是最常见的配置。为什么?因为它效率高——10位传8位有效数据,有效载荷80%。而且8位正好是一个字节,软件处理起来最方便。
3.6 驱动开发中的帧配置实战
在驱动里配置帧格式,其实就是设置几个寄存器。以STM32为例:
/* USART帧格式配置示例 */
USART_InitTypeDef USART_InitStructure;
/* 8位数据,无校验,1位停止位(8N1) */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 或者 8位数据,偶校验,1位停止位(8E1) */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
注意:配置校验位时,数据位长度要相应调整。比如8位数据+校验位,有些芯片内部会把数据位设为9位(8位数据+1位校验)。一定要看芯片手册确认。
嗯,到这里UART帧结构的四个部分就讲完了。起始位是发令枪,数据位是干货,校验位是体检医生,停止位是句号。理解了这些,你就能看懂UART波形图,也能正确配置驱动了。