3、UART协议原理:UART帧格式(起始位、数据位、校验位、停止位)、波特率定义与计算
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是嵌入式系统中最基础、最广泛使用的串行通信协议之一。与I2C、SPI等同步通信协议不同,UART属于异步串行通信,收发双方不需要共享时钟信号,而是通过预先约定好的波特率(Baud Rate)和帧格式(Frame Format)来完成数据的正确解析。理解UART帧结构中每一位的作用,以及波特率与比特率之间的换算关系,是进行串口驱动开发、通信调试和低层协议分析的前提。本章将深入拆解UART帧格式的每一个细节,并系统讲解波特率的定义、计算与误差容忍度。
上图展示了UART帧格式的基本构成以及波特率与比特率的关系。在后续内容中,我们将逐一拆解帧格式中每一位的作用,并深入探讨波特率在驱动开发中的实际应用与误差控制。
3.1 UART帧格式深度拆解
UART协议的核心在于其异步帧结构。由于没有独立的时钟线,接收端必须依靠起始位来同步采样时钟,并依据约定的波特率在每一位的中心点进行采样。一个标准的UART帧由以下部分按顺序组成:空闲态(Idle)→ 起始位(Start Bit)→ 数据位(Data Bits)→ 校验位(Parity Bit,可选)→ 停止位(Stop Bit)→ 空闲态。下面逐一分析每个字段的工程含义。
3.1.1 空闲态与起始位
空闲态(Idle State):当UART总线没有数据传输时,TX线保持在高电平(逻辑1)。这个高电平状态是UART协议的基础,它使得接收端能够通过检测电平的下降沿(Falling Edge)来识别新帧的开始。
起始位(Start Bit):起始位是一个低电平(逻辑0)脉冲,持续时间为一个波特率周期(即1/波特率秒)。接收端在检测到下降沿后,会启动一个内部的波特率计数器,并在后续每一位的中点(50%位宽处)进行采样,以确保采样的稳定性。起始位是帧同步的关键,没有起始位,接收端将无法确定数据从哪一位开始。
3.1.2 数据位(Data Bits)
数据位是帧中真正承载信息的部分,紧随起始位之后。数据位的长度可以配置,常见的有5、6、7、8、9位。在大多数现代嵌入式系统中,8位数据位(8N1)是最常用的配置,因为它正好对应一个字节(Byte)。
数据位的发送顺序遵循LSB First(最低有效位在前)的原则。例如,要发送十六进制数据 0x55(二进制 01010101),发送顺序为:1 → 0 → 1 → 0 → 1 → 0 → 1 → 0(从D0到D7)。这一顺序与I2C/SPI(通常MSB First)不同,在驱动开发中需要特别注意,尤其是在与PC端串口调试助手交互时,如果字节序配置错误,会导致数据完全错乱。
3.1.3 校验位(Parity Bit)
校验位用于简单的错误检测,它只能检测奇数个位错误,无法纠错。UART支持三种校验模式:
- 无校验(None):帧中不包含校验位,帧总长度最短。
- 奇校验(Odd):数据位和校验位中“1”的总个数为奇数。例如数据位
0x55(含4个1),则校验位为1,使总数为5(奇数)。 - 偶校验(Even):数据位和校验位中“1”的总个数为偶数。例如数据位
0x55(含4个1),则校验位为0,使总数为4(偶数)。
校验位在工业总线(如RS-485)中应用较多,用于对抗电磁干扰。但在高速、大数据量传输场景下,由于校验位增加了开销且检测能力有限,通常选择无校验模式,而将错误检测交给更高层协议(如CRC校验)。
3.1.4 停止位(Stop Bit)
停止位位于帧的末尾,是一个高电平(逻辑1)信号,持续时间为1、1.5或2个波特率周期。停止位的作用是标志一帧数据的结束,并保证总线回到空闲态(高电平),为下一帧的起始位下降沿做准备。
常见的停止位配置为1位(1 Stop Bit)。使用2位停止位(2 Stop Bit)多见于低速、抗干扰要求高的场景(如某些PLC通信),但会降低有效数据传输率。1.5位停止位仅用于某些特定的5位数据位配置,在普通驱动开发中极少遇到。
| 配置名称 | 数据位 | 校验位 | 停止位 | 帧总位数 | 典型应用场景 |
|---|---|---|---|---|---|
| 8N1 | 8 | 无 | 1 | 10 | 最通用,PC串口、蓝牙模块、GPS模块 |
| 8E1 | 8 | 偶校验 | 1 | 11 | Modbus RTU、工业仪表 |
| 8O1 | 8 | 奇校验 | 1 | 11 | 老旧电信设备、部分PLC |
| 7E1 | 7 | 偶校验 | 1 | 10 | ASCII码传输(历史遗留) |
| 9N1 | 9 | 无 | 1 | 11 | 多机通信地址帧标志(如9位UART) |
3.2 波特率定义与计算
波特率(Baud Rate)定义为每秒传输的符号(Symbol)数量,单位是Bd(Baud)。在UART中,由于每个符号仅代表一个二进制电平(0或1),因此波特率 = 比特率(bps)。但在其他调制技术(如QAM)中,一个符号可能携带多个比特,此时波特率与比特率不相等。在UART驱动开发中,我们通常直接称“波特率”为每秒传输的位数。
3.2.1 波特率与位时间
波特率决定了每一位的持续时间(位时间 T_bit),计算公式为:
T_bit = 1 / 波特率 (单位:秒)
例如,波特率为 115200 时,每一位持续时间为 1 / 115200 ≈ 8.68 μs。接收端必须在起始位下降沿后,每隔 T_bit 时间采样一次数据位。如果收发双方的波特率存在偏差,采样点会逐渐偏移,导致误码。
3.2.2 波特率误差与容忍度
UART是异步通信,收发双方使用各自的时钟源。即使标称波特率相同,实际频率也可能因晶振精度、分频器舍入误差而不同。接收端通常在每个数据位的中点采样,只要采样点没有偏移到相邻位,通信就能成功。
对于标准的8N1帧(10位),接收端在起始位下降沿后,会在第1.5位、2.5位……9.5位处采样。如果发送端波特率比接收端快,那么接收端采样到的数据位会逐渐“滞后”。理论分析表明,对于10位帧,允许的最大波特率误差约为 ±4.5%,但工程上为了留有余量,通常要求误差控制在 ±2%以内,推荐 ±1%以内。
clk_get_rate 获取的UART外设时钟频率必须能被目标波特率整除,否则会产生分频误差。
3.2.3 波特率分频计算实例
以STM32F4系列为例,其USART外设时钟(PCLK2)通常为 84 MHz。要产生 115200 波特率,需要计算分频系数 USARTDIV:
USARTDIV = PCLK2 / (16 × 波特率)
= 84,000,000 / (16 × 115,200)
= 84,000,000 / 1,843,200
≈ 45.5729
硬件寄存器中,USARTDIV 的整数部分写入 BRR[15:4],小数部分写入 BRR[3:0]。实际写入值需要将小数部分乘以16并四舍五入:
小数部分 = 0.5729 × 16 ≈ 9.17 → 取整为 9
BRR 值 = (45 << 4) | 9 = 0x2D9
实际产生的波特率为:84,000,000 / (16 × (45 + 9/16)) = 84,000,000 / (16 × 45.5625) = 115,226.3,误差约为 +0.023%,完全在容忍范围内。
3.3 实战场景:串口通信乱码排查与波特率校准
场景背景:某物联网网关设备使用ESP32-C3(内置UART)与一个工业传感器模块通信,传感器模块固定波特率为 9600-8N1。设备上电后,网关能收到数据,但内容全部为乱码。
初步排查:工程师首先检查了代码中的UART初始化参数,确认设置为 9600, 8N1,与传感器一致。随后使用逻辑分析仪抓取传感器TX引脚波形,发现波形正常,帧格式正确。问题定位到ESP32-C3的UART接收配置。
深入分析:通过读取ESP32-C3的 UART_CLKDIV_REG 寄存器,发现实际分频值对应的波特率为 9592.3,误差约 -0.08%。这个误差本身很小,不应导致乱码。进一步检查发现,工程师在初始化UART时,误将 parity 参数设置为 UART_PARITY_ODD(奇校验),而传感器实际发送的是无校验(8N1)。由于帧格式不匹配,接收端将校验位当作数据位解析,导致所有字节的高位错乱。
解决方案:将UART初始化参数中的校验位改为 UART_PARITY_DISABLE,停止位保持1位。修改后通信恢复正常,数据解析完全正确。
复盘经验:乱码问题不一定源于波特率偏差,帧格式(尤其是校验位)不匹配是更常见的隐性原因。在驱动开发中,建议使用逻辑分析仪或示波器抓取实际波形,对比帧格式中的每一位,而不是仅依赖代码配置。同时,在调试阶段可打印UART外设的实际分频寄存器值,确认波特率误差在允许范围内。
3.4 常见误区与总结复盘
在UART驱动开发与调试中,以下误区值得特别注意:
- 误区一:认为波特率越高越好。高波特率(如1Mbps以上)对PCB走线、电平转换芯片的压摆率(Slew Rate)以及线缆长度都有严格要求。在工业现场,长线传输时盲目提高波特率会导致信号反射和码间串扰(ISI)。
- 误区二:忽略“波特率”与“比特率”的区分。在UART中二者相等,但在调试其他调制型通信(如GMSK)时,混淆二者会导致带宽估算错误。
- 误区三:停止位越长越可靠。停止位的主要作用是帧间隔,并非抗干扰手段。增加停止位会降低有效吞吐量,对于抗干扰,应优先考虑屏蔽、双绞线或使用RS-485差分信号。
- 误区四:校验位能保证数据正确。奇偶校验只能检测奇数个位翻转,对于偶数个位翻转(如两位同时翻转)无能为力。在关键控制场景,必须使用CRC或更高层校验。