基于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.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. 舵机控制核心代码

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/contentcnm/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
posted @ 2025-12-05 16:56  yu8yu7  阅读(18)  评论(0)    收藏  举报