STM32控制舵机完全指南:从原理到实战
一、舵机基础原理
1.1 舵机是什么?
舵机(Servo Motor)是一种位置伺服驱动器,它可以根据控制信号精确地旋转到特定角度并保持在该位置。舵机内部包含直流电机、减速齿轮组、控制电路和电位器(用于检测当前角度)。
1.2 舵机如何工作?
舵机通过接收PWM(脉冲宽度调制)信号来控制角度。这个信号有三个关键特征:
频率固定:通常为50Hz(周期20ms)脉宽可变:高电平持续时间在0.5ms-2.5ms之间变化脉宽与角度对应:
0.5ms → 0度1.5ms → 90度2.5ms → 180度
二、硬件准备与连接
2.1 所需材料
STM32开发板(如STM32F103C8T6)舵机(常见SG90)杜邦线若干5V电源(注意:STM32的3.3V可能无法驱动舵机)
2.2 接线方式
舵机线缆颜色STM32连接点红色电源+5V电源棕色地线GND黄色信号线PWM输出引脚(如PA6)
重要提示:
当驱动多个舵机时,建议使用外部电源供电确保共地(STM32与舵机电源地连接在一起)
三、STM32 PWM配置
3.1 PWM基础概念
PWM(脉冲宽度调制)是控制舵机的核心技术。STM32的定时器可以生成精确的PWM信号:
ARR(自动重装载值):决定PWM周期CCR(捕获/比较值):决定脉冲宽度(占空比)
3.2 CubeMX配置步骤
打开STM32CubeMX,选择对应芯片配置时钟树,确保定时器时钟正确(如72MHz)选择定时器(如TIM3)和通道(如CH1)设置模式为"PWM Generation CH1"参数设置:
Prescaler(分频系数):71Counter Period(ARR):1999Pulse(初始CCR):150(对应1.5ms)
3.3 关键代码解析
PWM初始化代码(以TIM3通道1为例):
// PWM初始化函数
void PWM_Init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
// 1. 使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 2. GPIO配置
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 3. 定时器基础配置
TIM_TimeBaseStruct.TIM_Prescaler = 72 - 1; // 72MHz/72 = 1MHz
TIM_TimeBaseStruct.TIM_Period = 20000 - 1; // 20ms周期
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
// 4. PWM通道配置
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStruct);
// 5. 启动定时器
TIM_Cmd(TIM3, ENABLE);
}
四、舵机控制实战
4.1 角度控制函数
将PWM脉宽转换为角度控制:
// 设置舵机角度(0-180度)
void Servo_SetAngle(float angle) {
// 角度转换为CCR值:500(0°) ~ 2500(180°)
uint16_t pulse = (angle / 180) * 2000 + 500;
TIM_SetCompare1(TIM3, pulse); // 更新CCR值
}
4.2 主程序示例
#include "stm32f10x.h"
#include "pwm.h"
#include "delay.h"
int main(void) {
Delay_Init();
PWM_Init();
while(1) {
// 0° → 90° → 180°循环
Servo_SetAngle(0);
Delay_ms(1000);
Servo_SetAngle(90);
Delay_ms(1000);
Servo_SetAngle(180);
Delay_ms(1000);
}
}
4.3 按键控制进阶版
通过按键控制角度增减:
uint8_t key = KEY_GetNum();
if(key == 1) { // KEY1按下
angle += 30;
if(angle > 180) angle = 0;
Servo_SetAngle(angle);
OLED_ShowNum(1, 7, angle, 3); // 显示当前角度
}
五、常见问题与调试技巧
5.1 舵机不转动
检查步骤:
确认电源电压≥4.8V检查信号线连接是否正确用示波器测量PWM波形检查代码中定时器和GPIO配置
5.2 舵机抖动或不稳定
解决方案:
增加电源滤波电容(如100μF)确保电源电流足够(单个舵机约需300mA)检查PWM信号是否稳定
5.3 角度不准确
校准方法:
// 实际测试后调整公式
void Servo_Calibrate(float angle) {
// 自定义校准参数
uint16_t pulse = (angle / 180) * 1800 + 600; // 根据实测调整
TIM_SetCompare1(TIM3, pulse);
}
六、项目扩展
6.1 多舵机控制
STM32的单个定时器可以同时控制4路舵机(通用定时器):
// 初始化TIM3的4个通道
TIM_OC1Init(TIM3, &TIM_OCInitStruct); // CH1
TIM_OC2Init(TIM3, &TIM_OCInitStruct); // CH2
// ...其他通道类似
6.2 机械臂控制实例
6自由度机械臂控制:
void RoboticArm_Control(float angles[6]) {
Servo_SetAngle(0, angles[0]); // 底座
Servo_SetAngle(1, angles[1]); // 肩部
Servo_SetAngle(2, angles[2]); // 肘部
// ...其他关节
}
6.3 使用中断优化
通过定时器中断实现平滑运动:
void TIM3_IRQHandler(void) {
if(TIM_GetITStatus(TIM3, TIM_IT_Update)) {
static uint8_t step = 0;
float target_angle = 90 + 30 * sin(step++ * 0.1);
Servo_SetAngle(target_angle);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
七、学习资源推荐
官方文档:
《STM32参考手册》定时器章节STM32CubeMX用户手册 开发工具:
逻辑分析仪(观察PWM波形)STM32CubeMonitor(实时调试) 进阶项目:
双足机器人平衡控制云台跟踪系统自动窗帘控制器
完整工程下载: STM32舵机控制示例代码
通过本指南,您已经掌握了从基础原理到实际应用的STM32舵机控制技术。建议按照以下步骤实践:
从单个舵机控制开始尝试按键交互控制实现多舵机协同最后开发完整项目(如机械臂)
遇到问题时,记住检查电源、信号和代码配置这三个关键环节。祝您在嵌入式开发之路上越走越远!