STM32 基本定时器笔记:计数公式、影子寄存器与计数方向

定时器本质上就是个计数器。输入的是 CPU 的时钟信号,预分频器 PSC 会执行第一重计数降低频率。预分频器的输出信号会被送入计数器 CNT,计数器溢出会触发更新事件,完成一次定时器触发。

输入时钟 → 预分频器(PSC) → 计数器(CNT) → 自动加载寄存器(ARR) → 溢出触发更新事件

:更新事件的产生是硬件行为,软件想感知它还需要使能中断。

ARR 保存的是计数上限,也就是计数到 ARR+1 就会溢出,触发事件。也就是说:

定时器触发周期 = (ARR + 1) × (PSC + 1) / 时钟频率

公式拆解

为什么是 +1 值而不是原值? 比如 ARR + 1 而不是 ARR。

这是因为硬件的工作方式是"输入 N+1 个信号,输出 1 个信号"。比如 PSC 是 0,那每次输入都会触发一次输出,因为每一次计数都是溢出;PSC 是 1,那每两次输入才会溢出一次:0 → 1 → 溢出。

时钟1: CNT=0 (等于ARR,还没溢出)
时钟2: CNT 要变成1 → 但 ARR 限制了 → 溢出!CNT 重置为 0,触发更新事件

→ 溢出发生在试图超过 ARR 的时候

:要小心把 ARR 设为 0。向上计数模式下,这可能导致不确定行为,一般建议 ARR ≥ 1。

而且,计数是从 0 开始的,所以数到 999 的时候,实际上也就计数了 1000 次。

为什么是 (ARR + 1) × (PSC + 1)?

其实可以把 PSC 理解成另一重计数器,或者说是前置计数器。两个计数器叠加,可以有效降低系统收到的触发频率。

举个例子,如果时钟是 72MHz,我要 1ms 的触发,可以这样设置:PSC 设为 71,这样信号到 ARR 就是 1MHz 了;但是目标频率是 1KHz,所以 ARR 要设置为 (1MHz / 1KHz) - 1 = 1000 - 1 = 999

代入公式就是:

1/1000 s = (999 + 1) × (71 + 1) / 72MHz

值的更新

PSC 值默认情况下是自动装载:更新值写入影子寄存器,等待下一个更新事件才生效。通过设置 UG 位,可以立即触发更新事件,让 PSC 值马上生效。此外,从模式控制器(如复位模式、门控模式)也能触发更新事件。

PSC 和 ARR 都有影子寄存器,只是 PSC 的影子寄存器始终启用(无法关闭,写入后等待更新事件生效),ARR 的影子寄存器可选:

  • ARPE=1 时启用:写 ARR 需要等更新事件生效
  • ARPE=0 时禁用:写 ARR 立即生效

计数中途改变溢出值可能会导致定时不准,为了安全起见,推荐尽量使用影子寄存器。连起来看就是:

计数器当前溢出值是 a → 写入新值 b 到影子寄存器 → 计数器计数递增到 a+1 → 溢出,触发计数器溢出值更新到 b、计数值重置为 0

溢出之后,在同一个时钟周期内就会自动完成置 0:

时钟周期:  [N]    [N+1]  [N+2]
CNT:      ARR  →  0   →  1   → ...
              ↑
           溢出检测
           重载为 0

计数方向

除了常用的向上计数,还支持:

  • 向下计数:从 ARR 倒数到 0
  • 中央对齐:先向上再向下,适合电机 PWM

:PSC 是没有计数方向的,它也不需要,因为其唯一作用就是分频。