4、PWM调制技术:PWM原理、占空比与频率的关系、分辨率选择

好,咱们进入第四讲。前面聊了电机选型和驱动电路,现在该聊聊怎么让电机转得「听话」了。说白了,就是PWM调制技术。

PWM这东西,你肯定不陌生。但用在电动牙刷这种小玩意儿上,讲究还挺多。我刚开始做这个项目时,觉得PWM嘛,不就是给个方波嘛,能有多难?结果第一次调出来的牙刷,震得我手都麻了,噪音还大。后来才明白,频率、占空比、分辨率,这三者得配合好才行。

4.1 PWM原理:其实就是个开关

PWM的全称是Pulse Width Modulation,脉冲宽度调制。原理很简单:用数字信号模拟模拟信号。

你想想看,单片机只能输出高电平和低电平,没法直接输出3.5V这种中间值。那怎么办?快速开关!

比如,你要让电机转一半的力气。那就让高电平占一半时间,低电平占一半时间。电机因为有惯性,不会跟着每个脉冲跳,它感受到的是平均电压。

核心公式:

平均电压 = 高电平电压 × 占空比

占空比 = 高电平时间 / 整个周期时间

举个例子:供电是5V,占空比60%。那电机感受到的平均电压就是5V × 60% = 3V。嗯,就这么简单。

我在项目中遇到过一个问题:有些新手工程师觉得PWM频率越高越好,结果选了个几百kHz的。电机倒是安静了,但驱动芯片烫得能煎鸡蛋。为什么?因为开关损耗上去了。所以频率不是越高越好,得平衡。

4.2 占空比与频率的关系:别搞混了

这两个概念,我见过太多人搞混了。咱们捋一捋。

频率:一秒钟开关多少次。单位是Hz。
占空比:每次开关中,高电平占多少比例。单位是百分比。

频率决定了「开关的快慢」,占空比决定了「力气的大小」。两者是独立的,但实际应用中会互相影响。

举个例子:

  • 频率20kHz,占空比50%:每秒钟开关20000次,每次高电平占一半时间。
  • 频率20kHz,占空比80%:每秒钟还是开关20000次,但高电平占了八成时间。

你看,频率没变,但电机转速变了。反过来,频率变了,占空比不变,电机转速也不变。

我的经验:

电动牙刷的PWM频率,我一般选在20kHz到40kHz之间。为什么?

  • 低于20kHz:人耳能听到,会有「滋滋」声,用户体验差。
  • 高于40kHz:开关损耗增加,电池续航下降。

20kHz刚好在人类听觉上限附近,大部分用户听不到。当然,年轻人可能还能听到一点点,但已经可以接受了。

4.3 分辨率选择:精度和资源的博弈

分辨率,说白了就是占空比能调多细。

8位分辨率:占空比可以调0/255到255/255,共256级。
10位分辨率:占空比可以调0/1023到1023/1023,共1024级。
16位分辨率:占空比可以调0/65535到65535/65535,共65536级。

分辨率越高,控制越精细。但代价是什么?

  • 定时器资源占用更多
  • 中断频率可能更高
  • 代码复杂度增加

我建议电动牙刷选8位或10位分辨率就够了。为什么?

你想想看,电动牙刷的振动频率控制,其实不需要那么精细。用户能感受到的振动变化,大概在5%的占空比变化以上。8位分辨率有256级,每级变化约0.4%,已经远远超过人眼(或者说人手)能分辨的精度了。

我曾经踩过的坑:

有一次我为了追求「极致控制」,选了16位分辨率。结果定时器溢出中断频繁触发,导致主循环被频繁打断,按键响应都变慢了。后来查了半天才发现是分辨率太高惹的祸。

所以,别盲目追求高分辨率。够用就好。

4.4 实际代码示例:STM32的PWM配置

咱们以STM32为例,看看怎么配置PWM。我用的是HAL库,但原理都一样。

// 定时器句柄
TIM_HandleTypeDef htim2;

// PWM初始化函数
void PWM_Init(void)
{
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    // 定时器基础配置
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 71;          // 72MHz / (71+1) = 1MHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 999;            // 1MHz / (999+1) = 1kHz
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&htim2);
    
    // PWM通道配置
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 500;              // 占空比 500/1000 = 50%
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
    
    // 启动PWM
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}

// 动态修改占空比
void PWM_SetDuty(uint16_t duty)
{
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, duty);
}

这段代码里,Prescaler和Period决定了PWM频率。Prescaler=71,Period=999,算下来频率是1kHz。但前面我说了,电动牙刷要用20kHz以上,所以实际项目中我会把Period改成49,这样频率就是20kHz了。

频率计算公式:

PWM频率 = 定时器时钟 / (Prescaler + 1) / (Period + 1)

占空比 = Pulse / (Period + 1) × 100%

你看,Prescaler和Period配合,就能得到想要的频率。Pulse就是占空比控制值。

4.5 避坑指南:PWM常见问题

做PWM控制,有几个坑我帮你们踩过了,直接说结论:

  1. 死区时间:如果驱动电路是半桥或全桥,一定要加死区时间。否则上下管直通,瞬间烧管子。我吃过这个亏,一次就烧了三个MOS管。
  2. PWM引脚复用:很多MCU的PWM引脚和普通IO复用。记得配置成复用功能,不然输出不了波形。
  3. 负载变化:电机启动时电流大,PWM占空比不要从0直接跳到100%。我习惯做软启动,比如500ms内从0逐渐升到目标值。
  4. 滤波电容:PWM输出端加个小电容(比如0.1μF),能滤掉高频噪声。但别太大,否则波形会变圆,影响控制精度。

嗯,PWM这块就聊这么多。下一章咱们讲PID控制算法,那才是让牙刷振动「指哪打哪」的关键。到时候见。