2. PWM调速原理:占空比概念、频率选择、PWM生成方式(硬件/软件)

好,咱们直接切入正题。PWM,全称叫脉冲宽度调制。说白了,就是通过控制一个方波信号里“高电平”占了多少时间,来模拟出不同的电压效果。你想想看,美容仪的振动马达要转得快还是慢,靠的就是这个。

2.1 占空比:核心中的核心

占空比,英文叫Duty Cycle。它指的是在一个周期内,高电平时间占总周期的百分比。

  • 占空比 = 高电平时间 / 周期 × 100%
  • 占空比 0%:一直低电平,马达不转。
  • 占空比 100%:一直高电平,马达全速转。
  • 占空比 50%:一半时间通电,一半时间断电。马达转速大概在一半左右。

我在项目中遇到过一个问题:有次用PWM控制一个微型振动马达,占空比从0%调到100%,结果马达在30%以下根本不转。后来查了数据手册才发现,马达有个“启动电压”门槛。低于这个电压,它连动都不动。嗯,这里要注意,占空比和最终转速并不是严格的线性关系,尤其是小占空比区域。

核心公式:

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

比如5V供电,占空比60%,平均电压就是3V。马达感受到的就是这个等效电压。

2.2 频率选择:不是越高越好,也不是越低越好

频率,就是PWM信号每秒钟重复的次数。单位是Hz。频率选多少,直接影响马达的振动效果和噪音。

我个人习惯把频率分成三个区间来看:

频率范围 特点 适用场景
低频(20Hz - 200Hz) 马达能明显感觉到“一顿一顿”的,噪音大,有嗡嗡声 老式振动器、低端玩具
中频(200Hz - 2kHz) 振动比较平滑,噪音适中 大部分美容仪、按摩器
高频(2kHz - 20kHz) 振动非常平滑,但可能进入人耳可听范围,产生啸叫 精密仪器、需要静音的场合

为什么会这样?因为马达本身有机械惯性。频率太低,每次通电断电之间,马达有足够时间停下来,所以你会感觉到“突突突”的冲击。频率高了,马达还没完全停下来,下一个脉冲又来了,所以振动就平滑了。

我曾经踩过一个坑:为了追求静音,把PWM频率设到了18kHz。结果美容仪工作时发出尖锐的啸叫声,用户投诉说像蚊子飞。后来才发现,18kHz虽然人耳不太敏感,但马达的线圈和外壳会共振,反而放大了噪音。最后我换到了25kHz,问题解决。所以,频率选择要避开马达自身的机械谐振点。

我的建议:对于美容仪振动马达,起始频率选1kHz左右。如果觉得噪音大,往上调到2kHz-4kHz。如果觉得振动感太“硬”,可以适当降低频率。没有绝对标准,得靠耳朵和手感去调。

2.3 PWM生成方式:硬件PWM vs 软件PWM

生成PWM信号,主要有两种方式。我分别说说它们的优缺点。

2.3.1 硬件PWM

硬件PWM,就是利用单片机内部集成的定时器/计数器模块,自动产生PWM波形。你只需要设置好占空比和频率,剩下的硬件自己搞定,CPU不用管。

  • 优点:
    • 精度高,频率稳定,不受程序执行干扰。
    • 不占用CPU时间,可以同时控制多路PWM。
    • 分辨率高,通常能做到8位、16位甚至更高。
  • 缺点:
    • 受限于单片机引脚,通常只有特定几个引脚支持硬件PWM。
    • 配置稍微复杂一点,需要看数据手册的定时器部分。

我一般优先用硬件PWM。比如STM32的TIM定时器,配置好预分频和自动重装载值,再设置比较值,PWM就出来了。代码大概长这样:

// 以STM32为例,配置TIM2通道1输出PWM
// 假设系统时钟72MHz,预分频器72-1,自动重装载1000-1
// 那么PWM频率 = 72MHz / 72 / 1000 = 1kHz
// 占空比 = 比较值 / 自动重装载值

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_TimeBaseStructure.TIM_Prescaler = 71;        // 预分频
TIM_TimeBaseStructure.TIM_Period = 999;           // 自动重装载值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

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(TIM2, &TIM_OCInitStructure);

TIM_Cmd(TIM2, ENABLE);

2.3.2 软件PWM

软件PWM,就是靠CPU在程序里不断翻转IO口电平,模拟出PWM波形。通常用定时器中断或者延时循环来实现。

  • 优点:
    • 任意IO口都可以输出PWM,不受硬件限制。
    • 实现简单,几行代码就能跑起来。
  • 缺点:
    • 占用CPU时间,频率高了CPU就干不了别的了。
    • 精度和稳定性差,容易受其他中断影响。
    • 同时控制多路PWM时,代码复杂度急剧上升。

软件PWM的典型代码,用延时实现:

// 软件PWM,占空比50%,频率1kHz
// 周期 = 1ms,高电平500us,低电平500us

void soft_pwm_set(uint8_t duty) {
    // duty范围0-100
    uint16_t high_time = duty * 10;   // 单位us
    uint16_t low_time = (100 - duty) * 10;

    GPIO_SetBits(GPIOA, GPIO_Pin_0);   // 拉高
    delay_us(high_time);
    GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 拉低
    delay_us(low_time);
}

// 注意:这个函数必须在主循环里不断调用,否则PWM会停止

警告:软件PWM有一个致命问题——如果程序里还有其他耗时操作(比如按键扫描、显示刷新),PWM波形就会变形。我曾经在一个项目里用软件PWM控制马达,结果一按按键,马达转速就抖一下。后来换成硬件PWM,世界清净了。

2.4 如何选择?我的实战经验

给你一个简单的决策树:

  • 如果单片机有硬件PWM引脚,且引脚够用 → 无脑选硬件PWM。省心、稳定、精度高。
  • 如果硬件PWM引脚不够用,但只需要控制1-2路马达 → 可以用软件PWM,但频率别太高,1kHz以内还行。
  • 如果需要同时控制3路以上马达,且要求高精度 → 换单片机,或者加外部PWM驱动芯片(比如PCA9685)。

我记得有一次做一款三头美容仪,需要同时控制三个马达独立振动。单片机只有两路硬件PWM,第三路用软件PWM死活调不好。最后加了一颗PCA9685,I2C接口,16路PWM输出,完美解决。成本多了几块钱,但开发时间省了一周。

好了,PWM调速的原理就讲到这里。下一节咱们聊聊具体的马达驱动电路设计,包括H桥和MOS管选型。到时候见。