4. 定时器与PWM生成:高级定时器配置、互补PWM输出、死区时间设置、刹车功能

电机控制的核心,说白了就是控制电压。而电压怎么给到电机?靠的就是PWM。STM32的高级定时器,就是专门干这个活的。我刚开始做电机驱动时,总觉得PWM嘛,不就是输出个方波?结果第一次上电,MOS管直接冒烟了。嗯,从那以后,我再也不敢小看定时器配置了。

4.1 高级定时器 vs 通用定时器

STM32的定时器家族里,高级定时器(TIM1、TIM8等)和通用定时器(TIM2、TIM3等)最大的区别在哪?

功能 高级定时器 通用定时器
互补PWM输出 ✅ 支持 ❌ 不支持
死区时间插入 ✅ 硬件自动插入 ❌ 需软件模拟
刹车功能 ✅ 硬件快速关断 ❌ 无
重复计数器 ✅ 支持 ❌ 不支持
编码器接口 ✅ 支持 ✅ 支持

做电机控制,尤其是FOC或者方波六步换相,必须用高级定时器。为什么?因为你需要同时控制上桥和下桥的MOS管,而且上下桥绝对不能同时导通——这就是死区时间的由来。

4.2 互补PWM输出与死区时间

互补PWM,就是一对信号:一个高电平的时候,另一个必须是低电平。但实际器件有开关延迟,如果上桥还没完全关断,下桥就开了,那就直通短路了。

死区时间:在上桥关断和下桥开启之间,插入一段两者都关断的时间。这个时间通常为几百纳秒到几微秒,取决于你的MOS管驱动速度和栅极电荷。

我个人习惯这样配置死区时间:

// 以TIM1为例,配置互补PWM和死区时间
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

// 1. 时基配置
TIM_TimeBaseStructure.TIM_Prescaler = 0;          // 不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; // 中央对齐模式
TIM_TimeBaseStructure.TIM_Period = 7200 - 1;      // PWM频率 = 72MHz / 7200 = 10kHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

// 2. 输出比较配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;  // 使能互补输出
TIM_OCInitStructure.TIM_Pulse = 3600;             // 50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;      // 互补输出极性
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);

// 3. 死区时间和刹车配置
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
TIM_BDTRInitStructure.TIM_DeadTime = 0x50;        // 死区时间 = 0x50 * Tck = 80 * 13.9ns ≈ 1.11μs
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRInit(TIM1, &TIM_BDTRInitStructure);

// 4. 使能输出
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);

死区时间计算:TIM_DeadTime寄存器的值乘以定时器时钟周期。比如72MHz时钟,Tck=13.9ns,0x50=80,死区≈1.11μs。我一般从1μs开始试,然后看波形调小。

4.3 刹车功能(Break Function)

刹车功能,是高级定时器最救命的功能。当检测到故障信号(比如过流、过压),硬件能在几十纳秒内把所有PWM输出强制拉到安全状态。

我曾经在一个项目中,电流采样电阻虚焊,导致过流信号没及时触发。从那以后,我所有电机项目都强制使用刹车功能,而且刹车引脚必须硬件拉低才能恢复。

刹车配置要点:

  • 刹车极性:高电平有效还是低电平有效,取决于你的故障信号
  • 自动输出:使能后,刹车释放时自动恢复PWM输出
  • 空闲状态:刹车时输出高还是低,取决于你的MOS管驱动

4.4 知识体系结构图

下面这张图,把高级定时器配置的核心逻辑串起来了:

高级定时器PWM配置流程 高级定时器PWM配置核心流程 ① 时基配置 ② 输出比较配置 ③ 死区时间设置 ④ 刹车功能配置 ⑤ 使能PWM输出 关键参数 • 预分频器:决定时钟 • 周期值:决定频率 • 计数模式:边沿/中央 • 占空比:决定电压 • 互补极性:高/低有效 • 死区时间:1~5μs • 刹车极性:高/低电平 • 空闲状态:安全电平 • 自动恢复:使能/禁止 • 锁级别:防止误改 • 主输出使能:最后一步

4.5 常见配置陷阱与避坑

配置高级定时器,有几个地方特别容易翻车:

  • 主输出使能:TIM_CtrlPWMOutputs(TIM1, ENABLE) 必须在 TIM_Cmd 之前调用,否则没输出。我见过有人调了半天,发现是顺序反了。
  • 空闲状态:刹车时输出什么电平?如果你的MOS管是高电平导通,刹车时应该输出低电平。这个搞反了,刹车反而会炸管子。
  • 锁级别:TIM_LOCKLevel 可以防止运行时误改关键参数。调试时设成 LOCK_OFF,量产时建议设成 LOCK_1 或 LOCK_2。

调试技巧:用示波器看PWM波形时,先看单通道,再看互补对。死区时间对不对?看两个通道有没有同时为高的时候。我习惯把死区时间设大一点(比如2μs),确认波形没问题后再逐步减小。

4.6 实际项目中的配置清单

下面是我做电机控制时,高级定时器配置的检查清单:

  1. 时钟配置:TIM1挂在哪条总线上?APB2还是APB1?
  2. 时基参数:频率、计数模式、预分频
  3. 输出通道:使能主输出和互补输出
  4. 极性设置:高有效还是低有效?
  5. 死区时间:根据MOS管参数计算
  6. 刹车引脚:配置GPIO为复用功能
  7. 刹车极性:匹配故障信号
  8. 空闲状态:刹车时的安全电平
  9. 主输出使能:最后一步
  10. 波形验证:示波器确认

嗯,这个清单我每次做新项目都会过一遍。尤其是刹车功能,千万别省。你想想看,电机堵转或者过流的时候,软件响应可能要几十微秒,但硬件刹车只要几十纳秒。这差距,就是炸板子和不炸板子的区别。