基于STM32F103ZET6实现6路舵机控制
一、硬件连接
1. 电路连接
定时器 | 通道 | 对应引脚 | 舵机编号 |
---|---|---|---|
TIM2 | CH1 | PA0 | 舵机1 |
TIM2 | CH2 | PA1 | 舵机2 |
TIM2 | CH3 | PA2 | 舵机3 |
TIM2 | CH4 | PA3 | 舵机4 |
TIM3 | CH1 | PC6 | 舵机5 |
TIM3 | CH2 | PC7 | 舵机6 |
2. 电源要求
- 每个舵机需独立供电(建议5V/2A)
- 逻辑部分供电3.3V
二、软件实现代码
1. 定时器初始化(TIM2+TIM3)
#include "stm32f10x.h"#define SERVO_PWM_FREQ 50 // 50Hz
#define SERVO_PULSE_MIN 500 // 0.5ms
#define SERVO_PULSE_MAX 2500 // 2.5msvoid TIM2_TIM3_PWM_Init() {GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_InitStruct;TIM_OCInitTypeDef TIM_OCInitStruct;// 使能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);// GPIO配置(复用推挽输出)GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;// TIM2通道配置 (PA0-PA3)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_Init(GPIOA, &GPIO_InitStruct);// TIM3通道配置 (PC6-PC7)GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_Init(GPIOC, &GPIO_InitStruct);// 定时器基础配置TIM_InitStruct.TIM_Prescaler = 72 - 1; // 预分频 1MHzTIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_InitStruct.TIM_Period = 20000 - 1; // 20ms周期TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInit(TIM2, &TIM_InitStruct);TIM_TimeBaseInit(TIM3, &TIM_InitStruct);// PWM模式配置TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStruct.TIM_Pulse = SERVO_PULSE_MIN;TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;// 配置TIM2通道TIM_OC1Init(TIM2, &TIM_OCInitStruct);TIM_OC2Init(TIM2, &TIM_OCInitStruct);TIM_OC3Init(TIM2, &TIM_OCInitStruct);TIM_OC4Init(TIM2, &TIM_OCInitStruct);// 配置TIM3通道TIM_OC1Init(TIM3, &TIM_OCInitStruct);TIM_OC2Init(TIM3, &TIM_OCInitStruct);// 使能定时器TIM_Cmd(TIM2, ENABLE);TIM_Cmd(TIM3, ENABLE);
}
2. 舵机控制核心代码
typedef struct {uint16_t target_pulse; // 目标脉宽uint16_t current_pulse; // 当前脉宽float angle; // 当前角度
} ServoCtrl;ServoCtrl servos[6] = {0};// 角度转脉宽
uint16_t AngleToPulse(float angle) {return SERVO_PULSE_MIN + (angle / 180.0f) * (SERVO_PULSE_MAX - SERVO_PULSE_MIN);
}// 初始化舵机参数
void Servo_Init() {for(int i=0; i<6; i++) {servos[i].angle = 0.0f;servos[i].current_pulse = AngleToPulse(0.0f);servos[i].target_pulse = AngleToPulse(0.0f);}
}// 设置舵机角度
void Servo_SetAngle(uint8_t index, float angle) {if(index >= 6) return;angle = angle > 180.0f ? 180.0f : angle < 0.0f ? 0.0f : angle;servos[index].target_pulse = AngleToPulse(angle);
}// PWM中断服务函数
void TIM2_IRQHandler() {if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {static uint8_t channel = 0;// 更新各通道占空比TIM_ClearITPendingBit(TIM2, TIM_IT_Update);switch(channel) {case 0: TIM_SetCompare1(TIM2, servos[0].current_pulse); break;case 1: TIM_SetCompare2(TIM2, servos[1].current_pulse); break;case 2: TIM_SetCompare3(TIM2, servos[2].current_pulse); break;case 3: TIM_SetCompare4(TIM2, servos[3].current_pulse); break;case 4: TIM_SetCompare1(TIM3, servos[4].current_pulse); break;case 5: TIM_SetCompare2(TIM3, servos[5].current_pulse); break;}channel = (channel + 1) % 6;}
}
三、关键参数配置
1. 定时器计算
系统时钟:72MHz
预分频:72-1 → 1MHz计数频率
周期值:20000 → 20ms周期
占空比范围:500-2500(对应0.5ms-2.5ms)
2. 角度控制算法
// 平滑角度过渡(增量控制)
void Servo_Update() {for(int i=0; i<6; i++) {float error = servos[i].target_pulse - servos[i].current_pulse;float step = error * 0.1f; // 调整步长(0.1-0.5)if(step > 0) {servos[i].current_pulse += (uint16_t)step;if(servos[i].current_pulse > servos[i].target_pulse)servos[i].current_pulse = servos[i].target_pulse;} else {servos[i].current_pulse += (uint16_t)step;if(servos[i].current_pulse < servos[i].target_pulse)servos[i].current_pulse = servos[i].target_pulse;}}
}
四、主程序流程
int main() {// 系统初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);Delay_Init();Servo_Init();TIM2_TIM3_PWM_Init();// 设置初始角度Servo_SetAngle(0, 90.0f); // 舵机1→90°Servo_SetAngle(3, 45.0f); // 舵机4→45°while(1) {Servo_Update(); // 更新角度Delay_ms(20); // 20ms刷新周期}
}
五、扩展
1. 多机同步控制
// 同步更新所有通道
void Servo_SyncUpdate() {TIM_SetCompare1(TIM2, servos[0].current_pulse);TIM_SetCompare2(TIM2, servos[1].current_pulse);TIM_SetCompare3(TIM2, servos[2].current_pulse);TIM_SetCompare4(TIM2, servos[3].current_pulse);TIM_SetCompare1(TIM3, servos[4].current_pulse);TIM_SetCompare2(TIM3, servos[5].current_pulse);
}
2. 连续旋转模式
// 设置连续旋转速度(0-200rpm)
void Servo_SetSpeed(uint8_t index, int16_t speed) {if(speed > 0) {servos[index].target_pulse = SERVO_PULSE_MIN + (speed * 2000 / 200);} else {servos[index].target_pulse = SERVO_PULSE_MAX + (speed * 2000 / 200);}
}
参考代码 STM32F103ZET6同时控制6个舵机的程序 www.youwenfan.com/contentcsj/71392.html
六、完整工程结构
├── Drivers/
│ ├── CMSIS/
│ └── STM32F10x_HAL_Driver/
├── Middlewares/
│ └── Servo_Control/ # 舵机控制库
│ ├── servo.c
│ └── servo.h
├── Applications/
│ └── main.c # 主程序入口
└── Projects/└── STM32F103ZET6/├── startup_stm32f10x_hd.s└── system_stm32f10x.c