STM32 HAL库实战:F103C8T6通过PWM精准控制SG90舵机角度
1. 硬件准备与基础概念
第一次接触STM32控制舵机时,我翻遍了实验室的零件箱,找出几样关键设备:一块蓝色封装的STM32F103C8T6最小系统板(江湖人称"蓝莓派")、一个9克重的SG90舵机、几根红黑相间的杜邦线。这里特别提醒新手,舵机的三根线中棕色永远是接地线,红色接电源(4.8-6V),橙色才是信号线——这个配色方案就像交通信号灯一样直观。
SG90舵机的工作原理其实很有趣。它内部有个微型直流电机配合减速齿轮组,通过电位器反馈位置构成闭环控制。当我们给舵机发送特定周期的PWM信号时,控制板会比较信号脉宽与电位器反馈电压,驱动电机转到指定角度。这种设计让舵机既能保持位置又具备一定扭矩,非常适合需要精确角度控制的场景。
必备硬件清单:
- STM32F103C8T6开发板(核心工作频率72MHz)
- SG90舵机(工作电压4.8-6V)
- 5V/2A外接电源(避免板载USB供电不足)
- ST-Link V2下载器
- 面包板与连接线
注意:直接用开发板的3.3V供电可能导致舵机扭矩不足甚至无法转动,这是我调试时踩过的第一个坑。后来用万用表测量发现,舵机在空载时电流就达100mA,转动瞬间峰值可达300mA,远超板载LDO的负载能力。
2. CubeMX工程配置详解
打开CubeMX时,我习惯先进行三个关键配置:RCC时钟源选择外部晶振(8MHz)、SYS调试接口设为SWD模式、时钟树配置确保最终APB1总线频率为72MHz。这些基础设置就像盖房子的地基,一旦出错后续所有功能都可能异常。
PWM定时器配置步骤:
- 在Pinout界面启用TIM2通道1(PA0引脚)
- 在Configuration标签页配置TIM2参数:
- Prescaler(预分频值):719
- Counter Mode(计数模式):Up(向上计数)
- Period(自动重装载值):1999
- Pulse(初始脉冲值):50(对应0.5ms脉宽)
- CH Polarity(通道极性):High(高电平有效)
这里有个计算技巧:PWM频率=72MHz/(719+1)/(1999+1)=50Hz。为什么选择50Hz?因为SG90舵机要求控制信号周期为20ms(1/50Hz),这是行业标准。实际调试时,我用逻辑分析仪抓取波形,发现当占空比在2.5%-12.5%之间变化时(对应0.5ms-2.5ms脉宽),舵机角度会从0°平滑过渡到180°。
时钟树配置要点:
- HCLK设为72MHz(最大允许值)
- APB1 Prescaler设为2(定时器时钟36MHz×2=72MHz)
- APB2 Prescaler保持1(保持72MHz)
生成代码前记得勾选"Generate peripheral initialization as a pair of .c/.h files",这样TIM的配置会单独成文件,方便后期维护。我遇到过因误操作导致CubeMX配置丢失的情况,所以现在养成了生成代码前必点"Project > Save Project"的习惯。
3. PWM控制代码实战
打开生成的Keil工程,在main.c中找到/* USER CODE BEGIN 2 */区域,添加PWM启动代码:
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 启动TIM2通道1的PWM输出接下来创建角度控制函数。根据实测数据,SG90的脉宽与角度呈线性关系,我们可以封装一个实用函数:
void Set_Servo_Angle(TIM_HandleTypeDef *htim, uint32_t Channel, float angle) { if(angle > 180) angle = 180; if(angle < 0) angle = 0; // 角度转脉冲计算公式:Pulse = (angle/180)*200 + 50 uint32_t pulse = (uint32_t)((angle/180.0)*200 + 50); __HAL_TIM_SET_COMPARE(htim, Channel, pulse); }这个函数的神奇之处在于将0-180°映射到50-250的寄存器值。举个例子:
- 输入90°时:(90/180)*200+50=150,对应1.5ms脉宽(正好是中位)
- 输入180°时:(180/180)*200+50=250,对应2.5ms脉宽
在main循环中测试不同角度:
while (1) { Set_Servo_Angle(&htim2, TIM_CHANNEL_1, 0); // 归零 HAL_Delay(1000); Set_Servo_Angle(&htim2, TIM_CHANNEL_1, 90); // 直角 HAL_Delay(1000); Set_Servo_Angle(&htim2, TIM_CHANNEL_1, 180); // 极限位置 HAL_Delay(1000); }调试时发现舵机在极限角度会有"吱吱"的堵转声,这是因为它仍在试图修正位置。解决方法是在机械结构上留出2-3°余量,或者软件限制最大角度为175°。
4. 进阶技巧与问题排查
多舵机控制方案:当需要控制多个舵机时,建议:
- 使用不同定时器的PWM通道(如TIM2_CH1, TIM3_CH2等)
- 配置相同基准频率(50Hz)
- 为每个舵机单独供电,共地处理
我曾用TIM2的四个通道同时驱动四个SG90,发现当所有舵机同步转动时会出现电源跌落。后来改用外接5V/3A电源并增加1000μF电容后问题解决。
常见故障排查:
舵机无反应:
- 检查信号线是否接在PWM引脚
- 用示波器验证PWM波形
- 测量供电电压是否≥4.8V
角度不准确:
- 重新校准脉宽范围(有些舵机需要0.6ms-2.4ms)
- 检查齿轮是否打滑
- 确保PWM周期严格20ms
舵机发热严重:
- 避免长时间保持在极限位置
- 检查机械负载是否过大
- 考虑加装散热片
性能优化技巧:
- 使用DMA自动更新CCR寄存器实现平滑运动
- 采用余弦加速度曲线减少机械冲击
- 在定时器中断中实现舵机队列控制
记得有次项目需要舵机快速扫频,我直接在主循环中修改CCR值,结果出现严重抖动。后来改用TIM的更新中断,每20ms精确调整一次占空比,运动立刻变得丝滑流畅。这个经验告诉我:涉及精确时序的控制,一定要善用硬件定时器。