1. PWM技术概述与单片机应用场景
PWM(Pulse Width Modulation)即脉冲宽度调制,是单片机控制领域最基础也最实用的技术之一。我第一次接触PWM是在大二做智能小车项目时,当时用51单片机通过PWM控制电机转速,那种通过代码改变硬件行为的奇妙体验至今难忘。简单来说,PWM就是通过快速开关数字信号,用不同占空比的方波来模拟连续变化的模拟量。
在实际工程中,PWM主要解决三类问题:
- 功率控制:比如LED调光、电机调速,传统模拟电路需要大功率电阻分压,而PWM只需改变占空比
- 信号生成:产生特定频率的波形(如蜂鸣器发声)
- 数模转换:当DAC模块不够用时,PWM+低通滤波可替代
以常见的STM32F103系列为例,其高级定时器(TIM1)和通用定时器(TIM2-TIM4)都支持PWM输出,最高分辨率可达16位。我在工业控制项目中实测发现,对于直流电机控制,10kHz的PWM频率配合12位分辨率就能实现非常平滑的转速调节。
2. PWM核心参数与硬件配置要点
2.1 关键参数解析
-
频率(Freq):决定PWM周期,计算公式为Freq = Timer_CLK / (PSC + 1) / (ARR + 1)
- 电机控制常用8-20kHz(超出人耳听觉范围)
- LED调光常用100-1kHz(避免可见闪烁)
-
占空比(Duty):高电平时间占比,Duty = CCR / (ARR + 1)
- STM32的CCR寄存器直接决定脉冲宽度
- 例:ARR=999,CCR=300时,占空比为30%
-
分辨率:可调节的最小占空比变化量
- 8位分辨率:256级(ARR=255)
- 12位分辨率:4096级(ARR=4095)
2.2 硬件配置实战
以STM32CubeMX配置TIM3_CH1输出PWM为例:
- 时钟树配置确保定时器时钟源正确(通常APB1总线)
- 定时器模式选择"PWM Generation CH1"
- 参数设置:
c复制htim3.Instance = TIM3; htim3.Init.Prescaler = 71; // 72MHz/(71+1)=1MHz htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 999; // 1MHz/1000=1kHz htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - 通道配置:
c复制sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // 初始占空比50% sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
关键提示:不同单片机厂商的PWM外设命名差异很大,ST的TIMx、ESP32的LEDC、Arduino的analogWrite()底层机制完全不同,但核心原理相通。
3. 典型应用场景与代码实现
3.1 LED呼吸灯效果
c复制// 渐变效果实现
void breath_led(void) {
static uint8_t dir = 0;
static uint16_t val = 0;
if(dir == 0) {
val += 10;
if(val >= 1000) dir = 1;
} else {
val -= 10;
if(val == 0) dir = 0;
}
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, val);
HAL_Delay(10);
}
这个例子展示了如何通过动态调整CCR值实现平滑亮度变化。实际项目中我发现,当PWM频率低于100Hz时,人眼会明显察觉到闪烁,因此LED控制建议使用500Hz以上频率。
3.2 直流电机调速
c复制// 速度百分比转换
void set_motor_speed(uint8_t percent) {
if(percent > 100) percent = 100;
uint16_t ccr_val = __HAL_TIM_GET_AUTORELOAD(&htim3) * percent / 100;
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, ccr_val);
}
在电机控制中,H桥电路配合PWM可实现正反转和调速。需要注意的是,电机属于感性负载,PWM关闭瞬间会产生反向电动势,必须加入续流二极管保护电路。我曾因忽略这点烧毁过两个MOS管,教训深刻。
4. 进阶技巧与问题排查
4.1 多通道同步输出
某些场景需要多个PWM通道严格同步(如RGB调光),配置时需注意:
- 使用同一个定时器的不同通道
- 确保所有通道采用相同的ARR值
- 调用HAL_TIM_PWM_Start()时使用多通道版本
c复制// 启动TIM3的CH1和CH2
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1 | TIM_CHANNEL_2);
4.2 常见问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无PWM输出 | GPIO未重映射 | 检查AFIO配置 |
| 占空比异常 | CCR值超过ARR | 确保CCR ≤ ARR |
| 波形抖动 | 中断优先级冲突 | 调整定时器中断优先级 |
| 频率不准 | 时钟源配置错误 | 检查RCC时钟树 |
我在调试四轴飞行器电调时遇到过PWM输出不稳定的问题,最终发现是SysTick中断打断了PWM更新事件。通过将定时器中断优先级设置为最高解决了这个问题。
5. 硬件设计注意事项
-
驱动能力:单片机IO通常只能提供20mA左右电流,驱动大功率负载必须外接MOS管或驱动IC(如IR2104)
-
滤波设计:当PWM用于DAC功能时,RC滤波器的截止频率应小于PWM频率的1/10。例如10kHz PWM建议使用:
code复制R = 1kΩ, C = 10μF => fc ≈ 16Hz -
抗干扰措施:
- 长距离传输时加入光耦隔离(如PC817)
- 电机等大电流负载单独供电
- 在MOS管栅极串联10-100Ω电阻抑制振铃
记得第一次做BLDC电机驱动时,PWM信号线上的干扰导致控制器频繁重启。后来在信号线加入磁珠滤波并在PCB上加强地平面设计后,系统稳定性大幅提升。
