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 使用说明
- 上电初始化:所有舵机转到90度中间位置
- 按键控制 :
- 按键1:选中舵机1,角度增加5°
- 按键2:选中舵机1,角度减少5°
- 按键3:选中舵机2,角度增加5°
- 按键4:选中舵机2,角度减少5°
- OLED显示:实时显示当前舵机和角度
- 紧急停止:可通过代码设置紧急停止标志
4.3 舵机角度对照表
| 角度 | 脉冲宽度 | 说明 |
|---|---|---|
| 0° | 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
五、注意事项
- 电源供应:舵机工作时电流较大,建议使用独立5V/2A电源
- 共地连接:STM32地和舵机电源地必须连接在一起
- 舵机保护:避免舵机堵转时间过长,以免烧毁舵机
- 速度控制:通过速度参数控制舵机转动速度,避免冲击
- 限位保护:在代码中设置角度限位,防止舵机损坏
六、扩展功能建议
- 串口控制:通过串口接收指令控制舵机
- 蓝牙/WiFi控制:添加无线控制模块
- 电位器反馈:使用电位器实现舵机位置反馈
- EEPROM存储:保存舵机位置和配置
- Web控制界面:通过网络控制舵机