基于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
相关推荐
嵌入式老牛3 小时前
HC32F460_ADC驱动(三)
单片机·嵌入式硬件
秀秀更健康4 小时前
stm32: 系统时钟如何配置为72Mhz
stm32·单片机·嵌入式硬件
QAQ小菜鸟7 小时前
一、安装Altium Designer 26.1
嵌入式硬件
嵌入式-老费8 小时前
esp32开发与应用(用面包板去学模块)
嵌入式硬件
归零鸟9 小时前
WD Elements移动硬盘能识别出盘但不能出盘的修复记录
stm32·单片机·嵌入式硬件
追兮兮10 小时前
MCUQuickStart v1.1.0发布,一键生成Keil工程+RTOS模板
stm32·单片机·嵌入式硬件·freertos·gd32·keil5
国科安芯10 小时前
ASP7A84AS与主流架构兼容替代及系统级电源完整性解决方案的深度研究
单片机·嵌入式硬件·架构
kaikaile199510 小时前
STC8单片机实现简单花样DMX512控制器
单片机·嵌入式硬件
szxinmai主板定制专家10 小时前
RK3568 + CODESYS+实时系统运动控制器PLC,支持 AI 视觉目标检测,预测性维护,混合多系统部署,多路模拟量采集
arm开发·人工智能·嵌入式硬件·fpga开发
rit843249910 小时前
STM32移植NES模拟器指南
stm32·单片机·嵌入式硬件