串口波特率误差计算

UART 是异步通信,收发双方没有共享时钟。主频除不出整数分频时波特率就有误差,超过约 2% 就会开始丢字节。

串口配置的常见坑

波特率误差要卡在 2% 以内。UART 是异步通信,收发双方没有共享时钟,靠各自的波特率对齐。一帧 10 位里采样点会累积偏移,误差超过约 2% 时最后一位就可能采错。9 位数据或连续长帧对误差更敏感,建议压到 1% 以内。这就是为什么串口常用 11.0592 MHz 这种「怪」晶振。

11.0592 MHz 是为了整除。11.0592 MHz = 9600 × 1152,用它做 51 单片的时钟,9600、19200、115200 这些波特率都能整除,误差为零。换成 12 MHz 时 9600 的误差约 0.16%、115200 超过 8% 根本不通。代价是这个频率对定时和运算不方便,所以很多板子会同时挂两颗晶振。

PSC 和 ARR 都要减一。定时器里预分频寄存器写的是「分频系数减一」,自动重载寄存器写的是「计数次数减一」,因为两者都是从 0 开始数。忘了减一会导致定时差一个 tick,在长定时里误差虽小,但在精确定时(比如做波特率或 PWM 频率)时会直接体现出来。

定时越长分辨率越粗。定时器的计数位宽固定(常见 16 位即 65536 个计数),定时越长就必须用越大的预分频,于是每个 tick 变长、可调整的档位变少。想要 10 秒定时又想要 1 μs 精度,在 16 位定时器上是做不到的,得用主频更高的定时器或级联。

过采样倍数写错会差一倍。多数 MCU 的 UART 是 16 倍过采样,但有些型号(如 STM32 的 OVER8 模式)可以改成 8 倍提高速度上限。这时分频系数要按 8 算而不是 16,照旧按 16 算出来的波特率会正好差一倍。配置前查一下芯片手册里的过采样设置。