UART 设计:波特率分频、帧格式、采样容错与 RX FIFO 溢出
更新时间:2026-09-19。本文与同步的 SPI、I2C 对照。UART 无共享时钟、点对点、全双工,常挂 APB 做调试 console 与工业 Modbus(见 RS485/Modbus)。
本文要回答的问题
- 没有时钟线,收发双方怎么对齐每一位?波特率分频怎么算?
- 一帧由哪些位组成,起始/停止位起什么作用?
- 为什么用 16 倍过采样、在每位中间采样?怎么抗波特率误差?
- 帧错误、校验错误、溢出(overrun)分别怎么判定?
一、帧格式:起始位 + 数据位 + 校验 + 停止位
空闲为高电平(mark)。一帧(典型 8N1):
空闲 ┐ 起始 D0 D1 D2 D3 D4 D5 D6 D7 停止 空闲
1 └ 0(1位) ────── 8 数据位(LSB先发)───── 1(1位) ─ 1- 起始位:高→低跳变,占 1 位时间,通知接收方一帧开始并提供时间基准。
- 数据位:5–9 位,通常 8 位,LSB 先发。
- 校验位(可选):none/even/odd,做简单检错。
- 停止位:1、1.5 或 2 位高电平,给接收方喘息并保证下一个下降沿可辨。
- 双方必须约定一致的波特率与帧格式,否则解出乱码。
二、波特率生成:分频计数器
发送端把系统时钟分频出「位周期」节拍。若系统时钟 f_clk、目标波特率 baud,分频系数 = f_clk / baud。50 MHz 出 115200:50_000_000/115200 ≈ 434 个系统拍一个位周期。寄存器可配分频值以支持 9600~921600 等。
TX:一个 FSM + 移位寄存器,按位节拍依次输出起始低电平、数据、校验、停止高电平;发送保持寄存器(THR)与移位寄存器分离可实现双缓冲(写一字节时上一字节正在移)。
三、RX:16 倍过采样 + 中位采样
接收方没有对方时钟,用本地更高频率(常用 16× 波特)过采样来恢复位定时:
- 空闲监测 RXD;检测到下降沿(高→低)认为可能是起始位。
- RXD 先经两级触发器同步消除亚稳态(见 亚稳态)。
- 从下降沿起,等到位周期中点(约第 8 个 16× 拍)再采样,确认仍是低才认定为真起始位(滤毛刺、避开边沿抖动)。
- 之后每隔 16 个 16× 拍(即每个位周期中点)采样一次数据位,共取 8 位,拼成字节。
- 在停止位中点应采到高;为低即 帧错误(FE)。
为什么在中间采样、为何能容错:只要累计相位误差在一帧内不超过约 ±0.5 位,中点采样仍落在该位区间。8N1 共 10 位,允许的收发波特率偏差约 ±(0.5/10)=±5%(实际留裕量按 ±2~3% 设计)。更稳的做法是每位多点投票(如 7/8/9 三点取多数)抗噪声。每收到新起始位都重新对齐,避免误差跨帧累积——这正是起始位的关键价值。
四、RX FIFO 与溢出(Overrun)
收来的字节先入 RX FIFO(见 FIFO 深度设计),CPU 来不及逐字节取也不丢。触发中断的阈值/超时可配(见入门 中断与 DMA)。关键错误:
- 溢出 ORE(overrun error):FIFO 满时又收到完整新字节,无处可存,新字节(或旧字节,看实现)丢失。必须置 ORE 标志/中断,软件统计并丢弃当前帧或复位接收。
- 校验错误 PE:even/odd 计算结果与校验位不符。
- 帧错误 FE:停止位应为高却为低(波特率不匹配、断线、噪声)。
- break 检测:RXD 被拉低超过一整帧时间,常用于唤醒/特殊信号。
设计 FIFO 深度要结合最坏中断延迟与波特率:115200 下每 ~87 µs 来一字节,高波特率(921600,~10.8 µs/字节)下中断方式很易溢出,应加大 FIFO 或走 DMA。
五、流控(可选)
- 无流控:3 线(TX/RX/GND)。
- RTS/CTS 硬件流控:接收方 FIFO 将满时拉 RTS(对端看到 CTS)请对方停发,可在高波特率下根治溢出;软件 XON/XOFF 则占用数据码。
- 半双工 RS485 需在发送时驱动方向使能(DE),见 RS485/Modbus。
六、常见的坑
- 只在边沿采、不在中位采:相位/波特率稍有偏差就采到跳变沿,误码;必须 16× 过采样、中点对齐。
- RXD 不同步:异步输入直入逻辑产生亚稳态,先两级同步。
- 波特率分频取整误差大:低 f_clk 出高 baud 时误差超容限;选合适时钟或分数分频。
- FIFO 满不收尾:不检测 overrun,静默丢字节且无标志;必须置 ORE/中断。
- 位序/帧格式错配:UART 是 LSB 先发,与 SPI/数据习惯相反;校验/停止位数两端要一致。
- 高波特率用中断逐字节取:CPU 响应不及导致溢出;加 FIFO/DMA/RTS-CTS。
- TX 未等移位完成就改数据:要等 TX 移位空(TEMT)再关时钟/断电。
相关与延伸
对比见 SPI 主机、I2C 主机;同步原理见 亚稳态;FIFO 深度见 FIFO 深度设计;总线接口见 APB;工业扩展见 RS485/Modbus。
总结
UART 靠起始位下降沿对齐、用本地 16 倍过采样在每位中点取数,在无时钟线情况下容忍约 ±半位的累计波特率误差;帧=起始位+LSB 先发的数据位+可选校验+停止位,RXD 先两级同步,收字节入 FIFO,停止位为低报帧错误、校验不符报 PE、FIFO 满又来新字节报 overrun,高波特率要靠深 FIFO/DMA/硬件流控防丢。