4. 输出通道配置:单通道与多通道PWM输出,互补输出与死区插入,刹车功能
输出通道配置这块,说实在的,是PWM模块里最容易出bug的地方。我见过不少同事,寄存器配得飞起,一上示波器就傻眼——波形对不上,或者一开机就炸管。嗯,咱们今天把这几个关键点捋清楚。
4.1 单通道与多通道PWM输出
先聊最基本的。单通道输出,说白了就是一个定时器通道产生一路PWM。比如控制一个LED亮度,或者驱动一个舵机,单通道就够了。
多通道呢?就是一个定时器的多个通道同时输出。比如TIM1有4个通道,你可以让CH1、CH2、CH3、CH4各自输出不同占空比的PWM。这在电机控制里很常见——一个定时器搞定三相驱动。
核心区别:
- 单通道:配置简单,占用资源少,适合独立控制
- 多通道:共享时基,相位同步好,适合多路协调控制
我个人习惯,只要能用多通道,绝不用多个定时器。为什么?因为多个定时器之间会有相位偏差,你想想看,两个定时器的计数起点不一样,输出的PWM波形天然就有相位差。这在某些应用里是致命的。
配置代码其实不复杂,以STM32的HAL库为例:
// 单通道配置示例
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; // 占空比
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
// 多通道配置——只需重复配置不同通道
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
小技巧:多通道输出时,建议先配置所有通道,再统一启动。我曾经先启动CH1再配置CH2,结果CH2的波形第一个周期是乱的——因为启动时配置还没生效。
4.2 互补输出与死区插入
互补输出,这是电机驱动和逆变器的核心功能。说白了就是一对信号,一个高另一个就低,反之亦然。比如控制H桥的上下管,绝对不能同时导通,否则就是短路——炸管是分分钟的事。
死区插入就是为了解决这个问题的。上下管切换时,插入一段两者都关断的时间,让电流有时间泄放掉。
我记得第一次做BLDC驱动,死区时间设得太短,结果上电一瞬间,MOS管直接冒烟了。后来查手册才知道,MOS管的关断延迟比开通延迟长,死区时间必须覆盖这个差异。
| 死区时间 | 适用场景 | 风险 |
|---|---|---|
| 太短(<100ns) | 高频开关(>100kHz) | 上下管直通,炸管 |
| 适中(100ns-1μs) | 通用电机驱动(10-50kHz) | 效率适中 |
| 太长(>1μs) | 低频大功率(<5kHz) | 波形畸变,效率下降 |
配置互补输出时,需要同时设置输出极性、空闲状态和死区时间。以STM32高级定时器为例:
// 互补输出 + 死区配置
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 100; // 死区时间,单位取决于定时器时钟
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
// 配置互补通道
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 互补通道极性
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
// 启动互补输出
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
注意:互补输出必须使用高级定时器(TIM1/TIM8等),普通定时器没有这个功能。另外,死区时间的单位取决于定时器的时钟分频,一定要看数据手册换算。
为什么会需要调整死区时间?因为不同的功率器件开关速度不一样。IGBT慢,MOSFET快,SiC更快。我建议你先看器件手册的开关时间参数,然后留出至少20%的余量。
4.3 刹车功能
刹车功能,英文叫Break,是高级定时器的一个安全机制。当检测到异常信号时,可以强制关闭PWM输出,把输出引脚拉到安全状态。
这个功能在工业驱动里是强制要求的。比如电机过流、过温、急停按钮按下,刹车信号一来,PWM立刻停止,不管CPU在干什么。
我曾经在一个项目中,刹车信号没接,结果电机堵转时电流飙升,MOS管直接烧了。后来加了刹车功能,过流信号直接连到定时器的刹车输入引脚,硬件自动保护,再也没出过问题。
刹车功能的配置要点:
- 刹车源:可以是外部引脚,也可以是内部比较器输出
- 刹车极性:高电平有效还是低电平有效
- 刹车后的输出状态:可以是高阻、低电平或高电平
- 自动恢复:刹车信号消失后,PWM是否自动恢复
// 刹车功能配置
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0; // 刹车输入滤波
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; // 自动恢复
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
避坑指南:刹车引脚一般有内部上拉/下拉,配置时要注意。我曾经因为没配置内部上拉,刹车引脚悬空,结果干扰信号误触发了刹车,电机频繁启停。加个10kΩ下拉电阻就解决了。
下面这张图总结了输出通道配置的核心逻辑:
最后说一句,输出通道配置这块,最忌讳的就是想当然。你以为配置对了,示波器一看全露馅。我建议你每次改完配置,都先用示波器抓一下波形,确认死区时间、极性、相位都对得上。尤其是互补输出,上下管的波形一定要同时抓,确保没有重叠。
嗯,这部分内容就到这里。配置的时候多留个心眼,别像我当年那样炸管就行。