3、UART协议原理:UART帧格式(起始位、数据位、校验位、停止位)、波特率定义与计算

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是嵌入式系统中最基础、最广泛使用的串行通信协议之一。与I2C、SPI等同步通信协议不同,UART属于异步串行通信,收发双方不需要共享时钟信号,而是通过预先约定好的波特率(Baud Rate)和帧格式(Frame Format)来完成数据的正确解析。理解UART帧结构中每一位的作用,以及波特率与比特率之间的换算关系,是进行串口驱动开发、通信调试和低层协议分析的前提。本章将深入拆解UART帧格式的每一个细节,并系统讲解波特率的定义、计算与误差容忍度。

UART 帧格式与波特率映射关系 UART 帧结构 (8N1 示例) 空闲 高电平 ST 0 D0 LSB D1 D2 D3 D4 D5 D6 D7 MSB PB 可选 SP 1 时间 t → (每一位持续时间为 1/波特率 秒) 波特率 vs 比特率 波特率 符号/秒 (Bd) 比特率 位/秒 (bps) UART 中每个符号仅携带 1 位数据, 因此: 波特率 = 比特率 (仅适用于 UART 二进制电平) 波特率计算示例 (115200-8N1) 帧总位数 = 1 (起始) + 8 (数据) + 0 (无校验) + 1 (停止) = 10 位 每帧传输时间 = 10 / 115200 ≈ 86.8 μs 有效数据率 = 8 / 10 × 115200 = 92,160 bps (约 11.25 KB/s) ⚠ 波特率误差要求:UART 接收端容忍度通常为 ±2%~±3%,超过则可能产生采样错位或乱码。

上图展示了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%位宽处)进行采样,以确保采样的稳定性。起始位是帧同步的关键,没有起始位,接收端将无法确定数据从哪一位开始。

工程要点:在驱动开发中,接收中断(RX Interrupt)通常由起始位的下降沿触发。如果总线上存在噪声导致电平抖动,可能会产生虚假的起始位。因此,硬件UART外设通常内置了毛刺滤波(Glitch Filter),只有低电平持续时间超过一定阈值(如1/16位宽)才被认定为有效起始位。

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位数据位配置,在普通驱动开发中极少遇到。

表3-1 常见UART帧格式配置对比
配置名称 数据位 校验位 停止位 帧总位数 典型应用场景
8N18无110最通用,PC串口、蓝牙模块、GPS模块
8E18偶校验111Modbus RTU、工业仪表
8O18奇校验111老旧电信设备、部分PLC
7E17偶校验110ASCII码传输(历史遗留)
9N19无111多机通信地址帧标志(如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%以内。

风险提示:在驱动开发中,如果使用MCU内部RC振荡器(精度约±1%~±3%)且波特率设置较高(如921600),则可能因误差累积导致通信失败。此时应改用外部晶振,或降低波特率。另外,在Linux内核中,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或更高层校验。
总结:UART帧格式是异步通信的基石,每一位都有明确的时序和电平要求。驱动开发者必须熟练掌握起始位下降沿触发、LSB First发送顺序、停止位高电平恢复等关键细节。波特率计算的核心在于分频系数的精确配置,务必通过实际波形验证误差。在调试乱码问题时,应按照“帧格式 → 波特率误差 → 电气特性”的顺序逐一排查,避免盲目修改参数。