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 | 大功率场合,美容仪少见 |
怎么调? 我一般这样操作:
- 先设一个保守值,比如500ns
- 用示波器看上下管的栅极波形,确保一个完全关断后另一个才导通
- 逐步减小死区时间,直到波形上出现“交叠”的临界点
- 在这个临界点基础上,再加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控制,那才是真正考验调参功夫的地方。到时候我会分享一个我调了三天三夜才搞定的案例,保证让你少走弯路。