3. PWM生成原理:定时器配置、占空比与频率计算、互补输出与死区插入
各位同学,今天我们来聊聊PWM生成。这玩意儿在电机控制里,可以说是最基础也最关键的一环。我刚开始做电机驱动那会儿,总觉得PWM不就是方波嘛,高低电平来回跳,有啥难的?结果第一次上板子,电机嗡嗡响就是不转,查了半天才发现是定时器配置出了问题。嗯,从那以后我再也不敢小看PWM的配置了。
3.1 PWM的本质:说白了就是个计数器
PWM的全称是脉冲宽度调制,说白了就是通过调整高电平的宽度来控制平均电压。你想想看,电机要转得快,就给高电平时间长一点;要转得慢,就给短一点。这个「给」的过程,就是靠定时器来完成的。
我习惯把定时器想象成一个「自动数数的计数器」。它从0开始往上数,数到某个设定值就重置,然后重新数。在这个过程中,我们比较计数器的值和另一个设定值,如果计数器小于这个值,输出高电平;大于这个值,输出低电平。这就是PWM的基本原理。
核心公式:
- PWM频率 = 定时器时钟频率 / (预分频系数 + 1) / (自动重装载值 + 1)
- 占空比 = 比较值 / (自动重装载值 + 1) × 100%
3.2 定时器配置:别让细节坑了你
配置定时器生成PWM,我一般分三步走。第一步,选定时器;第二步,设参数;第三步,启动输出。听起来简单,但每一步都有坑。
第一步:选定时器
STM32的定时器分好几种:基本定时器、通用定时器、高级定时器。做电机控制,我建议直接用高级定时器,比如TIM1或TIM8。为什么?因为它们支持互补输出和死区插入,这两样东西在电机驱动里几乎是标配。我曾经图省事用通用定时器做H桥驱动,结果死区得靠软件延时,不仅麻烦,还不安全。
第二步:设参数
参数设置主要涉及三个寄存器:PSC(预分频器)、ARR(自动重装载值)、CCR(捕获比较值)。
| 参数 | 作用 | 典型值 |
|---|---|---|
| PSC | 分频时钟,降低计数频率 | 71(72MHz时钟分频后1MHz) |
| ARR | 决定PWM周期 | 999(1kHz PWM) |
| CCR | 决定占空比 | 0~999(0%~100%) |
举个例子,我想生成1kHz的PWM,系统时钟72MHz。先设PSC=71,这样定时器时钟变成1MHz。再设ARR=999,这样计数器从0数到999,总共1000个时钟周期,频率就是1MHz/1000=1kHz。完美。
第三步:启动输出
这一步容易忘。配置完寄存器后,记得要调用HAL_TIM_PWM_Start()。我刚开始学的时候,配置了半天,输出口就是没波形,查了半小时才发现忘了启动。嗯,这种低级错误,犯过一次就记住了。
// 以STM32 HAL库为例
TIM_HandleTypeDef htim1;
TIM_OC_InitTypeDef sConfigOC;
// 1. 初始化定时器
htim1.Instance = TIM1;
htim1.Init.Prescaler = 71; // 72MHz / (71+1) = 1MHz
htim1.Init.Period = 999; // 1MHz / (999+1) = 1kHz
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&htim1);
// 2. 配置PWM通道
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; // 占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
// 3. 启动PWM输出
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
3.3 占空比与频率计算:别搞反了
占空比和频率,这两个概念容易混淆。频率决定电机转得快慢的「上限」,占空比决定「实际速度」。举个例子,你让电机跑1kHz的PWM,占空比50%,那平均电压就是电源电压的一半。如果占空比调到100%,那就是满电压。
我遇到过一个问题:电机低速运行时抖动厉害。查了半天,发现是PWM频率太低了。低频PWM会导致电机电流断续,转矩脉动大。后来我把频率从100Hz提高到10kHz,问题就解决了。所以,电机控制一般建议PWM频率在10kHz~20kHz之间,既听不到噪音,又能保证电流连续。
我的经验:
占空比计算时,注意CCR值不能超过ARR值。如果CCR=ARR,那就是100%占空比;如果CCR=0,那就是0%。但实际应用中,我一般不会让占空比到0%或100%,留点余量,防止电机失控。
3.4 互补输出与死区插入:保护你的MOS管
做电机驱动,尤其是H桥或三相逆变器,互补输出是必须的。什么叫互补输出?就是一个通道输出高电平时,另一个通道输出低电平,两者正好相反。这样就能控制上下桥臂交替导通。
但这里有个问题:上下桥臂不能同时导通,否则会短路。MOS管的开关需要时间,从导通到关断不是瞬间完成的。如果上桥臂还没完全关断,下桥臂就导通了,那电流就会直通,烧管子。这就是死区插入的意义——在切换时插入一段「都关断」的时间。
死区时间怎么设?我一般根据MOS管的datasheet来算。比如IRF540的关断延迟时间典型值是50ns,那我至少设100ns的死区。实际项目中,我习惯设到500ns~1μs,留点安全余量。死区太短不安全,太长会影响波形质量,这是个权衡。
// 配置互补输出和死区
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
sBreakDeadTimeConfig.DeadTime = 100; // 死区时间,单位取决于定时器时钟
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
// 启动互补输出
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
警告:
死区时间不是越大越好。死区期间,上下桥臂都关断,电机电流会通过体二极管续流,这会增加损耗和发热。我曾经在一个项目中把死区设到3μs,结果MOS管温度飙到80度。后来优化到500ns,温度降到50度。所以,死区时间要在安全和效率之间找平衡。
3.5 知识体系总览
下面这张图是我自己画的PWM生成知识体系,你可以把它当作一个检查清单。每次配置PWM时,按这个流程走一遍,基本不会漏东西。
这张图把PWM生成的三个核心模块串起来了。左边是定时器配置,中间是频率占空比计算,右边是互补输出和死区。做项目时,按这个顺序来,基本不会出错。
好了,这一章的内容就到这里。PWM生成是电机控制的基础,配置好了,后面的电流环、速度环才能跑得稳。下一章我们聊聊电流采样,那又是另一个有意思的话题。
公众号:蓝海资料掘金营,微信deep3321