4、PWM驱动开发:PWM定时器配置、输出极性设置、死区时间插入、互补输出配置

PWM 驱动,说白了就是让芯片输出一串宽度可调的脉冲。电机调速、LED 调光、开关电源,都离不开它。但真正要把 PWM 用好,尤其是驱动半桥、全桥这类功率电路,光会配个频率占空比可不够。

我个人习惯把 PWM 开发分成四步:定时器骨架搭好 → 极性定对 → 死区插准 → 互补输出收尾。下面咱们一个一个来拆。

4.1 PWM 定时器配置——先把架子搭起来

大部分 MCU 的 PWM 都是由通用定时器或高级定时器产生的。我最早用 STM32 的时候,以为配个 TIM 就是设几个寄存器,结果输出死活没波形。后来才发现,时基单元没配对,后面全白搭。

配置的核心就三个参数:

  • 预分频器(PSC)——决定计数时钟频率
  • 自动重装载值(ARR)——决定 PWM 周期
  • 比较值(CCR)——决定占空比

公式很简单:

PWM 频率 = 定时器时钟 / ((PSC + 1) × (ARR + 1))
占空比   = CCR / (ARR + 1) × 100%

举个例子,我常用 72 MHz 主频,想要 20 kHz 的 PWM:

PSC = 71  → 计数时钟 = 72 MHz / 72 = 1 MHz
ARR = 49  → PWM 频率 = 1 MHz / 50 = 20 kHz
CCR = 25  → 占空比 = 25 / 50 = 50%
我的习惯:先把 PSC 配大一点,让计数时钟降到 1 MHz 左右,这样 ARR 和 CCR 的数值范围更宽,调试时用示波器看也方便。

4.2 输出极性设置——正反逻辑别搞反

输出极性,就是决定高电平有效还是低电平有效。寄存器里通常叫 POLARITY 或 OCxP。

极性设置 有效电平 典型应用场景
高电平有效 CCR 匹配时输出高 通用 PWM、LED 调光
低电平有效 CCR 匹配时输出低 互补输出、负逻辑驱动

为什么会搞反?我记得有一次调试一个电机驱动板,PWM 波形看着没问题,电机就是反转。查了半天,原来是极性设反了,占空比越大转速反而越低。

注意:互补输出时,主输出和互补输出的极性通常是独立的。配错了轻则发热,重则烧管子。

4.3 死区时间插入——防止上下管直通

死区时间,是 PWM 驱动半桥/全桥电路时,上下两个开关管同时关断的那段间隔。没有死区,一个管还没关死,另一个就开了,瞬间短路。

我在项目中遇到过最惨的一次:死区设了 50 ns,觉得够了。结果 MOSFET 的关断延迟有 80 ns,上电瞬间直接冒烟。嗯,从那以后我学乖了。

死区时间怎么算?

死区时间 ≥ 关断延迟 + 开通延迟 + 安全裕量

一般建议:

  • 低速 MOSFET(几百 kHz 以下):200 ns ~ 500 ns
  • 高速 GaN/SiC(MHz 级):50 ns ~ 100 ns
  • 安全裕量至少留 20%

配置时,高级定时器通常有专门的死区寄存器。以 STM32 为例:

TIM1->BDTR |= TIM_BDTR_DTG_0;   // 死区时间 = 1 个计数时钟周期
// 如果计数时钟 = 1 MHz,死区 = 1 µs
避坑指南:我曾经把死区时间设得太大(5 µs),结果电机在低速时抖动得厉害。死区不是越大越好,够用就行。

4.4 互补输出配置——一对信号同时搞定

互补输出,就是同一个 PWM 信号,同时输出两路:一路原相,一路反相。专门用来驱动半桥的上下管。

配置要点:

  1. 使能互补通道——比如 TIM1_CH1 和 TIM1_CH1N
  2. 设置输出极性——主输出和互补输出可以独立设
  3. 插入死区——死区插入后,两路信号之间会自动产生间隔
  4. 使能主输出——高级定时器通常有个 MOE 位,忘了开就没波形

我见过不少新手,配完寄存器发现没输出,查了半天——MOE 位没置 1。说白了,高级定时器多了一层安全锁,你得主动解锁。

下面这张图,是我自己总结的 PWM 互补输出配置流程:

PWM 互补输出配置流程 1. 配置定时器时基 2. 设置输出通道模式 3. 配置输出极性 4. 插入死区时间 5. 使能主输出 (MOE) 常见坑点 • 忘了使能互补通道 • 极性配反导致短路 • 死区太小烧管子 调试建议 先用示波器看两路波形

4.5 实战配置示例——以 STM32 TIM1 为例

下面给一个完整的配置片段,20 kHz PWM,死区 1 µs,互补输出:

// 1. 时基配置
TIM1->PSC = 71;           // 72 MHz / 72 = 1 MHz
TIM1->ARR = 49;           // 1 MHz / 50 = 20 kHz

// 2. 通道模式:PWM 模式 1
TIM1->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;  // PWM 模式 1
TIM1->CCMR1 |= TIM_CCMR1_OC1PE;                      // 预装载使能

// 3. 输出极性:高电平有效
TIM1->CCER |= TIM_CCER_CC1E;    // 主输出使能
TIM1->CCER |= TIM_CCER_CC1NE;   // 互补输出使能
// 默认极性为高电平有效,不修改 CC1P/CC1NP

// 4. 死区时间:1 µs(计数时钟 1 MHz)
TIM1->BDTR |= 1;                // DTG[7:0] = 1

// 5. 使能主输出
TIM1->BDTR |= TIM_BDTR_MOE;

// 6. 设置占空比 50%
TIM1->CCR1 = 25;

// 7. 启动定时器
TIM1->CR1 |= TIM_CR1_CEN;
调试小技巧:配置完先别接功率电路。用示波器看两路输出波形,确认死区时间、极性、频率都对,再上负载。我吃过亏,现在每次都这么干。

4.6 常见问题与排查思路

现象 可能原因 排查方法
无波形输出 MOE 未使能 / 通道未使能 检查 BDTR 寄存器和 CCER 寄存器
频率不对 PSC 或 ARR 算错 用公式反算,核对寄存器值
上下管同时导通 死区时间太小或极性配反 示波器看两路波形是否有重叠
电机抖动 死区时间过大 逐步减小死区,观察抖动消失点

嗯,PWM 驱动开发说难不难,说简单也不简单。核心就一句话:时基算准、极性设对、死区插够、互补使能。把这四步走稳了,大部分 PWM 应用都能搞定。