3. PWM与电机调速:直流电机调速原理、占空比与平均电压的关系、死区时间与互补PWM

这一章,我们来聊聊PWM怎么让电机转起来、转多快。说白了,就是怎么用一串方波去控制一个直流电机。我刚开始接触这个的时候,也觉得挺神奇的——一个只有0和1的信号,居然能让电机平滑地调速。

3.1 直流电机调速原理

直流电机的转速,本质上由电枢两端的平均电压决定。电压高,转得快;电压低,转得慢。那问题来了:我们怎么改变这个电压?

传统做法是用一个可变电阻串联在回路里,分掉一部分电压。但电阻会发热,效率低得可怜。另一种是用线性稳压器,同样的问题——能量都耗在调整管上了。

PWM就不一样了。它不浪费能量,而是通过快速开关电源,让电机“看到”一个等效的平均电压。电机本身是个大电感,电流不会突变,所以它会把脉冲串“平滑”成连续的电流。

核心公式:

Vavg = Vin × Duty

其中 Duty 是占空比,范围 0~1(或 0%~100%)。

比如 12V 电源,50% 占空比,平均电压就是 6V。

我在一个项目里遇到过这种情况:电机低速时抖得厉害,怎么调PID都没用。后来发现是PWM频率太低,电机在每一个脉冲周期里都“喘口气”,转速自然不稳。把频率从100Hz提到1kHz,问题就解决了。嗯,这里要注意——频率不是越高越好,后面会讲。

3.2 占空比与平均电压的关系

占空比,就是高电平时间占整个周期的比例。你想想看,一个周期里,高电平时间越长,平均电压就越高。

占空比 高电平时间 (10kHz, 100μs周期) 平均电压 (12V电源) 电机状态
0% 0 μs 0 V 停止
25% 25 μs 3 V 低速
50% 50 μs 6 V 中速
75% 75 μs 9 V 中高速
100% 100 μs 12 V 全速

这个关系是线性的,所以控制起来非常直观。你给一个0~100%的占空比,电机就给你一个0~100%的转速(理想情况下)。

但实际中,有一个“死区”——占空比太低时,电机可能根本不转。因为电机需要一定的启动转矩,克服静摩擦和惯性。我记得有一次调试,占空比从0%慢慢往上加,到8%左右电机才“咔”一下动起来。这个阈值,跟电机本身、负载、电源电压都有关系。

我的习惯:在软件里做一个“最小占空比”限制,比如 5%~10%,避免电机在死区里嗡嗡响却不转。同时做一个“启动加速”逻辑,先给一个较高的占空比让电机转起来,再降到目标值。

3.3 死区时间与互补PWM

这部分,是很多初学者容易踩坑的地方。尤其是做H桥驱动的时候。

先说说互补PWM。在H桥里,上管和下管不能同时导通,否则就是直通短路,电流会瞬间烧毁MOS管。所以我们需要一对互补的信号:上管导通时,下管必须关断;下管导通时,上管必须关断。

但问题来了——任何开关器件都有导通和关断的延迟。MOS管关断需要时间,导通也需要时间。如果上管还没完全关断,下管就开始导通了,那瞬间就短路了。

这就是死区时间(Dead Time)存在的意义。在互补PWM里,我们在两个信号之间插入一段“都关断”的时间,确保一个管子完全关断后,另一个才导通。

互补PWM与死区时间示意图 上管PWM 导通 导通 下管PWM 导通 导通 死区 上管关断 → 下管导通 死区时间内,上下管都关断。 电流通过MOS管体二极管续流,不会中断。 死区时间太短 → 直通短路;太长 → 波形失真、效率下降。

死区时间怎么设?我一般这样估算:

  • 查MOS管数据手册,找到关断延迟时间 td(off) 和下降时间 tf
  • 死区时间 > td(off) + tf,再留 20%~50% 的余量
  • 比如一个MOS管关断延迟 50ns,下降时间 30ns,那死区时间至少设 100ns

我曾经踩过的坑:在一个无刷电机驱动项目里,死区时间设得太小(只有 50ns),结果上电瞬间MOS管直接冒烟。后来用示波器一看,上下管有 20ns 的重叠导通时间——就是这 20ns,把管子烧了。从那以后,我每次都会用示波器实测死区时间,而不是只看代码里设的值。

死区时间也不是越大越好。太大会导致:

  • 波形失真,电机电流谐波增加
  • 有效占空比降低,电机出力不足
  • 体二极管导通时间变长,发热增加

所以,死区时间是一个权衡。我个人习惯在 100ns~500ns 之间,具体看MOS管的开关速度和PWM频率。频率越高,死区时间占比越大,对波形的影响也越明显。

3.4 实现方式:硬件 vs 软件

互补PWM和死区时间,可以用硬件实现,也可以用软件实现。

方式 优点 缺点 适用场景
硬件(MCU内部定时器) 精确、稳定、不占CPU 配置复杂,受定时器资源限制 大多数电机控制项目
软件(GPIO翻转+延时) 灵活,不受硬件限制 占用CPU,精度受中断影响 简单实验、低速应用
专用驱动芯片 内置死区、保护功能完善 成本高,灵活性差 大功率、高可靠性场合

我强烈建议用硬件方式。现在的MCU,比如STM32、TI的C2000系列,定时器都支持互补PWM输出和可编程死区插入。配置好了之后,CPU几乎不用管,硬件自动生成精确的波形。

下面是一个STM32的配置示例,用CubeMX生成代码,核心配置就这几行:

// 以TIM1为例,配置CH1和CH1N为互补输出
// 死区时间设为 144ns(时钟频率 168MHz,死区寄存器值 24)
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;  // 占空比 50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

// 设置死区时间
htim1.Instance->BDTR = TIM_BREAK_OFF | 24;  // 24个时钟周期 ≈ 144ns

你看,代码量很少。但要注意,BDTR寄存器里的死区时间值,不同MCU的计算方式不一样。有的直接写纳秒,有的要换算成时钟周期。一定要看数据手册。

一个小技巧:调试时先用示波器看PWM波形,确认死区时间对不对。我习惯把死区时间设得稍微大一点(比如200ns),等系统稳定了再慢慢调小,找到最佳值。