STM32 舵机控制程序(基于标准外设库)

STM32 舵机控制程序,支持角度控制、速度控制、多舵机同步、按键控制等功能,适用于机器人、机械臂、云台等应用场景。

一、系统架构

复制代码
STM32 舵机控制系统架构:
├── 硬件层
│   ├── STM32F103C8T6/CBT6 微控制器
│   ├── SG90/MG996R 舵机 × 4
│   ├── 按键 × 4
│   ├── OLED 显示屏(可选)
│   └── 电源模块(5V/2A)
├── 驱动层
│   ├── TIM PWM 输出
│   ├── GPIO 按键扫描
│   ├── 延时函数
│   └── 中断管理
├── 控制层
│   ├── 舵机角度控制
│   ├── 舵机速度控制
│   ├── 多舵机同步
│   ├── 轨迹规划
│   └── 限位保护
└── 应用层
    ├── 手动控制模式
    ├── 自动控制模式
    ├── 预设动作序列
    └── 示教再现

二、硬件连接

2.1 舵机接口连接

复制代码
STM32F103    SG90/MG996R    功能说明
PA6 (TIM3_CH1) → 舵机1信号线  舵机1控制
PA7 (TIM3_CH2) → 舵机2信号线  舵机2控制
PB0 (TIM3_CH3) → 舵机3信号线  舵机3控制
PB1 (TIM3_CH4) → 舵机4信号线  舵机4控制
5V          → 舵机电源正极   舵机供电(需外接5V/2A电源)
GND         → 舵机电源负极   共地

2.2 按键接口连接

复制代码
STM32F103    按键    功能说明
PB12        → 按键1  舵机1角度增加
PB13        → 按键2  舵机1角度减少
PB14        → 按键3  舵机2角度增加
PB15        → 按键4  舵机2角度减少

三、核心代码实现

3.1 头文件定义 (servo_control.h)

c 复制代码
#ifndef SERVO_CONTROL_H
#define SERVO_CONTROL_H

#include "stm32f10x.h"
#include <stdint.h>

// 舵机配置参数
#define SERVO_NUM          4           // 舵机数量
#define SERVO_MIN_ANGLE    0           // 最小角度
#define SERVO_MAX_ANGLE    180         // 最大角度
#define SERVO_MIN_PULSE    500         // 最小脉冲宽度(us) - 0.5ms
#define SERVO_MAX_PULSE    2500        // 最大脉冲宽度(us) - 2.5ms
#define SERVO_PERIOD       20000       // PWM周期(us) - 20ms

// 舵机速度参数
#define SERVO_SPEED_MIN    1           // 最小速度(度/周期)
#define SERVO_SPEED_MAX    10          // 最大速度
#define SERVO_SPEED_DEFAULT 3          // 默认速度

// 舵机ID定义
typedef enum {
    SERVO_1 = 0,
    SERVO_2 = 1,
    SERVO_3 = 2,
    SERVO_4 = 3
} ServoID;

// 舵机状态结构
typedef struct {
    uint8_t id;                // 舵机ID
    uint16_t current_angle;    // 当前角度
    uint16_t target_angle;     // 目标角度
    uint16_t speed;            // 转动速度
    uint8_t enabled;           // 使能标志
    uint8_t moving;            // 正在移动标志
    uint16_t pulse_width;      // 当前脉冲宽度
    uint32_t last_update;      // 最后更新时间
} ServoStatus;

// 系统状态结构
typedef struct {
    uint8_t selected_servo;    // 当前选中的舵机
    uint8_t control_mode;      // 控制模式(0:手动,1:自动)
    uint8_t emergency_stop;    // 紧急停止标志
    uint32_t system_time;      // 系统时间
} SystemStatus;

// 函数声明
void Servo_Init(void);
void Servo_SetAngle(ServoID servo_id, uint16_t angle);
void Servo_SetPulseWidth(ServoID servo_id, uint16_t pulse_us);
void Servo_SetSpeed(ServoID servo_id, uint16_t speed);
void Servo_UpdateAll(void);
void Servo_EmergencyStop(void);
void Servo_MoveToPosition(uint16_t angles[SERVO_NUM]);
void Servo_ExecuteSequence(uint16_t sequence[][SERVO_NUM], uint8_t seq_len, uint16_t delay_ms);

// 按键处理函数
void Key_Scan(void);
void Key_Process(void);

// 工具函数
uint16_t AngleToPulse(uint16_t angle);
uint16_t PulseToAngle(uint16_t pulse);

#endif // SERVO_CONTROL_H

3.2 舵机驱动实现 (servo_control.c)

c 复制代码
#include "servo_control.h"
#include "delay.h"

// 全局变量
ServoStatus g_servos[SERVO_NUM];
SystemStatus g_system;

// 舵机PWM引脚配置
typedef struct {
    GPIO_TypeDef* gpio_port;
    uint16_t gpio_pin;
    uint8_t tim_channel;
} ServoPinConfig;

static ServoPinConfig servo_pins[SERVO_NUM] = {
    {GPIOA, GPIO_Pin_6, 1},   // PA6 - TIM3_CH1
    {GPIOA, GPIO_Pin_7, 2},   // PA7 - TIM3_CH2
    {GPIOB, GPIO_Pin_0, 3},   // PB0 - TIM3_CH3
    {GPIOB, GPIO_Pin_1, 4}    // PB1 - TIM3_CH4
};

// 初始化舵机
void Servo_Init(void)
{
    uint8_t i;
    
    // 初始化系统状态
    g_system.selected_servo = SERVO_1;
    g_system.control_mode = 0;
    g_system.emergency_stop = 0;
    g_system.system_time = 0;
    
    // 初始化舵机状态
    for(i = 0; i < SERVO_NUM; i++)
    {
        g_servos[i].id = i;
        g_servos[i].current_angle = 90;      // 默认90度
        g_servos[i].target_angle = 90;
        g_servos[i].speed = SERVO_SPEED_DEFAULT;
        g_servos[i].enabled = 1;
        g_servos[i].moving = 0;
        g_servos[i].pulse_width = AngleToPulse(90);
        g_servos[i].last_update = 0;
    }
    
    // 初始化GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    // 配置舵机PWM引脚
    for(i = 0; i < SERVO_NUM; i++)
    {
        GPIO_InitStructure.GPIO_Pin = servo_pins[i].gpio_pin;
        GPIO_Init(servo_pins[i].gpio_port, &GPIO_InitStructure);
    }
    
    // 初始化定时器TIM3
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
    // 定时器基础配置
    TIM_TimeBaseStructure.TIM_Period = SERVO_PERIOD - 1;        // 20ms周期
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;              // 72MHz/72 = 1MHz,1us计数
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    
    // PWM模式配置
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_Pulse = 0;
    
    // 配置4个通道
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_OC3Init(TIM3, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_OC4Init(TIM3, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    TIM_Cmd(TIM3, ENABLE);
    
    // 初始化所有舵机到90度
    for(i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, 90);
    }
    
    Delay_ms(1000);  // 等待舵机稳定
}

// 角度转脉冲宽度
uint16_t AngleToPulse(uint16_t angle)
{
    // 限制角度范围
    if(angle < SERVO_MIN_ANGLE) angle = SERVO_MIN_ANGLE;
    if(angle > SERVO_MAX_ANGLE) angle = SERVO_MAX_ANGLE;
    
    // 线性映射:0° -> 500us, 180° -> 2500us
    return SERVO_MIN_PULSE + (angle * (SERVO_MAX_PULSE - SERVO_MIN_PULSE)) / SERVO_MAX_ANGLE;
}

// 脉冲宽度转角度
uint16_t PulseToAngle(uint16_t pulse)
{
    // 限制脉冲范围
    if(pulse < SERVO_MIN_PULSE) pulse = SERVO_MIN_PULSE;
    if(pulse > SERVO_MAX_PULSE) pulse = SERVO_MAX_PULSE;
    
    // 线性映射:500us -> 0°, 2500us -> 180°
    return ((pulse - SERVO_MIN_PULSE) * SERVO_MAX_ANGLE) / (SERVO_MAX_PULSE - SERVO_MIN_PULSE);
}

// 设置舵机角度
void Servo_SetAngle(ServoID servo_id, uint16_t angle)
{
    if(servo_id >= SERVO_NUM || g_system.emergency_stop) return;
    
    // 限制角度范围
    if(angle < SERVO_MIN_ANGLE) angle = SERVO_MIN_ANGLE;
    if(angle > SERVO_MAX_ANGLE) angle = SERVO_MAX_ANGLE;
    
    g_servos[servo_id].target_angle = angle;
    g_servos[servo_id].moving = 1;
}

// 设置舵机脉冲宽度
void Servo_SetPulseWidth(ServoID servo_id, uint16_t pulse_us)
{
    if(servo_id >= SERVO_NUM) return;
    
    uint16_t pulse = pulse_us;
    if(pulse < SERVO_MIN_PULSE) pulse = SERVO_MIN_PULSE;
    if(pulse > SERVO_MAX_PULSE) pulse = SERVO_MAX_PULSE;
    
    g_servos[servo_id].pulse_width = pulse;
    
    // 更新PWM输出
    switch(servo_pins[servo_id].tim_channel)
    {
        case 1: TIM_SetCompare1(TIM3, pulse); break;
        case 2: TIM_SetCompare2(TIM3, pulse); break;
        case 3: TIM_SetCompare3(TIM3, pulse); break;
        case 4: TIM_SetCompare4(TIM3, pulse); break;
    }
}

// 设置舵机速度
void Servo_SetSpeed(ServoID servo_id, uint16_t speed)
{
    if(servo_id >= SERVO_NUM) return;
    
    if(speed < SERVO_SPEED_MIN) speed = SERVO_SPEED_MIN;
    if(speed > SERVO_SPEED_MAX) speed = SERVO_SPEED_MAX;
    
    g_servos[servo_id].speed = speed;
}

// 更新所有舵机
void Servo_UpdateAll(void)
{
    uint8_t i;
    uint32_t current_time = g_system.system_time;
    
    for(i = 0; i < SERVO_NUM; i++)
    {
        if(!g_servos[i].enabled || !g_servos[i].moving) continue;
        
        // 检查是否需要更新(根据速度控制更新频率)
        if(current_time - g_servos[i].last_update < 20) continue;  // 每20ms更新一次
        
        g_servos[i].last_update = current_time;
        
        // 计算新的角度
        int16_t diff = g_servos[i].target_angle - g_servos[i].current_angle;
        
        if(abs(diff) <= g_servos[i].speed)
        {
            // 到达目标角度
            g_servos[i].current_angle = g_servos[i].target_angle;
            g_servos[i].moving = 0;
        }
        else
        {
            // 逐步接近目标角度
            if(diff > 0)
                g_servos[i].current_angle += g_servos[i].speed;
            else
                g_servos[i].current_angle -= g_servos[i].speed;
        }
        
        // 设置PWM输出
        uint16_t pulse = AngleToPulse(g_servos[i].current_angle);
        Servo_SetPulseWidth((ServoID)i, pulse);
    }
}

// 紧急停止
void Servo_EmergencyStop(void)
{
    uint8_t i;
    
    g_system.emergency_stop = 1;
    
    for(i = 0; i < SERVO_NUM; i++)
    {
        g_servos[i].moving = 0;
        Servo_SetPulseWidth((ServoID)i, 0);  // 停止PWM输出
    }
}

// 移动到指定位置
void Servo_MoveToPosition(uint16_t angles[SERVO_NUM])
{
    uint8_t i;
    
    for(i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, angles[i]);
    }
}

// 执行动作序列
void Servo_ExecuteSequence(uint16_t sequence[][SERVO_NUM], uint8_t seq_len, uint16_t delay_ms)
{
    uint8_t i;
    
    for(i = 0; i < seq_len; i++)
    {
        Servo_MoveToPosition(sequence[i]);
        
        // 等待所有舵机到位
        uint8_t all_arrived = 0;
        while(!all_arrived)
        {
            Servo_UpdateAll();
            Delay_ms(10);
            
            all_arrived = 1;
            for(uint8_t j = 0; j < SERVO_NUM; j++)
            {
                if(g_servos[j].moving)
                {
                    all_arrived = 0;
                    break;
                }
            }
        }
        
        Delay_ms(delay_ms);
    }
}

3.3 主程序 (main.c)

c 复制代码
#include "stm32f10x.h"
#include "servo_control.h"
#include "delay.h"
#include "key.h"
#include "oled.h"

// 预设动作序列
uint16_t action_sequence[][SERVO_NUM] = {
    // 初始位置
    {90, 90, 90, 90},
    // 动作1:挥手
    {45, 90, 90, 90},
    {135, 90, 90, 90},
    {45, 90, 90, 90},
    {135, 90, 90, 90},
    // 动作2:点头
    {90, 45, 90, 90},
    {90, 135, 90, 90},
    {90, 45, 90, 90},
    {90, 135, 90, 90},
    // 回到初始位置
    {90, 90, 90, 90}
};

int main(void)
{
    // 系统初始化
    SystemClock_Init();
    Delay_Init();
    Key_Init();
    OLED_Init();
    
    // 舵机初始化
    Servo_Init();
    
    // 显示欢迎信息
    OLED_ShowString(0, 0, "STM32 Servo Ctrl");
    OLED_ShowString(0, 2, "Select: Servo 1");
    OLED_ShowString(0, 4, "Angle: 90");
    OLED_ShowString(0, 6, "Mode: Manual");
    
    while(1)
    {
        // 更新系统时间
        g_system.system_time++;
        
        // 按键扫描和处理
        Key_Scan();
        Key_Process();
        
        // 更新舵机位置
        Servo_UpdateAll();
        
        // 显示当前状态
        OLED_ShowNum(80, 2, g_system.selected_servo + 1, 1);
        OLED_ShowNum(56, 4, g_servos[g_system.selected_servo].current_angle, 3);
        
        Delay_ms(1);
    }
}

3.4 按键控制 (key.c)

c 复制代码
#include "key.h"
#include "servo_control.h"
#include "delay.h"

// 按键引脚定义
#define KEY1_PIN    GPIO_Pin_12
#define KEY2_PIN    GPIO_Pin_13
#define KEY3_PIN    GPIO_Pin_14
#define KEY4_PIN    GPIO_Pin_15
#define KEY_PORT    GPIOB

// 按键状态
typedef enum {
    KEY_NONE = 0,
    KEY1_PRESS,
    KEY2_PRESS,
    KEY3_PRESS,
    KEY4_PRESS
} KeyStatus;

// 按键初始化
void Key_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = KEY1_PIN | KEY2_PIN | KEY3_PIN | KEY4_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  // 上拉输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(KEY_PORT, &GPIO_InitStructure);
}

// 按键扫描
KeyStatus Key_Scan(void)
{
    static uint8_t key_lock = 0;
    static uint16_t key_delay = 0;
    
    if(key_lock == 0)
    {
        if((KEY_PORT & KEY1_PIN) == 0)
        {
            key_delay++;
            if(key_delay >= 10)  // 消抖
            {
                key_delay = 0;
                key_lock = 1;
                return KEY1_PRESS;
            }
        }
        else if((KEY_PORT & KEY2_PIN) == 0)
        {
            key_delay++;
            if(key_delay >= 10)
            {
                key_delay = 0;
                key_lock = 1;
                return KEY2_PRESS;
            }
        }
        else if((KEY_PORT & KEY3_PIN) == 0)
        {
            key_delay++;
            if(key_delay >= 10)
            {
                key_delay = 0;
                key_lock = 1;
                return KEY3_PRESS;
            }
        }
        else if((KEY_PORT & KEY4_PIN) == 0)
        {
            key_delay++;
            if(key_delay >= 10)
            {
                key_delay = 0;
                key_lock = 1;
                return KEY4_PRESS;
            }
        }
        else
        {
            key_delay = 0;
        }
    }
    else
    {
        // 等待按键释放
        if((KEY_PORT & (KEY1_PIN | KEY2_PIN | KEY3_PIN | KEY4_PIN)) == 
           (KEY1_PIN | KEY2_PIN | KEY3_PIN | KEY4_PIN))
        {
            key_lock = 0;
        }
    }
    
    return KEY_NONE;
}

// 按键处理
void Key_Process(void)
{
    KeyStatus key = Key_Scan();
    
    switch(key)
    {
        case KEY1_PRESS:  // 舵机1角度增加
            if(g_system.selected_servo == SERVO_1)
            {
                uint16_t new_angle = g_servos[SERVO_1].current_angle + 5;
                if(new_angle > SERVO_MAX_ANGLE) new_angle = SERVO_MAX_ANGLE;
                Servo_SetAngle(SERVO_1, new_angle);
            }
            break;
            
        case KEY2_PRESS:  // 舵机1角度减少
            if(g_system.selected_servo == SERVO_1)
            {
                uint16_t new_angle = g_servos[SERVO_1].current_angle - 5;
                if(new_angle < SERVO_MIN_ANGLE) new_angle = SERVO_MIN_ANGLE;
                Servo_SetAngle(SERVO_1, new_angle);
            }
            break;
            
        case KEY3_PRESS:  // 舵机2角度增加
            if(g_system.selected_servo == SERVO_2)
            {
                uint16_t new_angle = g_servos[SERVO_2].current_angle + 5;
                if(new_angle > SERVO_MAX_ANGLE) new_angle = SERVO_MAX_ANGLE;
                Servo_SetAngle(SERVO_2, new_angle);
            }
            break;
            
        case KEY4_PRESS:  // 舵机2角度减少
            if(g_system.selected_servo == SERVO_2)
            {
                uint16_t new_angle = g_servos[SERVO_2].current_angle - 5;
                if(new_angle < SERVO_MIN_ANGLE) new_angle = SERVO_MIN_ANGLE;
                Servo_SetAngle(SERVO_2, new_angle);
            }
            break;
    }
}

3.5 OLED显示 (oled.c)

c 复制代码
#include "oled.h"
#include "i2c.h"

// OLED初始化
void OLED_Init(void)
{
    I2C_Init();
    
    OLED_WriteCmd(0xAE);  // 关闭显示
    OLED_WriteCmd(0xD5);  // 设置显示时钟分频比/振荡器频率
    OLED_WriteCmd(0x80);
    OLED_WriteCmd(0xA8);  // 设置多路复用比率
    OLED_WriteCmd(0x3F);
    OLED_WriteCmd(0xD3);  // 设置显示偏移
    OLED_WriteCmd(0x00);
    OLED_WriteCmd(0x40);  // 设置显示起始行
    OLED_WriteCmd(0x8D);  // 电荷泵设置
    OLED_WriteCmd(0x14);
    OLED_WriteCmd(0x20);  // 内存地址模式
    OLED_WriteCmd(0x02);
    OLED_WriteCmd(0xA1);  // 段重映射
    OLED_WriteCmd(0xC8);  // 扫描方向
    OLED_WriteCmd(0xDA);  // 设置COM引脚硬件配置
    OLED_WriteCmd(0x12);
    OLED_WriteCmd(0x81);  // 对比度设置
    OLED_WriteCmd(0xCF);
    OLED_WriteCmd(0xD9);  // 预充电周期
    OLED_WriteCmd(0xF1);
    OLED_WriteCmd(0xDB);  // VCOMH取消选择级别
    OLED_WriteCmd(0x40);
    OLED_WriteCmd(0xA4);  // 整个显示开启
    OLED_WriteCmd(0xA6);  // 正常显示
    OLED_WriteCmd(0xAF);  // 开启显示
    
    OLED_Clear();
}

// 显示字符串
void OLED_ShowString(uint8_t x, uint8_t y, char *str)
{
    while(*str)
    {
        OLED_ShowChar(x, y, *str++);
        x += 8;
        if(x > 120)
        {
            x = 0;
            y += 2;
        }
    }
}

// 显示数字
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len)
{
    uint8_t i;
    for(i = 0; i < len; i++)
    {
        OLED_ShowChar(x + i*8, y, '0' + (num / (uint32_t)pow(10, len-1-i)) % 10);
    }
}

3.6 高级功能扩展 (advanced_features.c)

c 复制代码
#include "servo_control.h"

// 舵机校准功能
void Servo_Calibration(void)
{
    printf("舵机校准开始...\n");
    
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        printf("校准舵机 %d:\n", i+1);
        
        // 转到最小角度
        Servo_SetAngle((ServoID)i, SERVO_MIN_ANGLE);
        Delay_ms(2000);
        
        // 转到最大角度
        Servo_SetAngle((ServoID)i, SERVO_MAX_ANGLE);
        Delay_ms(2000);
        
        // 回到中间
        Servo_SetAngle((ServoID)i, 90);
        Delay_ms(2000);
    }
    
    printf("舵机校准完成!\n");
}

// 轨迹规划 - 平滑移动到目标位置
void Servo_SmoothMove(ServoID servo_id, uint16_t target_angle, uint16_t duration_ms)
{
    uint16_t start_angle = g_servos[servo_id].current_angle;
    uint16_t steps = duration_ms / 20;  // 每20ms一步
    float angle_step = (float)(target_angle - start_angle) / steps;
    
    for(uint16_t i = 0; i < steps; i++)
    {
        uint16_t current_angle = start_angle + (uint16_t)(angle_step * i);
        Servo_SetAngle(servo_id, current_angle);
        Delay_ms(20);
    }
    
    // 确保到达最终位置
    Servo_SetAngle(servo_id, target_angle);
}

// 多舵机同步运动
void Servo_SyncMove(uint16_t target_angles[SERVO_NUM], uint16_t duration_ms)
{
    uint16_t start_angles[SERVO_NUM];
    uint16_t steps = duration_ms / 20;
    
    // 记录起始角度
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        start_angles[i] = g_servos[i].current_angle;
    }
    
    // 逐步移动
    for(uint16_t step = 0; step < steps; step++)
    {
        for(uint8_t i = 0; i < SERVO_NUM; i++)
        {
            float progress = (float)step / steps;
            uint16_t current_angle = start_angles[i] + 
                                   (uint16_t)((target_angles[i] - start_angles[i]) * progress);
            Servo_SetAngle((ServoID)i, current_angle);
        }
        Delay_ms(20);
    }
    
    // 确保到达最终位置
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, target_angles[i]);
    }
}

// 预设动作演示
void Servo_DemoActions(void)
{
    printf("开始演示预设动作...\n");
    
    // 动作1:波浪运动
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, 45);
        Delay_ms(200);
    }
    
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, 135);
        Delay_ms(200);
    }
    
    // 回到中间
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, 90);
    }
    
    Delay_ms(1000);
    
    // 动作2:交替运动
    for(uint8_t cycle = 0; cycle < 3; cycle++)
    {
        for(uint8_t i = 0; i < SERVO_NUM; i += 2)
        {
            Servo_SetAngle((ServoID)i, 45);
            if(i+1 < SERVO_NUM)
                Servo_SetAngle((ServoID)(i+1), 135);
        }
        Delay_ms(500);
        
        for(uint8_t i = 0; i < SERVO_NUM; i += 2)
        {
            Servo_SetAngle((ServoID)i, 135);
            if(i+1 < SERVO_NUM)
                Servo_SetAngle((ServoID)(i+1), 45);
        }
        Delay_ms(500);
    }
    
    // 回到初始位置
    for(uint8_t i = 0; i < SERVO_NUM; i++)
    {
        Servo_SetAngle((ServoID)i, 90);
    }
    
    printf("演示完成!\n");
}

四、编译与部署

4.1 Keil工程配置

复制代码
Target: STM32F103C8
Device: STM32F103C8T6
C/C++:
  Include Paths: .\inc; .\User; .\Hardware
  Define: STM32F10X_MD, USE_STDPERIPH_DRIVER
Linker:
  Scatter File: STM32_FLASH.sct
Debug:
  Debugger: ST-Link Debugger

4.2 使用说明

  1. 上电初始化:所有舵机转到90度中间位置
  2. 按键控制
    • 按键1:选中舵机1,角度增加5°
    • 按键2:选中舵机1,角度减少5°
    • 按键3:选中舵机2,角度增加5°
    • 按键4:选中舵机2,角度减少5°
  3. OLED显示:实时显示当前舵机和角度
  4. 紧急停止:可通过代码设置紧急停止标志

4.3 舵机角度对照表

角度 脉冲宽度 说明
500μs 最小位置
45° 1000μs 1/4位置
90° 1500μs 中间位置
135° 2000μs 3/4位置
180° 2500μs 最大位置

参考代码 stm32控制舵机程序 www.youwenfan.com/contentcsv/72263.html

五、注意事项

  1. 电源供应:舵机工作时电流较大,建议使用独立5V/2A电源
  2. 共地连接:STM32地和舵机电源地必须连接在一起
  3. 舵机保护:避免舵机堵转时间过长,以免烧毁舵机
  4. 速度控制:通过速度参数控制舵机转动速度,避免冲击
  5. 限位保护:在代码中设置角度限位,防止舵机损坏

六、扩展功能建议

  1. 串口控制:通过串口接收指令控制舵机
  2. 蓝牙/WiFi控制:添加无线控制模块
  3. 电位器反馈:使用电位器实现舵机位置反馈
  4. EEPROM存储:保存舵机位置和配置
  5. Web控制界面:通过网络控制舵机
相关推荐
星夜夏空9915 小时前
STM32单片机学习(27) —— SPI相关概念
stm32·单片机·学习
Hello:CodeWorld15 小时前
PCIe(PCI Express)技术详解:架构、演进与实践
linux·嵌入式硬件·express
周周记笔记15 小时前
半导体的坐标已经变了
嵌入式硬件
振南的单片机世界16 小时前
影子寄存器:改ARR下个周期才生效,波形不突变
arm开发·stm32·单片机·嵌入式硬件
芯岭技术16 小时前
XL2411蓝牙透传模组,通过MCU发送简单的串口AT指令,就能完成配网、数据传输等操作
单片机·嵌入式硬件
LS_learner16 小时前
内存申请和使用的场景分析(以AP->kernal->ISP为例)
嵌入式硬件
210Brian16 小时前
蓝桥杯单片机学习笔记(十四) V2026大模板源代码
单片机·学习·蓝桥杯
大卡片16 小时前
TIM控制器原理
单片机·嵌入式硬件
Tech_D16 小时前
微米级的精准魔法:激光微加工,解锁高端制造新可能
人工智能·单片机·机器人·自动化·制造