PWM 定时器核心参数计算指南 (PSC, ARR, CCR)

在微控制器(如STM32)的定时器配置中,精确计算预分频值(PSC)、自动重装载值(ARR)和捕获/比较寄存器值(CCR)是实现高精度PWM输出的基础。根据底层硬件机制,定时器输出 PWM 频率的底层硬件公式为:

\[f_{target} = \frac{f_{clk}}{(psc + 1) \times (arr + 1)} \]

为了根据目标频率精确配置寄存器,我们需要对上述公式进行反推。以下是详细的计算公式、原理剖析以及完整的 C 语言实现。


一、 核心计算公式与原理剖析

1. 核心参数定义

  • \(f_{clk}\):定时器的输入时钟频率(例如 168MHz)。
  • \(f_{target}\):期望输出的目标PWM频率(例如 40KHz)。
  • \(D_{percent}\):期望的占空比百分比(例如 50.0 代表 50%)。
  • \(N_{max}\):定时器的最大计数值,对于标准的16位定时器,其值为 65535。

2. 计算预分频值 (psc)

\[psc = \left\lceil \frac{\frac{f_{clk}}{f_{target}}}{N_{max} + 1} \right\rceil - 1 \]

(注:\(\lceil x \rceil\) 表示向上取整,\(N_{max}\) 为定时器最大计数值,16位定时器为 65535)

  • 为什么要这样算?
    16位定时器的 ARR 寄存器最大只能写入 65535。为了保证计算出的 ARR 绝对不会溢出,我们需要先求出理论总分频系数(\(f_{clk} / f_{target}\)),然后除以 \(65536\) 并向上取整。
  • 为什么要减 1?
    因为 STM32 硬件的实际分频系数是 PSC + 1。如果不减 1,硬件实际分频会变大,导致最终频率偏低。
  • 工程意义: 这种算法确保了在满足目标频率的前提下,分频系数尽可能小,从而为 ARR 留出最大的计数空间。

3. 计算自动重装载值 (arr)

\[arr = \left\lfloor \frac{\frac{f_{clk}}{f_{target}}}{psc + 1} \right\rfloor - 1 \]

(注:\(\lfloor x \rfloor\) 表示向下取整)

  • 为什么要这样算?
    在确定了 psc 后,利用总系数除以实际分频系数(psc + 1)即可得到 ARR + 1 的理论值。向下取整并减去 1 后,得到最终的 ARR
  • 为什么要让 ARR 尽可能大?
    ARR 直接决定了 PWM 的控制分辨率(步进长度)。 ARR 越大,意味着在一个 PWM 周期内,定时器“数”的步数越多。步长变短,占空比的调节就越精细,控制效果越平滑。此算法通过优先压低 PSC,榨干了硬件在当前频率下的分辨率潜力。

4. 计算捕获/比较寄存器值 (ccr)

\[ccr = \left\lfloor \frac{arr + 1}{100.0} \times D_{percent} \right\rfloor \]

  • 为什么要这样算?
    占空比是由 CCR 和 ARR 的比值决定的。因为一个完整周期包含 ARR + 1 个计数,所以必须用 (arr + 1) 乘以期望的占空比百分比。最后向下取整,确保 CCR 的值绝对不会超出 ARR 的范围,防止 PWM 输出异常。

二、 完整的 C 语言代码实现 (snake_case 规范)

以下是包含上述三个值的完整、连续计算代码,命名严格遵循 snake_case 规则:

// 变量定义
uint16_t psc;
uint16_t arr;
uint16_t ccr;

// 假设参数:定时器时钟 168MHz,目标频率 40KHz,占空比 50%
float sys_clock = 168000000.0f;
float target_freq = 40000.0f;
float duty_cycle_percent = 50.0f;

// 1. 计算 psc (确保 ARR 不溢出,且尽可能大以获得最高分辨率)
psc = (uint16_t)(ceilf(sys_clock / target_freq / 65536.0f) - 1);

// 2. 计算 arr (利用 (uint16_t) 截断特性实现向下取整)
arr = (uint16_t)(sys_clock / target_freq / (psc + 1)) - 1;

// 3. 计算 ccr (注意:必须用 arr + 1 参与计算)
ccr = (uint16_t)((arr + 1) * duty_cycle_percent / 100.0f);

三、 参数验算

168MHz 时钟、40KHz 目标频率、50% 占空比 为例,验证上述代码的执行结果:

  • 计算 psc:
    • sys_clock / target_freq = \(168,000,000 / 40,000 = 4200\)
    • \(4200 / 65536.0f \approx 0.064\)
    • ceilf(0.064) - 1 = \(1 - 1 = \mathbf{0}\)
  • 计算 arr:
    • sys_clock / target_freq / (psc + 1) = \(4200 / (0 + 1) = 4200\)
    • \((uint16\_t)(4200) - 1\) = \(4200 - 1 = \mathbf{4199}\)
  • 计算 ccr:
    • (arr + 1) * duty_cycle_percent / 100.0f = \(4200 \times 50.0 / 100.0 = 2100.0\)
    • (uint16_t)(2100.0) = 2100

硬件实际输出验证:

  • 实际频率 = \(168,000,000 / ((0 + 1) \times (4199 + 1)) = \mathbf{40,000 \text{ Hz}}\)
  • 实际占空比 = \(2100 / (4199 + 1) = \mathbf{50\%}\)

结论: 计算完美契合,且 arr 值(4199)远小于 65535,寄存器配置绝对安全,同时获得了当前频率下最高的控制分辨率。

posted @ 2026-09-14 10:30  一块一块儿  阅读(7)  评论(0)    收藏  举报