基于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)
c 复制代码
#include "stm32f10x.h"

#define SERVO_PWM_FREQ 50    // 50Hz
#define SERVO_PULSE_MIN 500  // 0.5ms
#define SERVO_PULSE_MAX 2500 // 2.5ms

void 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;          // 预分频 1MHz
    TIM_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. 舵机控制核心代码
c 复制代码
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. 定时器计算
c 复制代码
系统时钟:72MHz
预分频:72-1 → 1MHz计数频率
周期值:20000 → 20ms周期
占空比范围:500-2500(对应0.5ms-2.5ms)
2. 角度控制算法
c 复制代码
// 平滑角度过渡(增量控制)
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;
        }
    }
}

四、主程序流程

c 复制代码
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. 多机同步控制
c 复制代码
// 同步更新所有通道
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. 连续旋转模式
c 复制代码
// 设置连续旋转速度(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

六、完整工程结构

c 复制代码
├── Drivers/
│   ├── CMSIS/
│   └── STM32F10x_HAL_Driver/
├── Middlewares/
│   └── Servo_Control/      # 舵机控制库
│       ├── servo.c
│       └── servo.h
├── Applications/
│   └── main.c            # 主程序入口
└── Projects/
    └── STM32F103ZET6/
        ├── startup_stm32f10x_hd.s
        └── system_stm32f10x.c
相关推荐
威嵌神州15 小时前
嵌入式排故实录:高并发下串口数据“超时丢包”的根因剖析与架构优化
运维·服务器·嵌入式硬件·缓存
Zw-awa20 小时前
MPU6050:从原始加速度到姿态变化
stm32
少司府21 小时前
嵌入式入门篇(二):初识STM32F103ZET6
linux·python·stm32·单片机·嵌入式硬件·mcu·嵌入式软件
shimly1234561 天前
(done) 嵌入式硬件电路图 (8) 获取芯片手册信息
嵌入式硬件
Zwawa1 天前
让屏幕动起来:OLED动画效果,丝滑光标、帧动画和一只贪吃蛇
c语言·单片机·嵌入式
简单电磁炮1 天前
FWD八位单片机调试问题
单片机·嵌入式硬件
shimly1234561 天前
(done) 嵌入式硬件电路图 (6) 重要的元器件特性之MOS管
嵌入式硬件
菥蓂寻生2 天前
STM32移植到GD32中以105为例
stm32·单片机·嵌入式硬件
Zw-awa2 天前
让屏幕动起来:OLED动画效果,丝滑光标、帧动画和一只贪吃蛇
stm32
橘为己有4412 天前
51单片机:定时/计数器
单片机·51单片机