Dev tool

波特率 / 定时器分频

给一个时钟,问「115200 配得准吗」、「1kHz 怎么填 PSC 和 ARR」。 算出分频寄存器、实际频率和误差,省得写完代码再拿示波器对。

串口波特率

时钟可以写 72000000、72M、8MHz。 公式:USARTDIV = PCLK ÷ (16 × baud),小数部分 4 位。

BRR 寄存器 — —
实际波特率 — —
误差 — —
USARTDIV — —
常见波特率误差 —
波特率 整数 / 小数 实际 误差
定时器 / PWM
更新频率—
更新周期—
单次计数—
占空比—
高电平时间—

频率 = 时钟 ÷ ((PSC + 1) × (ARR + 1)),占空比 = CCR ÷ (ARR + 1)。 反解会优先选误差最小、且 ARR 尽量大的组合(占空比分辨率更高)。

为什么波特率误差会变成乱码

UART 没有时钟线,收发双方各自用本地时钟采样。接收端在起始位下降沿对齐, 然后每隔一个位时间采一次。如果发送方实际偏快 1%,到第 10 位时采样点已经偏了 0.1 个位宽, 还能落在中间;偏 5% 就是半个位宽,正好踩在边沿上——于是这一帧随缘。

所以误差要按整帧累积看,不是逐位看。常见做法是单向误差控制到 2% 以内, 115200 这种高速率还要更严。工具里的误差表就是拿来一眼扫的:全绿说明这个时钟配这组波特率没问题。

选 PSC 还是选 ARR

两个都能凑出同一个频率,但影响不同:PSC 决定计数一次多久,ARR 决定数多少次。 PWM 的占空比档位数等于 ARR + 1,所以要分辨率就把 ARR 拉大、PSC 压小。

反过来说,如果需要很长的定时(比如几秒一次的看门狗喂狗),ARR 已经到 65535 还不够, 就只能加 PSC。工具的反解会优先保证 ARR 尽量大,正是这个道理。

差一个数的地方

PSC=71 是除以 72,ARR=999 是数 1000 次再溢出, CCR=250 在 ARR=999 时是 25%。寄存器里的值永远比「除数」小 1, 这是嵌入式里最常见的 off-by-one。

常见问题

为什么 8MHz 时钟配不出准确的 115200?

STM32 的波特率分频是 USARTDIV = PCLK / (16 × baud),小数部分只有 4 位,也就是只能表示 1/16 的倍数。8MHz 下算出来是 4.3403,最接近的是 4 + 5/16 = 4.3125,实际波特率 115942,误差 +0.64%。要让误差归零,PCLK 必须是 16 × 115200 的整数倍——比如 7.3728MHz、14.7456MHz,或者从 8MHz 倍频到 72MHz。

误差多少算可以接受?

UART 是异步的,收发双方各自用本地时钟采样,累积误差必须在半个位时间内完成一帧才不出错。工程上一般要求单向误差小于 2%~3%,留足余量;超过 5% 就很容易偶发乱码,尤其是长帧、多字节连发。表里那些 0.0x% 的都可以放心用。

定时器的 ARR 和 PSC 有什么区别?

PSC 是预分频,把定时器时钟先除一次,决定「计数一次」对应多长时间;ARR 是自动重装值,决定数多少次溢出。两者相乘才是总的分频比。选择上优先把 PSC 调小、ARR 调大——因为 PWM 占空比的分辨率由 ARR 决定,ARR 只有 100 的话占空比只能调 1% 一档。

72MHz、PSC=71、ARR=999 为什么正好是 1kHz?

因为 (71+1) × (999+1) = 72 × 1000 = 72000,72000000 / 72000 = 1000。注意两个寄存器都要 +1:PSC=0 表示不分频(除以 1),ARR=0 表示数 1 次就溢出。这一点写代码时最容易差一个数。

占空比为什么是 CCR / (ARR + 1) 而不是 CCR / ARR?

因为计数器从 0 数到 ARR,一共经过 ARR+1 个状态。CCR 表示「计数值小于 CCR 时输出有效」,所以有效状态正好是 CCR 个。ARR=999 时周期是 1000 个计数,CCR=250 就是 25%。想让 CCR 直接等于百分比,就把 ARR 设成 99 或 999。