3、UART协议原理:UART帧格式(起始位、数据位、校验位、停止位)、波特率定义与计算
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是单片机系统中最基础、最常用的串行通信协议之一。与SPI、I2C等同步通信协议不同,UART在传输数据时不依赖时钟线,而是通过收发双方预先约定好的波特率(Baud Rate)以及帧格式(Frame Format)来实现数据的可靠传输。理解UART帧的每一位定义、波特率的本质以及误差容限,是编写稳定串口驱动、排查通信故障的基石。本章将深入剖析UART协议的核心原理,从帧格式的每一位说起,再到波特率的计算与误差分析,并结合实际工程案例进行拆解。
上图展示了UART通信的基本链路与帧结构。发送端MCU通过TX引脚将并行数据转换为串行位流,经过物理线路传输,接收端MCU通过RX引脚接收并还原数据。帧格式中,每一位都有其特定的电平与时间含义,下面我们将逐一深入解析。
3.1 UART帧格式:每一位的职责与设计
UART帧是数据传输的基本单位,其格式定义了线路空闲状态、数据同步方式以及数据完整性校验机制。一个标准的UART帧由起始位(Start Bit)、数据位(Data Bits)、校验位(Parity Bit,可选)和停止位(Stop Bit)组成。理解每一位的作用,是配置串口参数(如8N1、8E1等)的前提。
3.1.1 起始位:通信的“发令枪”
UART是异步协议,线上没有独立的时钟信号。当线路处于空闲状态时,TX引脚保持为高电平(逻辑1)。发送端要开始传输数据时,首先将线路拉低,并保持一个位时间(Bit Time),这个低电平脉冲就是起始位(逻辑0)。
- 核心作用:接收端通过检测线路上的下降沿(从高到低跳变)来识别起始位,从而与发送端实现帧同步。起始位是每一位数据采样的时间基准点。
- 工程细节:接收端在检测到下降沿后,并不会立即采样数据位,而是会等待半个位时间(即1/2 Bit Time)后,在起始位的中心点再次采样,确认电平确实为低。这一“二次确认”机制有效防止了线路上的毛刺噪声引起的误触发。
3.1.2 数据位:传输的核心内容
起始位之后便是数据位,这是实际要传输的信息。数据位的数量通常为5、6、7或8位,其中8位数据(一个字节)最为常用。数据位的传输顺序为从最低有效位(LSB)开始,到最高有效位(MSB)结束。
- LSB First:例如要发送十六进制数
0x53(二进制0101 0011),则线上先发送最低位1,然后是1、0、0、1、0、1,最后发送最高位0。 - 位时间:每一位的持续时间由波特率决定。例如波特率为9600bps时,每位持续约104.17微秒(μs)。
3.1.3 校验位:数据完整性的“守护者”
校验位用于检测数据在传输过程中是否发生错误。它是在数据位之后、停止位之前发送的额外一位。校验方式主要有三种:无校验(None)、奇校验(Odd)和偶校验(Even)。
| 校验方式 | 计算规则 | 示例(数据位 0x53 = 0101 0011) |
|---|---|---|
| 无校验 (N) | 不发送校验位,帧长度缩短1位 | 无校验位,直接跟停止位 |
| 偶校验 (E) | 数据位中“1”的个数 + 校验位“1”的个数 = 偶数 | 数据位中1的个数为4(偶数),校验位为0 |
| 奇校验 (O) | 数据位中“1”的个数 + 校验位“1”的个数 = 奇数 | 数据位中1的个数为4(偶数),校验位为1 |
判断方法:接收端在收到数据位后,会自行计算校验位并与接收到的校验位进行比较。若不一致,则置位错误标志(如USART的PE标志),通知软件处理。
3.1.4 停止位:帧结束的“休止符”
停止位标志着帧的结束,它表现为高电平(逻辑1),持续时间为1位、1.5位或2位(根据配置)。停止位不仅用于分隔相邻的两帧,更重要的是,它保证了下一帧起始位(下降沿)能够被可靠检测——因为起始位是低电平,而停止位是高电平,两者之间必然存在一个明显的下降沿。
- 常见配置:1位停止位(最常用)、2位停止位(常用于低速或抗干扰场景)。1.5位停止位仅见于某些特定协议(如一些老式电传打字机)。
- 工程意义:停止位越长,帧间隔越大,接收端处理时间越充裕,但有效数据传输率会降低。
3.2 波特率:通信的“心跳”与计算
波特率(Baud Rate)定义了每秒传输的符号数(Symbols)。在UART中,一个符号即一个位(Bit),因此波特率等同于比特率(bps, bits per second)。波特率决定了每一位的宽度(位时间),是收发双方必须严格匹配的参数。
3.2.1 波特率的本质与位时间
波特率是UART通信的“心跳”频率。收发双方必须使用相同的波特率,否则接收端采样点会逐渐偏移,导致数据错位。位时间(\( T_{bit} \))与波特率(\( B \))的关系为:
位时间 T_bit = 1 / 波特率 B
示例:B = 9600 bps → T_bit = 1/9600 ≈ 104.17 μs
B = 115200 bps → T_bit = 1/115200 ≈ 8.68 μs
接收端通常在每一位的中心点进行采样,以最大程度避免信号边沿的抖动或失真带来的误判。
3.2.2 波特率发生器与分频计算
在单片机中,波特率通常由内部定时器或专用波特率发生器从系统时钟分频得到。以经典的8051单片机为例,使用定时器1作为波特率发生器时,计算公式为:
波特率 = (2^SMOD / 32) × (定时器1溢出率)
定时器1溢出率 = 系统时钟频率 / (12 × (256 - TH1))
其中 SMOD 为波特率加倍位(PCON寄存器最高位)
对于STM32等现代ARM单片机,波特率寄存器(USART_BRR)的值计算如下:
USARTDIV = 外设时钟频率 (PCLK) / (16 × 目标波特率)
BRR 寄存器值 = 整数部分 << 4 | 小数部分(四舍五入到4位小数)
操作流程:配置波特率时,应先查阅芯片参考手册,确认外设时钟源频率,然后根据目标波特率反推分频系数。若分频结果存在小数,需进行四舍五入,并评估实际波特率与目标值的误差。
3.2.3 波特率误差容限与影响
收发双方的波特率不可能完全一致,总会存在微小偏差。只要偏差在±2%(对于8位数据+1起始+1停止的帧结构)以内,通信通常仍能正常进行。但若偏差过大,接收端在采样后续位时会发生“漂移”,最终导致采样点落在错误的位区间。
| 帧长度(位) | 允许的最大波特率误差(理论值) | 工程建议误差范围 |
|---|---|---|
| 10位(8N1) | ±4.5% | ±2% |
| 11位(8E1/8O1) | ±4.0% | ±1.5% |
| 12位(8N2) | ±3.5% | ±1.5% |
3.3 案例拆解:从波形到数据的排障实战
下面通过一个典型的工程场景,演示如何利用帧格式与波特率知识排查UART通信故障。
背景与现象:某嵌入式设备通过UART与PC通信,PC端串口助手配置为115200, 8, N, 1。设备上电后,PC端收到的是乱码,且字符无规律。
初步分析与假设:乱码通常由三种原因引起:波特率不匹配、帧格式不匹配、电平不匹配(如TTL与RS232)。首先排除电平问题(已确认使用USB转TTL模块)。
关键数据与验证过程:
- 检查波特率误差:使用示波器测量设备TX引脚的波形,测量一个完整帧的时长。假设测得一帧(10位)总时长为86.8μs,则实际波特率 = 10 / 86.8μs ≈ 115,207 bps,与目标115200误差仅为0.006%,在容限内。排除波特率问题。
- 检查帧格式:观察波形,发现空闲电平为高,起始位为低,停止位为高,符合UART电平定义。但仔细测量数据位,发现数据位只有7位,且停止位为2位。原来设备固件中配置的是
7, E, 2(7数据位、偶校验、2停止位)。 - 根因定位:PC端配置为8N1,而设备实际发送7E2。PC端将设备的校验位和停止位误认为数据位,导致解析出的字节完全错误。
解决方案与结果:将PC端串口助手配置改为9600, 7, E, 2(与设备匹配),或修改设备固件配置为115200, 8, N, 1。修改后通信恢复正常,数据收发准确无误。
复盘与经验:
- 排查UART通信问题时,示波器是最高效的工具。直接观察波形,数一数一帧中有多少位,测量每位宽度,即可快速判断波特率与帧格式。
- 不要假设两端配置一致,务必核对双方的数据位、校验位、停止位和波特率。
- 在固件中增加帧错误(FE)和噪声错误(NE)中断处理,有助于软件快速感知物理层异常。
3.4 常见误区与总结复盘
在UART协议的理解与应用中,工程师常陷入以下误区,需要特别留意:
- 误区一:认为波特率越高越好。高波特率意味着更短的位时间,对线路质量、寄生电容、地线干扰更敏感。在长线传输或恶劣电磁环境下,过高的波特率会导致误码率急剧上升。
- 误区二:忽略校验位的局限性。如前所述,奇偶校验无法检测偶数位错误。在关键控制链路中,应使用基于数据包的校验和(如CRC16/CRC32)。
- 误区三:停止位越长越可靠。停止位主要提供帧间隔,但过长的停止位会降低有效吞吐量。对于大多数应用,1位停止位足够;2位停止位通常用于时钟精度较差的低速场景。
- 误区四:采样点固定不变。虽然标准UART在位的中心采样,但一些高级MCU支持配置采样点位置(如STM32的OVER8/OVER16模式),合理配置采样点可提升抗干扰能力。
总结复盘:UART协议的精髓在于“异步”二字——通过起始位同步帧、通过波特率同步位。掌握帧格式的每一位定义,理解波特率的计算与误差容限,是编写健壮串口驱动的基础。在实际项目中,建议遵循以下原则:
- 配置明确:在代码中显式定义帧格式宏(如
#define UART_FRAME_8N1),避免魔法数字。 - 误差预算:在时钟频率无法整除目标波特率时,务必计算实际误差,并确保在容限范围内。
- 硬件流控:对于高速或双向大数据量传输,考虑启用RTS/CTS硬件流控,避免数据溢出。
- 调试手段:善用逻辑分析仪或示波器,将协议分析从“猜”变为“看”。