江协科技/江科大-STM32入门教程-13.TIM输出比较实战:从PWM基础到电机驱动闭环设计
1. PWM基础与TIM输出比较原理我第一次接触STM32的PWM功能时完全被那些专业术语搞懵了。后来发现PWM其实就是用数字信号模拟模拟量的一种巧妙方法。想象一下你家客厅的调光灯泡——虽然它实际只有开和关两种状态但通过快速开关就能让你感觉灯光在变亮或变暗这就是PWM的精髓。STM32的定时器TIM就像个精准的秒表而输出比较功能则是这个秒表上的闹钟功能。当计数器CNT的值和捕获/比较寄存器CCR的值相等时就会触发我们预设的动作。通用定时器有4个独立通道意味着你可以同时控制4个不同的设备比如让LED呼吸、电机变速、舵机转向这些都能同步进行。输出比较有8种工作模式但最常用的是PWM模式1和模式2。它们的区别就像镜子里的影像——模式1是原版模式2则是反相版。我刚开始总记混后来用了个土办法把PWM模式1记作小于CCR就有效模式2则是大于CCR才有效。2. 呼吸灯实战从配置到调参用PWM实现呼吸灯是新手入门的绝佳实验。记得我第一次做这个实验时LED要么常亮要么常灭完全看不出呼吸效果。后来发现是ARR值设得太小导致频率过高人眼无法分辨。具体配置步骤如下开启TIM3时钟和GPIOB时钟以PB5为例配置PB5为复用推挽输出模式初始化时基单元设置ARR999PSC7172MHz主频下产生1kHz PWM配置PWM模式1极性为高电平有效启用预装载和定时器// 关键代码示例 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC2Init(TIM3, TIM_OCInitStructure);调试时遇到过两个典型问题一是LED亮度变化不线性发现是直接用线性值设置CCR后来改用查表法解决二是低亮度时闪烁通过增大ARR值提高分辨率来改善。实测ARR999时分辨率约0.1%足够大多数应用场景。3. 舵机角度控制详解玩机器人项目时舵机控制是必学技能。普通舵机需要50Hz的PWM信号周期20ms其中高电平宽度在0.5ms-2.5ms对应0-180度。刚开始我直接用公式计算结果舵机抖动严重后来发现是中断干扰导致脉冲不稳定。硬件连接要注意三点电源必须足够建议单独供电信号线接任意GPIO需支持定时器输出务必共地配置要点// 50Hz PWM配置72MHz主频 TIM_TimeBaseStructure.TIM_Period 20000 - 1; // ARR TIM_TimeBaseStructure.TIM_Prescaler 72 - 1; // PSC角度转换公式uint16_t pulseWidth 500 (angle * 2000) / 180; // 单位us TIM_SetComparex(TIMx, pulseWidth * 72 / 1000);曾遇到过一个坑用高级定时器时忘了配置重复计数器导致舵机偶尔抽搐。后来发现高级定时器的TIM1/TIM8需要额外设置TIM_RepetitionCounter0才能稳定工作。4. 直流电机调速与TB6612驱动直流电机控制比舵机复杂得多需要驱动电路。TB6612是我最推荐的驱动芯片体积小、效率高还内置了热保护。第一次使用时因为没接VM电机电源调试了半天才发现问题。典型接线方式VM接7-12V电源根据电机额定电压VCC接3.3V逻辑电源STBY接高电平PWMA接PWM信号AIN1/AIN2接GPIO控制方向控制逻辑真值表AIN1AIN2PWMA电机状态00X刹车011反转010刹车101正转100刹车闭环调速需要编码器反馈这里分享一个简易PID实现typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; float PID_Update(PID_Controller* pid, float error) { pid-integral error; float derivative error - pid-prev_error; pid-prev_error error; return pid-Kp * error pid-Ki * pid-integral pid-Kd * derivative; }调试电机时发现PWM频率很关键太低会听到电机啸叫太高会导致驱动芯片发热。对于普通直流电机5-20kHz是比较理想的频率范围。