基于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
相关推荐
逐步前行7 小时前
STM32_TIM_寄存器操作
stm32·单片机·嵌入式硬件
0南城逆流08 小时前
【STM32】知识点介绍七:PWM功能
stm32·单片机·嵌入式硬件
智者知已应修善业8 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机
dashizhi20158 小时前
服务器共享禁止保存到本地磁盘、共享文件禁止另存为本地磁盘、移动硬盘等
运维·网络·stm32·安全·电脑
我是一棵无人问荆的小草8 小时前
单片机通电后延迟启动策略
单片机·嵌入式硬件
坏柠9 小时前
ESP32-S3 蓝牙 BLE 从零到一:广播、服务、特征,用一个智能灯的例子全讲透
嵌入式硬件
日更嵌入式的打工仔9 小时前
UART RX为什么要上拉
单片机
三佛科技-1873661339712 小时前
FT32F030F6AP7高性能32位RISC内核MCU解析(兼容STM32F030K6TP7)
stm32·单片机·嵌入式硬件
LCMICRO-1331084774613 小时前
长芯微LDC90810完全P2P替代ADC128D818,是一款八通道系统监控器,专为监控复杂系统状态而设计。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模数转换芯片adc
嵌入式老菜鸟qq12524277313 小时前
关于S2-LP休眠
单片机·嵌入式硬件·mcu·射频工程