2. UART硬件原理:帧格式、波特率生成、接收移位寄存器与FIFO缓冲区
UART(Universal Asynchronous Receiver/Transmitter)是嵌入式系统中最基础的串行通信外设。理解其硬件数据路径,是优化中断服务函数、解决接收超时与粘包问题的前提。本节从物理帧格式出发,逐级深入波特率时钟、移位寄存器与FIFO缓冲区的协同工作机理。
2.1 UART帧格式:异步传输的物理契约
UART采用异步串行通信,收发双方无需共享时钟信号,而是通过约定的帧格式与波特率完成数据同步。一个标准UART帧包含以下字段:
| 字段 | 位宽 | 电平状态 | 功能说明 |
|---|---|---|---|
| 起始位 | 1 bit | 低电平(0) | 标志数据帧开始,接收端检测到下降沿后启动采样 |
| 数据位 | 5~9 bit(常用8 bit) | LSB first | 承载有效载荷,通常为1字节数据 |
| 校验位 | 0/1 bit | 奇/偶校验 | 可选,用于检错(奇校验/偶校验/无校验) |
| 停止位 | 1/1.5/2 bit | 高电平(1) | 帧结束标志,保证帧间有至少1 bit的高电平间隔 |
关键点:起始位的下降沿是接收端时钟同步的参考点。接收端以波特率时钟的16倍或8倍过采样,在每位的中点附近采样,以避开信号跳变沿的噪声区域。
2.2 波特率生成:从系统时钟到位时钟
波特率(Baud Rate)定义每秒传输的符号数。对于UART,1波特 = 1 bit/s。波特率生成器通常由一个分频计数器实现:
// 波特率计算公式(以STM32 USART为例)
// Tx/Rx 波特率 = f_CK / (16 * USARTDIV)
// 其中 f_CK 为外设时钟,USARTDIV 为16位分频系数(整数+小数部分)
uint32_t baudrate = 115200;
uint32_t usartdiv = (f_CK + (baudrate * 8)) / (baudrate * 16); // 四舍五入
USART->BRR = usartdiv;
工程要点:波特率误差必须控制在 ±2% 以内,否则累积位偏移会导致帧错误。常用波特率(9600、19200、115200、921600)对应的分频系数应优先选择整数分频,避免小数分频引入的量化误差。
2.3 接收移位寄存器:串行到并行的转换核心
接收移位寄存器(Receive Shift Register, RSR)是UART接收路径的第一级硬件单元。其工作流程如下:
- 起始位检测:RX线检测到下降沿后,启动内部采样时钟。
- 位采样:在每个位的中点,将RX线上的电平值移入RSR。
- 帧校验:接收完停止位后,硬件自动校验起始位、校验位、停止位是否正确。
- 数据转移:校验通过后,RSR内容并行加载到接收数据寄存器(RDR),并置位RXNE(Receive Data Register Not Empty)标志。
常见陷阱:如果RSR正在接收下一帧数据时,上一帧数据尚未从RDR中读出(即RXNE标志未清除),则会发生溢出错误(Overrun Error, ORE)。此时新数据会覆盖RDR,旧数据永久丢失。FIFO缓冲区正是为解决此问题而设计。
2.4 FIFO缓冲区:硬件级流量平滑
FIFO(First In First Out)缓冲区是位于RDR与系统总线之间的硬件队列,用于解耦外设接收速率与CPU读取速率。现代MCU的UART外设通常集成深度为16字节或32字节的FIFO。
| 特性 | 无FIFO(传统UART) | 有FIFO(增强型UART) |
|---|---|---|
| 中断频率 | 每接收1字节触发1次中断 | 可配置触发阈值(如1/4/8/14字节) |
| CPU负载 | 高(频繁进出ISR) | 低(批量处理) |
| 抗粘包能力 | 弱(需软件逐字节判断) | 强(可配合超时计数器实现帧边界检测) |
| 溢出风险 | 高(CPU响应延迟时丢数据) | 低(FIFO提供缓冲深度) |
| 典型应用 | 低速、简单协议 | 高速、复杂协议、多任务系统 |
优化策略:在RTOS环境中,将FIFO触发阈值设置为FIFO深度的一半(如16字节FIFO设为8字节触发),配合DMA传输,可实现“零中断”接收模式——仅在DMA传输完成或超时时产生一次中断,极大降低CPU占用率。
2.5 硬件数据路径总结
从RX引脚到CPU读取,UART接收数据经过以下硬件路径:
- RX引脚 → 接收信号调理(施密特触发器、电平转换)
- 波特率时钟域同步 → 过采样(通常16倍)与位边界检测
- 接收移位寄存器(RSR) → 逐位串行输入,并行输出
- 帧校验逻辑 → 校验起始位、校验位、停止位,生成错误标志(FE/PE/ORE/NF)
- 接收数据寄存器(RDR) → 保存校验通过后的完整字节
- FIFO缓冲区 → 硬件队列,可配置触发阈值
- 系统总线接口 → CPU/DMA通过APB/AHB总线读取FIFO数据