4、PWM输出模式配置:边沿对齐模式与中心对齐模式。PWM模式1与模式2的选择。死区时间的插入(针对H桥)
好,咱们接着聊PWM。上一节我们把定时器的时基单元和计数器搞明白了,这一节要动真格的了——真正让PWM信号从引脚上输出出来。
说实话,PWM输出这块,我当年刚入行时也踩过不少坑。尤其是第一次调H桥驱动电机,一上电就炸管,吓得我赶紧拔电源。后来才发现,是死区时间没配好。嗯,咱们今天就把这些坑一个个填平。
4.1 边沿对齐模式 vs 中心对齐模式
这两种模式,说白了就是计数器计数的「姿势」不一样。
边沿对齐模式:计数器从0数到ARR,然后跳回0,再重新数。波形是对齐在一边的,所以叫边沿对齐。这种模式简单粗暴,适合对时序要求不高的场合。
中心对齐模式:计数器从0数到ARR,再从ARR数回0,像一个三角形。波形是对称的,中心点对齐。这种模式产生的PWM更「干净」,谐波少,电机运行更平稳。
我个人习惯,做电机控制时首选中心对齐模式。为什么?你想想看,电机绕组是感性负载,电流波形越平滑,转矩脉动就越小。中心对齐模式产生的PWM,在载波频率相同的情况下,等效开关频率是边沿对齐的两倍,电流纹波自然就小了。
我在项目中遇到过一台伺服驱动器,客户投诉低速运行时噪音大。我查了半天,发现工程师用的是边沿对齐模式。改成中心对齐后,噪音问题直接解决。就这么简单。
关键区别:
- 边沿对齐:更新事件发生在计数器溢出时(0→ARR→0)
- 中心对齐:更新事件发生在计数器达到ARR或0时(两个点)
- 中心对齐模式下,中断频率是边沿对齐的两倍
4.2 PWM模式1与模式2的选择
这两个模式,其实是决定PWM信号「高电平有效」还是「低电平有效」的。
PWM模式1:当计数器值 < 比较值(CCR)时,输出有效电平(通常是高电平)。当计数器值 ≥ 比较值时,输出无效电平(低电平)。
PWM模式2:正好反过来。当计数器值 < 比较值时,输出无效电平;当计数器值 ≥ 比较值时,输出有效电平。
说白了,模式1和模式2就是一对「互补」的关系。你选模式1,占空比从0%到100%对应CCR从0到ARR。选模式2,占空比从100%到0%对应CCR从0到ARR。
那到底选哪个?我建议你根据H桥的驱动芯片来定。有些驱动芯片要求高电平有效,有些要求低电平有效。我曾经因为没仔细看数据手册,把模式选反了,结果电机反转,差点把机械结构撞坏。嗯,从那以后我养成了一个习惯——先看驱动芯片的输入逻辑,再配PWM模式。
| 配置 | 计数器 < CCR | 计数器 ≥ CCR |
|---|---|---|
| PWM模式1 | 有效电平(高) | 无效电平(低) |
| PWM模式2 | 无效电平(低) | 有效电平(高) |
小技巧:如果你不确定该用哪个模式,可以先配成模式1,然后用示波器看波形。如果发现占空比反了,改成模式2就行。不用改CCR的值,省事。
4.3 死区时间的插入(针对H桥)
好,重点来了。死区时间,这是做H桥驱动时绝对不能跳过的一步。
H桥有上下两个开关管。如果上管还没完全关断,下管就导通了,那会发生什么?直通!电流直接从电源流到地,瞬间烧管子。我第一块H桥板就是这么烧的,冒烟的那一刻,心都在滴血。
死区时间,就是在上下管切换时,故意插入一段「都关断」的时间。比如上管关断后,等几百纳秒,再打开下管。这样即使开关管有延迟,也不会直通。
工业MCU的定时器,通常都内置了死区插入功能。以STM32为例,TIM1和TIM8的高级定时器,有专门的死区寄存器(BDTR)。你只需要设置一个值,硬件会自动在互补PWM信号中插入死区。
// STM32 TIM1 死区配置示例
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
// 时基配置
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
TIM_TimeBaseStructure.TIM_Period = 999; // 10kHz PWM
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// PWM通道配置
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 = 500; // 50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
// 死区配置
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 = 100; // 死区时间 = 100个时钟周期
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
// 使能输出
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
死区时间设多大合适?这得看你的开关管型号。IGBT一般需要1-3微秒,MOSFET可以短一些,几百纳秒到1微秒。我一般先设一个保守值,比如1微秒,然后用示波器看波形,确保上下管没有重叠导通,再慢慢减小。
警告:死区时间不是越大越好。死区太长,会导致波形失真,电机电流畸变,效率下降。死区太短,又有直通风险。建议根据开关管的datasheet中的turn-off delay和fall time来估算,再留20%-30%的余量。
4.4 实战中的避坑指南
最后,分享几个我踩过的坑,希望能帮你少走弯路。
- 互补PWM的极性要一致:我曾经把CH1和CH1N的极性配反了,结果死区时间变成了「重叠时间」,一上电就炸。检查极性时,一定要用示波器看两路信号的交集。
- 死区时间单位别搞错:有些MCU的死区寄存器是以时钟周期为单位的,有些是直接以时间为单位的。我见过有人把纳秒当微秒配,结果死区时间短得跟没有一样。
- 中心对齐模式下更新CCR要小心:在中心对齐模式下,更新比较值最好在计数器达到ARR或0时进行,否则可能会产生不完整的PWM脉冲。很多MCU提供了预装载功能,记得开启。
- 启动顺序很重要:先配置好所有参数,再使能输出。不要边配置边输出,否则中间状态可能导致电机抖动甚至反转。
好了,这一节的内容就到这。PWM输出模式配置,说白了就是选对模式、配好死区、注意细节。下一节我们讲PWM频率和占空比的动态调整,到时候会结合PID控制一起讲,敬请期待。