4. PWM调速原理:PWM频率与占空比、电机响应特性、死区时间设置

各位同学,咱们今天聊PWM调速。说实话,这玩意儿是电机控制里最基础、也最容易被忽视的一环。我见过不少工程师,上来就调PID,结果电机嗡嗡响、发热严重,最后发现是PWM参数没设对。嗯,咱们今天就把它彻底讲透。

4.1 PWM频率:不是越高越好

PWM频率,说白了就是开关管一秒钟通断多少次。你想想看,频率太低,电机一抖一抖的,像得了帕金森;频率太高,开关管发热,驱动芯片先扛不住。

那怎么选? 我个人习惯分三步走:

  • 听声音:频率低于16kHz,人耳能听到“滋滋”声。美容仪在脸上用,客户听到这声音肯定投诉。所以我一般选20kHz以上,人耳听不见。
  • 看电机电感:电机线圈有电感,电流不能突变。频率太高,电流还没爬上去就关断了,实际平均电流上不去。我遇到过一个小电机,标称1A,PWM设到100kHz,结果只能出0.6A。
  • 考虑死区时间:频率越高,每个周期越短,死区时间占比就越大。后面会细说。

我的经验值:美容仪常用的空心杯电机、微型直流电机,PWM频率取20kHz~40kHz最稳妥。我做过一个项目,客户非要50kHz,结果MOS管烫得能煎鸡蛋,最后乖乖改回30kHz。

4.2 占空比:控制电压的“水龙头”

占空比,就是高电平时间占整个周期的比例。50%占空比,等效电压就是电源电压的一半。这个好理解,但有几个坑要注意:

  • 非线性区:占空比太低(比如低于5%),电机可能根本不转。因为启动转矩不够。我调试时习惯从10%开始往上加。
  • 饱和区:占空比超过95%,再往上加,电机转速几乎不变。因为反电动势已经接近电源电压了。
  • 分辨率:8位PWM(0~255)够用吗?说实话,美容仪调速要求不高,8位够了。但如果你要做精密位置控制,至少得12位。

避坑指南:我曾经在一个项目里,用8位PWM控制电机,占空比从0调到255,结果电机在0~10和245~255这两个区间几乎没反应。后来发现是驱动芯片的输入阈值有死区。解决办法是软件上做映射,把0~10映射到10,245~255映射到245。

4.3 电机响应特性:别指望它瞬间听话

电机是个惯性系统。你给100%占空比,它不会瞬间到最高速;你突然降到0,它也不会立刻停。这就是机电时间常数。

为什么重要? 你想想看,美容仪做脉冲模式时,要求电机快速启停。如果PWM频率和电机响应不匹配,就会出现:

  • 启动延迟:指令发了,电机半天才动
  • 过冲:转速超过目标值,然后来回震荡
  • 停止拖尾:指令停了,电机还在转

我的做法:先测一下电机的机电时间常数。方法很简单——给电机一个阶跃电压(比如直接12V),用示波器看电流波形。电流从0上升到63%的时间,就是时间常数。然后PWM的更新频率至少要快于这个时间常数的10倍。

注意:千万别把PWM频率和电机响应频率搞混。PWM频率是开关频率,电机响应频率是机械带宽。前者通常20kHz以上,后者可能只有几十Hz。你PWM更新再快,电机也跟不上。所以控制周期(PID运算周期)一般设在1ms~10ms就够了,没必要跟PWM频率同步。

4.4 死区时间设置:保命用的

死区时间,就是上下桥臂同时关断的那一小段时间。为什么要有它?因为开关管不是理想器件,关断需要时间。如果上管还没完全关断,下管就导通了,那就直通短路——啪,冒烟。

设置原则

开关管类型 典型死区时间 说明
MOSFET(低速) 100ns~500ns 美容仪常用,成本低
MOSFET(高速) 50ns~200ns 需要专用驱动芯片
IGBT 1μs~3μs 大功率场合,美容仪少见

怎么调? 我一般这样操作:

  1. 先设一个保守值,比如500ns
  2. 用示波器看上下管的栅极波形,确保一个完全关断后另一个才导通
  3. 逐步减小死区时间,直到波形上出现“交叠”的临界点
  4. 在这个临界点基础上,再加50%的余量

我曾经踩过的坑:有一次为了追求效率,把死区时间设得很小,只有80ns。实验室测试一切正常,结果量产1000台,有3台在客户手里烧了。后来分析发现,是不同批次的MOS管关断时间有差异。从那以后,我死区时间至少留100%余量。效率低一点没关系,可靠性第一。

4.5 实战:一个完整的PWM配置示例

拿STM32F103做个例子,控制一个12V空心杯电机:

// PWM配置参数
#define PWM_FREQ        20000   // 20kHz
#define PWM_PERIOD      1000    // 自动重装载值
#define DEAD_TIME_NS    200     // 200ns死区时间

// 初始化定时器
void PWM_Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
    
    // 1. 计算预分频系数
    // 系统时钟72MHz,目标20kHz,周期1000
    // 预分频 = 72MHz / (20kHz * 1000) - 1 = 2.6,取3
    TIM_TimeBaseStructure.TIM_Prescaler = 3;
    TIM_TimeBaseStructure.TIM_Period = 999;  // 0~999,共1000个点
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    
    // 2. 配置PWM通道
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 500;  // 初始50%占空比
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    
    // 3. 设置死区时间
    // 200ns死区,系统时钟72MHz,每个计数周期13.89ns
    // 需要计数 = 200ns / 13.89ns ≈ 14.4,取15
    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 = 15;  // 对应约208ns
    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
    TIM_BDTRInit(TIM1, &TIM_BDTRInitStructure);
    
    // 4. 启动
    TIM_Cmd(TIM1, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

// 设置占空比函数
void Set_Duty(uint16_t duty)
{
    // 限制范围:5%~95%
    if(duty < 50) duty = 50;
    if(duty > 950) duty = 950;
    
    TIM_SetCompare1(TIM1, duty);
}

说个细节:代码里我把占空比限制在5%~95%,不是100%。为什么?因为100%占空比意味着一直导通,死区时间就没意义了。万一此时发生短路,没有死区保护,MOS管直接烧。所以,永远别让占空比到100%。

4.6 总结一下

PWM调速,说白了就是三件事:

  • 频率:选20kHz以上,兼顾听感和效率
  • 占空比:留5%的余量,别用满
  • 死区时间:宁大勿小,保命要紧

嗯,这一章就到这儿。下一章咱们聊PID控制,那才是真正考验调参功夫的地方。到时候我会分享一个我调了三天三夜才搞定的案例,保证让你少走弯路。