PWM脉冲宽度调制详解
笔记 / 嵌入式
引言
PWM(Pulse Width Modulation,脉冲宽度调制)是利用数字输出来模拟模拟电路控制的一种技术。它看似简单——只是控制高低电平的时间比例——但几乎是嵌入式系统中最常用的信号输出方式。从呼吸灯到电机调速,从舵机控制到音频合成,PWM 无处不在。
一、PWM 基本概念
关键参数
| 参数 | 定义 | 公式 |
|---|---|---|
| 周期(T) | 一个完整波形从开始到重复的时间 | T = 1/f |
| 频率(f) | 单位时间内完整周期的次数 | f = 1/T |
| 占空比(D) | 高电平时间占整个周期的比例 | D = Ton / T × 100% |
| 分辨率 | 占空比可调节的最小步距 | 由 ARR 决定 |
例:5V 系统,占空比 50% → 等效输出电压 ≈ 2.5V
二、STM32 PWM 生成原理
STM32 通过定时器输出比较的 PWM 模式生成 PWM 信号。核心寄存器:
| 寄存器 | 作用 |
|---|---|
TIMx_PSC(预分频器) | 对时钟频率进行分频 |
TIMx_ARR(自动重装载) | 决定 PWM 的周期/频率 |
TIMx_CCRx(捕获/比较) | 决定 PWM 的占空比 |
TIMx_CNT(计数器) | 当前计数值,不断与 CCRx 比较 |
工作流程(向上计数、PWM 模式 1)
高电平
↑ ┌──────┐ ┌──────┐
│ │ │ │ │
│─────┘ └────────┘ └────→
│ ← CCRx →←── (ARR-CCRx) ──→
│ ←─────── 一个周期 (ARR+1) ─────→
- 计数器 CNT 从 0 向上累加
- CNT < CCRx 时 → 输出高电平
- CNT ≥ CCRx 时 → 输出低电平
- CNT = ARR 时 → CNT 清零,开始下一个周期
三、频率与占空比计算公式
PWM 频率
PWM频率 = 定时器时钟频率 / [(PSC + 1) × (ARR + 1)]
占空比(PWM 模式 1)
占空比 = CCRx / (ARR + 1) × 100%
配置示例
目标:产生 1KHz、50% 占空比的 PWM
时钟:72MHz
• 设 PSC = 71 → 计数时钟 = 72MHz / 72 = 1MHz
• 设 ARR = 999 → PWM频率 = 1MHz / 1000 = 1KHz
• 设 CCRx = 500 → 占空比 = 500/1000 = 50%
四、频率与分辨率的权衡
这是 PWM 配置中最需要理解的设计权衡:
| 取舍 | 说明 |
|---|---|
| 频率 ↑ | ARR ↓ → 分辨率 ↓ |
| 分辨率 ↑ | ARR ↑ → 频率 ↓ |
示例:计数时钟 1MHz
若要 100KHz PWM → ARR=9,分辨率仅 10 级
若要 1KHz PWM → ARR=999,分辨率达 1000 级(0.1% 精度)
五、PWM 模式选择
| 模式 | 行为 | 适用场景 |
|---|---|---|
| PWM Mode 1 | CNT < CCR → 高电平 | 通用场合 |
| PWM Mode 2 | CNT ≥ CCR → 高电平 | 需要反相波形时 |
极性设置(TIM_OCPolarity_High / TIM_OCPolarity_Low)可进一步反转输出电平。
六、HAL 库配置与代码
① CubeMX 配置
- 选择定时器(如 TIM3),Clock Source 设为
Internal Clock - 选择通道(如 Channel 1),设为
PWM Generation CH1 - 设置参数:Prescaler、Counter Period(ARR)、Pulse(初始 CCRx)
② 呼吸灯示例
// 启动 PWM 输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
// 动态修改占空比实现呼吸灯
while (1) {
for (uint16_t i = 0; i < 1000; i += 10) {
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
HAL_Delay(20);
}
for (uint16_t i = 1000; i > 0; i -= 10) {
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
HAL_Delay(20);
}
}
③ 常用 API
| 函数/宏 | 功能 |
|---|---|
HAL_TIM_PWM_Start() | 启动 PWM 输出 |
HAL_TIM_PWM_Stop() | 停止 PWM 输出 |
__HAL_TIM_SET_COMPARE() | 动态修改占空比 |
__HAL_TIM_GET_AUTORELOAD() | 获取 ARR 值 |
七、典型应用
| 应用 | PWM 频率 | 占空比范围 | 说明 |
|---|---|---|---|
| LED 呼吸灯 | 1-2KHz | 0-100% | 频率高于人眼闪烁感知 |
| 舵机 SG90 | 50Hz(20ms周期) | 2.5%-12.5% | 0.5ms=0°,2.5ms=180° |
| 直流电机调速 | 16-20KHz | 0-100% | 避开人耳听觉范围 |
| 无源蜂鸣器 | 1-4KHz | 50% | 输出音频频率 |
八、舵机控制详解
舵机是 PWM 最经典的应用之一。以 SG90 为例:
周期 = 20ms(50Hz)
高电平持续 0.5ms → 舵机角度 0°
高电平持续 1.0ms → 舵机角度 45°
高电平持续 1.5ms → 舵机角度 90°
高电平持续 2.0ms → 舵机角度 135°
高电平持续 2.5ms → 舵机角度 180°
50Hz PWM 配置(72MHz 时钟):
PSC = 144 - 1 = 143 → CK_CNT = 72MHz / 144 = 500KHz
ARR = 10000 - 1 = 9999 → PWM周期 = 10000/500K = 20ms
CCR值范围 = 250 ~ 1250 → 0.5ms ~ 2.5ms
九、常见问题排查
| 问题 | 检查项 |
|---|---|
| 无 PWM 输出 | ①定时器时钟是否使能 ②GPIO 是否配置为复用功能 ③是否调用了 HAL_TIM_PWM_Start() |
| 频率偏差 | 检查 APB 预分频器设置、确认未启用 CKD 分频 |
| 占空比异常 | 确认 PWM 模式(Mode 1/2)与极性设置是否匹配 |
| 高级定时器无输出 | TIM1/TIM8 需设置 TIM_BDTR->MOE 位使能主输出 |
总结
PWM 是输出比较最实用的形态。掌握了频率、占空比、分辨率三者的关系,你就能用一根信号线控制 LED 的明暗、电机的快慢、舵机的角度——这是数字世界对模拟世界最优雅的控制方式。
控制不在于力的强弱,而在于节奏的精妙。 —— Iustitiae