3. STM32定时器与PWM输出:高级定时器配置、互补PWM输出、刹车功能与故障保护
说到电机控制,PWM 波就是它的「心脏跳动」。而 STM32 的高级定时器,就是专门为这个场景设计的。我刚开始做电机驱动时,用普通定时器凑合过一阵子,结果一遇到刹车需求就傻眼了——还得自己写中断去关管子,反应慢不说,还容易出 Bug。后来换了高级定时器,才发现硬件自动处理这些事有多爽。
3.1 高级定时器 vs 通用定时器:到底强在哪?
STM32 的定时器家族里,高级定时器(TIM1/TIM8)是大哥。它有的功能,通用定时器不一定有。我列个表,你一看就明白:
| 功能特性 | 高级定时器 (TIM1/TIM8) | 通用定时器 (TIM2~TIM5) |
|---|---|---|
| 互补 PWM 输出 | ✅ 支持,带死区插入 | ❌ 不支持 |
| 刹车功能 (Break) | ✅ 硬件级故障保护 | ❌ 无 |
| 重复计数器 | ✅ 可配置更新事件频率 | ❌ 无 |
| 编码器接口 | ✅ 支持 | ✅ 支持 |
| 输出比较通道数 | 4 通道 + 互补 | 4 通道 |
说白了,如果你只是点个灯、调个呼吸,通用定时器完全够用。但要做电机 FOC 或者三相逆变,高级定时器就是刚需。
3.2 互补 PWM 输出与死区时间
互补 PWM,就是一对高低电平相反的 PWM 信号,分别控制 H 桥或逆变器的上下管。你想想看,如果上管关断的同时下管立刻导通,管子还没完全关死,上下就直通了——那叫「穿通」,轻则发热,重则炸管。
所以,硬件必须在上下管切换时插入一段「死区时间」,让两个管子都关断一会儿。高级定时器自带死区插入逻辑,你只需要配一个寄存器值就行。
死区时间配置示例(TIM1,72MHz 主频):
// 死区时间 = DTG[7:0] 对应的步长
// 若 DTG[7] = 0,步长 = 1 个 t_dts(本例 t_dts = 13.89ns)
// 设置死区为 500ns ≈ 36 个步长
TIM1->BDTR = (36 << 0); // DTG = 36,死区 ≈ 500ns
// 使能互补输出和刹车功能
TIM1->BDTR |= TIM_BDTR_MOE | TIM_BDTR_AOE;
这里有个坑:死区时间不是越长越好。太长了,波形失真,电机电流谐波大;太短了,又有穿通风险。我一般根据功率管的 datasheet 里的关断延迟时间,再加 20%~30% 的余量。
3.3 刹车功能与故障保护
刹车功能,是高级定时器最让我放心的地方。一旦检测到外部故障信号(比如过流、过温),硬件会在几个时钟周期内强制把所有 PWM 输出拉到安全状态,不需要 CPU 干预。
刹车源可以是:
- 外部刹车输入引脚(BKIN):接硬件过流信号
- 内部比较器输出:STM32 内部比较器直接连到定时器
- 软件触发:通过寄存器位手动刹车
我的经验: 刹车引脚一定要做硬件去抖。我曾经在一个项目里直接拿比较器输出接 BKIN,结果电机启动时的 EMI 干扰导致误刹车,整条产线都在报故障。后来加了一个 RC 低通滤波,问题就解决了。
刹车后的输出状态可以配置:
- 输出高电平
- 输出低电平
- 高阻态(最常用,让电机自由滑行)
3.4 高级定时器配置实战步骤
我习惯按这个流程来配,不容易漏:
- 时钟使能:开启 TIM1 和 GPIO 时钟
- GPIO 配置:将 PWM 输出引脚设为复用功能推挽输出
- 时基配置:设置预分频器、自动重装载值、计数模式
- 输出比较配置:设置 PWM 模式、极性、占空比
- 死区与刹车配置:BDTR 寄存器
- 使能输出:设置 MOE 位,启动定时器
注意: 高级定时器的 MOE(主输出使能)位必须置 1,PWM 才会真正输出到引脚。很多人配了半天没波形,就是忘了这一位。
3.5 知识体系结构图
下面这张图,把高级定时器在电机控制中的角色串起来了:
3.6 常见问题与避坑
- PWM 输出极性反了? 检查 TIM_CCER 里的 CCxP 和 CCxNP 位,这两个位控制有效电平极性。
- 死区时间不对? 确认 t_dts 时钟源。高级定时器的死区时钟可以独立于定时器时钟,别搞混了。
- 刹车后无法恢复? 检查 MOE 位是否被硬件清零了。如果是,需要重新置位才能恢复输出。
一个小技巧: 调试时先用逻辑分析仪抓互补 PWM 的死区波形,确认死区时间符合预期再上强电。我曾经因为 DTG 计算错误,死区设成了 50ns,结果上电就炸了一个 MOS 管——从那以后,我每次都会先看波形。
嗯,高级定时器的内容就这些。配置起来其实不复杂,关键是理解每个寄存器的用途,尤其是 BDTR 里的那几位。你动手试一次,比看十遍文档都管用。