PWM(脉宽调制)是嵌入式开发中最常用的技术之一,它的核心思想是通过调节方波信号的占空比来模拟不同的电压值。想象一下老式的水龙头开关,快速开关就能控制出水量 - PWM就是这个原理的电子版。
在STM32中,PWM功能是通过定时器实现的。我刚开始接触时总搞混三个关键寄存器:
这里有个实用技巧:计算PWM频率时,记住这个公式:
c复制PWM频率 = 定时器时钟 / [(ARR+1)*(PSC+1)]
比如使用72MHz时钟,想要1kHz频率,可以设PSC=71,ARR=999:
(72,000,000)/(72*1000) = 1000Hz
HAL库配置PWM时有个坑我踩过:一定要先调用HAL_TIM_PWM_Init()初始化定时器,再调用HAL_TIM_PWM_Start()启动输出。有次调试两小时才发现漏了初始化步骤。
呼吸灯是PWM最直观的应用。我用PB8引脚(TIM4_CH3)实现时,发现几个关键点:
实测代码:
c复制// 指数亮度变化
for(int i=0; i<100; i++){
uint16_t val = exp(i/20.0)*10;
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, val);
HAL_Delay(10);
}
SG90舵机需要50Hz的PWM信号,但占空比范围很特殊(0.5ms-2.5ms)。我总结出快速配置法:
调试时发现舵机有"吱吱"声?可能是:
相比舵机,无刷电机需要更高频率的PWM(通常10kHz以上)。我在驱动小型无刷电机时,总结出三点经验:
c复制sDeadTimeConfig.DeadTime = 100; // 100ns死区
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sDeadTimeConfig);
c复制void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim1){
// 换相逻辑
}
}
通过PWM微调相电流,可以实现步进电机的细分控制。关键参数:
我在TMC5160驱动芯片上实现的配置:
c复制// 设置1/16微步
writeReg(TMC5160_CHOPCONF, 0x00010004);
// PWM频率设为20kHz
writeReg(TMC5160_PWMCONF, 0x000401C8);
调试PWM时,这些问题我遇到过太多次:
问题1:没有PWM输出
问题2:波形抖动严重
问题3:电机启动困难
有个实用技巧:用逻辑分析仪抓取PWM波形时,可以同时监测GPIO和定时器中断信号,这样能快速定位是配置问题还是驱动问题。