1. STM32 PWM功能基础解析
PWM(Pulse Width Modulation)即脉冲宽度调制,是嵌入式系统中控制模拟电路的经典数字技术。在STM32微控制器中,PWM功能通过定时器模块实现,能够生成精确的方波信号,广泛应用于电机控制、LED调光、电源转换等领域。
1.1 PWM核心参数与工作原理
PWM信号有三个关键参数:
- 频率(Frequency):信号周期数的倒数,决定信号变化的快慢
- 占空比(Duty Cycle):高电平时间占整个周期的百分比,决定有效功率
- 分辨率(Resolution):占空比可调节的最小步长,影响控制精度
STM32的定时器通过自动重装载寄存器(ARR)控制PWM频率,通过捕获/比较寄存器(CCRx)控制占空比。计数器从0开始递增,当计数值小于CCRx时输出高电平,大于CCRx但小于ARR时输出低电平,如此循环形成PWM波形。
提示:STM32的定时器时钟源通常来自APB总线,经过预分频器后作为计数器的实际时钟。计算PWM频率时需考虑这些分频系数。
1.2 STM32定时器的PWM模式
STM32提供两种主要的PWM模式:
-
边沿对齐模式(Edge-aligned):
- 向上计数:计数器从0增加到ARR,然后归零
- 向下计数:计数器从ARR减少到0,然后重置
- 波形变化发生在计数方向改变时
-
中心对齐模式(Center-aligned):
- 计数器先向上计数到ARR,再向下计数到0
- 波形变化在计数达到CCRx值时发生
- 适合电机控制等需要对称波形的应用
以TIM4为例,配置PWM模式1时:
- 当CNT < CCRx:输出有效电平(通常为高)
- 当CNT ≥ CCRx:输出无效电平
- CNT达到ARR时产生更新事件并重置
2. 硬件环境搭建与CubeMX配置
2.1 硬件连接准备
以NUCLEO-H745ZI-Q开发板为例,TIM4通道1对应引脚PD12(CN10接口的21脚)。实际项目中需根据具体MCU型号查阅数据手册确认定时器通道与引脚的对应关系。
典型连接方式:
- PWM输出引脚 → RC滤波器(转换为模拟信号)
- 滤波后信号 → 功率驱动电路或直接连接负载
- 示波器探头连接PWM输出引脚用于调试
2.2 STM32CubeMX基础配置
-
时钟树配置:
- 设置系统时钟为最高频率(如STM32H7可达480MHz)
- 确认定时器时钟源频率(APB总线频率)
-
定时器参数设置:
c复制htim4.Instance = TIM4; htim4.Init.Prescaler = 1080-1; // 预分频系数 htim4.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数 htim4.Init.Period = 2000-1; // ARR值 htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; -
PWM通道配置:
c复制sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 1000; // 初始CCR值 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 有效电平为高 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1); -
DMA配置(可选):
对于需要频繁更新PWM参数的场景,可配置DMA自动传输CCR值:c复制hdma_tim4_ch1.Instance = DMA1_Channel1; hdma_tim4_ch1.Init.Request = DMA_REQUEST_TIM4_CH1; hdma_tim4_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_tim4_ch1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_tim4_ch1.Init.MemInc = DMA_MINC_ENABLE; hdma_tim4_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_tim4_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_tim4_ch1.Init.Mode = DMA_CIRCULAR; // 循环模式 hdma_tim4_ch1.Init.Priority = DMA_PRIORITY_HIGH;
3. PWM输出实战代码实现
3.1 基础PWM输出
完成CubeMX配置后,在main函数中启动PWM:
c复制HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // 启动PWM
// 动态调整占空比
uint16_t duty = 0;
while (1) {
duty = (duty + 10) % 2000;
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, duty);
HAL_Delay(10);
}
3.2 使用DMA的PWM波形生成
对于复杂波形(如正弦波),可使用DMA自动更新CCR值:
-
定义波形数据数组:
c复制#define WAVE_POINTS 36 ALIGN_32BYTES(uint32_t SineWave[WAVE_POINTS]) = { 14999, 17603, 20128, 22498, 24640, 26488, 27988, 29093, 29770, 29998, 29770, 29093, 27988, 26488, 24640, 22498, 20128, 17603, 14999, 12394, 9869, 7499, 5357, 3509, 2009, 904, 227, 1, 227, 904, 2009, 3509, 5357, 7499, 9869, 12394, 14999 }; -
启动DMA传输:
c复制SCB_EnableICache(); SCB_EnableDCache(); SCB_CleanDCache_by_Addr((uint32_t*)SineWave, WAVE_POINTS); HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1, SineWave, WAVE_POINTS); -
DMA完成回调处理:
c复制void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM4) { // 可在此添加波形结束处理逻辑 } }
3.3 互补PWM与死区时间
对于电机驱动等需要互补PWM的场景,高级定时器(如TIM1/TIM8)支持:
c复制// 配置死区时间
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 45; // 死区时间值
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
[HAL](https://taotoken.net/?utm_source=hardware)_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
// 启动互补PWM
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
4. 高级应用与性能优化
4.1 动态频率调整
通过实时修改ARR值可改变PWM频率:
c复制void Set_PWM_Frequency(TIM_HandleTypeDef *htim, uint32_t freq) {
uint32_t timer_clock = HAL_RCC_GetPCLK1Freq() * 2; // 假设APB1 prescaler=1
uint32_t prescaler = htim->Instance->PSC;
uint32_t arr = (timer_clock / (prescaler + 1) / freq) - 1;
__HAL_TIM_SET_AUTORELOAD(htim, arr);
}
4.2 高分辨率PWM
当需要更高分辨率时:
- 提高定时器时钟频率(使用APB总线最高分频)
- 增大ARR值(但会降低PWM频率)
- 使用硬件特性(如STM32H7的HRTIM)
计算分辨率公式:
code复制分辨率(bit) = log2(ARR + 1)
4.3 同步多个PWM输出
通过定时器主从模式同步多个PWM:
- 配置一个定时器为主模式(Master)
- 其他定时器为从模式(Slave)
- 使用TRGO信号触发同步
c复制// 主定时器配置
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
// 从定时器配置
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR0; // 根据定时器关联选择ITRx
HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig);
5. 调试技巧与常见问题
5.1 PWM输出异常排查步骤
-
无输出:
- 确认定时器时钟已使能
- 检查GPIO是否配置为复用功能
- 验证PWM启动函数是否被调用
- 测量引脚电压排除硬件问题
-
频率不正确:
- 重新计算时钟树分频系数
- 检查ARR和PSC寄存器值
- 确认没有其他代码意外修改定时器配置
-
占空比异常:
- 确保CCR值不超过ARR
- 检查PWM极性设置
- 验证DMA传输数据是否正确
5.2 示波器测量要点
- 触发模式:建议使用边沿触发
- 时基设置:至少显示3-5个完整PWM周期
- 测量参数:
- 频率(Period)
- 占空比(Duty)
- 上升/下降时间(Rise/Fall)
- 过冲(Overshoot)
5.3 典型应用场景优化
-
电机控制:
- 使用中心对齐模式减少电磁干扰
- 添加死区时间防止上下管直通
- 采用互补PWM提高驱动效率
-
LED调光:
- PWM频率建议在200Hz-20kHz之间(避免可见闪烁)
- 使用Gamma校正使亮度变化更自然
- 对于RGB LED,需分别控制三个通道
-
电源转换:
- 选择足够高的PWM分辨率(通常≥10bit)
- 考虑加入斜率补偿防止次谐波振荡
- 使用硬件触发ADC同步采样
通过合理配置STM32的PWM功能,开发者可以实现高效精确的数字控制。实际项目中建议结合硬件特性(如DMA、HRTIM等)和具体应用需求,选择最优的实现方案。
