基于STM32的舵机控制系统(PWM控制)
一、舵机控制原理
1.1 舵机工作原理
- 控制信号:周期20ms(50Hz)的PWM方波
- 脉冲宽度:0.5ms2.5ms对应角度0°180°
- 角度计算公式:
脉冲宽度(ms) = 0.5 + 角度/180 * 2.0
1.2 角度与占空比关系
| 角度 | 脉宽(ms) | 占空比(20ms周期) | 对应计数值(720MHz) |
|---|---|---|---|
| 0° | 0.5ms | 2.5% | 1800 |
| 90° | 1.5ms | 7.5% | 5400 |
| 180° | 2.5ms | 12.5% | 9000 |
二、硬件连接(以STM32F103C8T6为例)
2.1 引脚连接
| 舵机线 | STM32引脚 | 备注 |
|---|---|---|
| 信号线(橙色) | PA0/PA6/PB6/PB8 | 任意定时器PWM输出 |
| 电源线(红色) | 5V电源 | 外部5V供电 |
| 地线(棕色) | GND | 与STM32共地 |
2.2 供电方案
// 注意:舵机需独立供电,避免电流过大损坏MCU
// 推荐方案:
// 1. 外部5V电源供电
// 2. 通过LDO(如AMS1117-5V)转换
// 3. 每个舵机并联100uF电容滤波
三、PWM配置(通用定时器)
3.1 定时器选择
// STM32F103C8T6定时器资源
// TIM1/2/3/4 支持PWM输出
// 推荐使用高级定时器(TIM1)或通用定时器(TIM2-4)
// 常用PWM引脚映射
// TIM1_CH1: PA8
// TIM1_CH2: PA9
// TIM1_CH3: PA10
// TIM1_CH4: PA11
// TIM2_CH1: PA0/PA5/PA15
// TIM2_CH2: PA1/PB3
// TIM3_CH1: PA6/PB4/PC6
// TIM3_CH2: PA7/PB5/PC7
// TIM4_CH1: PB6
// TIM4_CH2: PB7
// TIM4_CH3: PB8
// TIM4_CH4: PB9
3.2 PWM频率计算
// 系统时钟:72MHz
// 定时器分频:7200
// 计数频率:72MHz / 7200 = 10kHz
// 计数周期:10kHz = 0.1ms/计数
// 20ms周期需要计数:20ms / 0.1ms = 200
// 自动重装载值:200-1 = 199
// 0.5ms脉宽计数:0.5ms / 0.1ms = 5
// 2.5ms脉宽计数:2.5ms / 0.1ms = 25
四、标准库实现
4.1 头文件定义
// servo.h
#ifndef __SERVO_H
#define __SERVO_H
#include "stm32f10x.h"
// 舵机结构体定义
typedef struct {
TIM_TypeDef* TIMx; // 定时器
uint16_t TIM_Channel; // 定时器通道
float current_angle; // 当前角度
float target_angle; // 目标角度
float speed; // 旋转速度(度/秒)
uint8_t is_moving; // 是否在运动
} Servo_TypeDef;
// 舵机初始化结构体
typedef struct {
TIM_TypeDef* TIMx; // 定时器
uint16_t TIM_Channel; // 定时器通道
uint16_t min_pulse; // 最小脉宽(计数)
uint16_t max_pulse; // 最大脉宽(计数)
uint16_t init_angle; // 初始角度
} Servo_InitTypeDef;
// 函数声明
void Servo_Init(Servo_TypeDef* servo, Servo_InitTypeDef* init);
void Servo_SetAngle(Servo_TypeDef* servo, float angle);
void Servo_SetAngleImmediate(Servo_TypeDef* servo, float angle);
void Servo_SetSpeed(Servo_TypeDef* servo, float speed);
void Servo_Update(Servo_TypeDef* servo); // 更新运动
float Servo_GetAngle(Servo_TypeDef* servo);
uint8_t Servo_IsMoving(Servo_TypeDef* servo);
#endif
4.2 PWM初始化
// servo.c
#include "servo.h"
#include "delay.h"
#include "math.h"
// 全局变量
static uint16_t timer_arr = 199; // 自动重装载值(20ms)
static uint16_t timer_psc = 7199; // 预分频系数(10kHz)
// 初始化舵机
void Servo_Init(Servo_TypeDef* servo, Servo_InitTypeDef* init)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 1. 时钟使能
if (init->TIMx == TIM1) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
} else if (init->TIMx == TIM2) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
} else if (init->TIMx == TIM3) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
} else if (init->TIMx == TIM4) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
}
// 2. GPIO初始化
uint16_t pin = 0;
GPIO_TypeDef* port = NULL;
// 根据定时器和通道选择引脚
if (init->TIMx == TIM2) {
if (init->TIM_Channel == TIM_Channel_1) {
port = GPIOA;
pin = GPIO_Pin_0;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
} else if (init->TIM_Channel == TIM_Channel_2) {
port = GPIOA;
pin = GPIO_Pin_1;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}
} else if (init->TIMx == TIM3) {
if (init->TIM_Channel == TIM_Channel_1) {
port = GPIOA;
pin = GPIO_Pin_6;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
} else if (init->TIM_Channel == TIM_Channel_2) {
port = GPIOA;
pin = GPIO_Pin_7;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}
} else if (init->TIMx == TIM4) {
if (init->TIM_Channel == TIM_Channel_1) {
port = GPIOB;
pin = GPIO_Pin_6;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
} else if (init->TIM_Channel == TIM_Channel_2) {
port = GPIOB;
pin = GPIO_Pin_7;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
}
}
if (port != NULL) {
GPIO_InitStructure.GPIO_Pin = pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(port, &GPIO_InitStructure);
}
// 3. 定时器时基初始化
TIM_TimeBaseStructure.TIM_Period = timer_arr; // 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = timer_psc; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInit(init->TIMx, &TIM_TimeBaseStructure);
// 4. PWM输出初始化
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
TIM_OCInitStructure.TIM_Pulse = 0; // 初始脉冲宽度
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性高
// 初始化对应通道
switch(init->TIM_Channel) {
case TIM_Channel_1:
TIM_OC1Init(init->TIMx, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(init->TIMx, TIM_OCPreload_Enable);
break;
case TIM_Channel_2:
TIM_OC2Init(init->TIMx, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(init->TIMx, TIM_OCPreload_Enable);
break;
case TIM_Channel_3:
TIM_OC3Init(init->TIMx, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(init->TIMx, TIM_OCPreload_Enable);
break;
case TIM_Channel_4:
TIM_OC4Init(init->TIMx, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(init->TIMx, TIM_OCPreload_Enable);
break;
}
// 5. 使能定时器
TIM_Cmd(init->TIMx, ENABLE);
// 6. 如果是高级定时器,需要使能主输出
if (init->TIMx == TIM1) {
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
// 7. 初始化舵机结构体
servo->TIMx = init->TIMx;
servo->TIM_Channel = init->TIM_Channel;
servo->current_angle = init->init_angle;
servo->target_angle = init->init_angle;
servo->speed = 60.0f; // 默认60度/秒
servo->is_moving = 0;
// 8. 设置初始角度
Servo_SetAngleImmediate(servo, init->init_angle);
}
4.3 设置舵机角度
// 设置舵机角度(平滑运动)
void Servo_SetAngle(Servo_TypeDef* servo, float angle)
{
// 限制角度范围
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
servo->target_angle = angle;
servo->is_moving = 1;
}
// 立即设置舵机角度
void Servo_SetAngleImmediate(Servo_TypeDef* servo, float angle)
{
// 限制角度范围
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
// 计算脉冲宽度(计数)
// 0.5ms = 5计数, 2.5ms = 25计数
// 角度0-180对应计数5-25
uint16_t pulse = 5 + (uint16_t)(angle * 20.0f / 180.0f);
// 设置比较寄存器
switch(servo->TIM_Channel) {
case TIM_Channel_1:
TIM_SetCompare1(servo->TIMx, pulse);
break;
case TIM_Channel_2:
TIM_SetCompare2(servo->TIMx, pulse);
break;
case TIM_Channel_3:
TIM_SetCompare3(servo->TIMx, pulse);
break;
case TIM_Channel_4:
TIM_SetCompare4(servo->TIMx, pulse);
break;
}
servo->current_angle = angle;
servo->target_angle = angle;
servo->is_moving = 0;
}
4.4 平滑运动控制
// 更新舵机位置(需周期性调用)
void Servo_Update(Servo_TypeDef* servo)
{
static uint32_t last_time = 0;
uint32_t current_time = GetTickCount();
uint32_t delta_time = current_time - last_time;
if (delta_time < 10) // 10ms更新一次
return;
if (servo->is_moving) {
float angle_diff = servo->target_angle - servo->current_angle;
if (fabs(angle_diff) < 0.1f) {
// 到达目标位置
servo->current_angle = servo->target_angle;
servo->is_moving = 0;
} else {
// 计算移动步长
float step = (servo->speed * delta_time) / 1000.0f; // 度/毫秒
if (fabs(angle_diff) < step) {
servo->current_angle = servo->target_angle;
} else {
servo->current_angle += (angle_diff > 0 ? step : -step);
}
// 更新PWM
Servo_SetAngleImmediate(servo, servo->current_angle);
}
}
last_time = current_time;
}
五、HAL库实现
5.1 使用CubeMX配置
// 配置步骤:
// 1. 开启对应定时器
// 2. 选择Channel为PWM Generation CHx
// 3. 参数配置:
// Prescaler: 7199
// Counter Period: 199
// Pulse: 初始脉宽(如15对应1.5ms)
// 4. 生成代码
5.2 HAL库初始化
// servo_hal.h
#ifndef __SERVO_HAL_H
#define __SERVO_HAL_H
#include "main.h"
#include "tim.h"
typedef struct {
TIM_HandleTypeDef* htim; // 定时器句柄
uint32_t channel; // 定时器通道
float current_angle; // 当前角度
float target_angle; // 目标角度
float speed; // 旋转速度
uint8_t is_moving; // 是否在运动
} Servo_HAL_TypeDef;
// 函数声明
void Servo_HAL_Init(Servo_HAL_TypeDef* servo, TIM_HandleTypeDef* htim, uint32_t channel);
void Servo_HAL_SetAngle(Servo_HAL_TypeDef* servo, float angle);
void Servo_HAL_SetAngleImmediate(Servo_HAL_TypeDef* servo, float angle);
void Servo_HAL_Update(Servo_HAL_TypeDef* servo);
#endif
5.3 HAL库实现
// servo_hal.c
#include "servo_hal.h"
#include "math.h"
// 初始化舵机
void Servo_HAL_Init(Servo_HAL_TypeDef* servo, TIM_HandleTypeDef* htim, uint32_t channel)
{
servo->htim = htim;
servo->channel = channel;
servo->current_angle = 90.0f; // 默认90度
servo->target_angle = 90.0f;
servo->speed = 60.0f; // 默认60度/秒
servo->is_moving = 0;
// 启动PWM
HAL_TIM_PWM_Start(servo->htim, servo->channel);
// 设置初始角度
Servo_HAL_SetAngleImmediate(servo, 90.0f);
}
// 设置舵机角度
void Servo_HAL_SetAngle(Servo_HAL_TypeDef* servo, float angle)
{
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
servo->target_angle = angle;
servo->is_moving = 1;
}
// 立即设置舵机角度
void Servo_HAL_SetAngleImmediate(Servo_HAL_TypeDef* servo, float angle)
{
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
// 计算脉宽(计数)
uint16_t pulse = 5 + (uint16_t)(angle * 20.0f / 180.0f);
// 设置比较寄存器
__HAL_TIM_SET_COMPARE(servo->htim, servo->channel, pulse);
servo->current_angle = angle;
servo->target_angle = angle;
servo->is_moving = 0;
}
六、多舵机控制
6.1 舵机控制数组
// multi_servo.c
#include "multi_servo.h"
#define MAX_SERVO_NUM 8
Servo_TypeDef servos[MAX_SERVO_NUM];
uint8_t servo_count = 0;
// 添加舵机
uint8_t Servo_Add(Servo_InitTypeDef* init)
{
if (servo_count >= MAX_SERVO_NUM)
return 0;
Servo_Init(&servos[servo_count], init);
servo_count++;
return 1;
}
// 同时设置多个舵机角度
void Servo_SetMultipleAngles(uint8_t servo_indices[], float angles[], uint8_t count)
{
for (int i = 0; i < count; i++) {
if (servo_indices[i] < servo_count) {
Servo_SetAngle(&servos[servo_indices[i]], angles[i]);
}
}
}
// 更新所有舵机
void Servo_UpdateAll(void)
{
for (int i = 0; i < servo_count; i++) {
Servo_Update(&servos[i]);
}
}
6.2 舵机同步运动
// 舵机轨迹规划
typedef struct {
float start_angle;
float end_angle;
float duration; // 运动时间(秒)
uint32_t start_time;
uint8_t is_running;
} Servo_Trajectory;
void Servo_StartTrajectory(Servo_TypeDef* servo, float end_angle, float duration)
{
static Servo_Trajectory traj;
traj.start_angle = servo->current_angle;
traj.end_angle = end_angle;
traj.duration = duration;
traj.start_time = HAL_GetTick();
traj.is_running = 1;
// 计算所需速度
servo->speed = fabs(end_angle - servo->current_angle) / duration;
servo->target_angle = end_angle;
servo->is_moving = 1;
}
七、应用示例
7.1 机械臂控制
// robot_arm.c
#include "servo.h"
#include "math.h"
// 定义机械臂舵机
Servo_TypeDef base_servo; // 底座
Servo_TypeDef shoulder_servo; // 肩部
Servo_TypeDef elbow_servo; // 肘部
Servo_TypeDef wrist_servo; // 腕部
Servo_TypeDef gripper_servo; // 夹爪
// 初始化机械臂
void RobotArm_Init(void)
{
Servo_InitTypeDef init;
// 底座舵机 (TIM2_CH1 PA0)
init.TIMx = TIM2;
init.TIM_Channel = TIM_Channel_1;
init.init_angle = 90;
Servo_Init(&base_servo, &init);
// 肩部舵机 (TIM2_CH2 PA1)
init.TIMx = TIM2;
init.TIM_Channel = TIM_Channel_2;
init.init_angle = 45;
Servo_Init(&shoulder_servo, &init);
// 肘部舵机 (TIM3_CH1 PA6)
init.TIMx = TIM3;
init.TIM_Channel = TIM_Channel_1;
init.init_angle = 90;
Servo_Init(&elbow_servo, &init);
// 腕部舵机 (TIM3_CH2 PA7)
init.TIMx = TIM3;
init.TIM_Channel = TIM_Channel_2;
init.init_angle = 0;
Servo_Init(&wrist_servo, &init);
// 夹爪舵机 (TIM4_CH1 PB6)
init.TIMx = TIM4;
init.TIM_Channel = TIM_Channel_1;
init.init_angle = 0;
Servo_Init(&gripper_servo, &init);
}
// 控制夹爪
void RobotArm_Gripper(uint8_t state, float speed)
{
if (state) {
Servo_SetSpeed(&gripper_servo, speed);
Servo_SetAngle(&gripper_servo, 30); // 闭合
} else {
Servo_SetSpeed(&gripper_servo, speed);
Servo_SetAngle(&gripper_servo, 0); // 打开
}
}
// 移动到指定位置
void RobotArm_MoveTo(float base_angle, float shoulder_angle, float elbow_angle, float wrist_angle)
{
Servo_SetAngle(&base_servo, base_angle);
Servo_SetAngle(&shoulder_servo, shoulder_angle);
Servo_SetAngle(&elbow_servo, elbow_angle);
Servo_SetAngle(&wrist_servo, wrist_angle);
}
// 更新机械臂
void RobotArm_Update(void)
{
Servo_Update(&base_servo);
Servo_Update(&shoulder_servo);
Servo_Update(&elbow_servo);
Servo_Update(&wrist_servo);
Servo_Update(&gripper_servo);
}
7.2 云台控制
// gimbal.c
#include "servo.h"
#include "mpu6050.h"
Servo_TypeDef pitch_servo; // 俯仰舵机
Servo_TypeDef yaw_servo; // 偏航舵机
// PID控制器
typedef struct {
float Kp, Ki, Kd;
float error, last_error, integral;
float output;
} PID_Controller;
PID_Controller pitch_pid, yaw_pid;
// 云台初始化
void Gimbal_Init(void)
{
Servo_InitTypeDef init;
// 俯仰舵机
init.TIMx = TIM2;
init.TIM_Channel = TIM_Channel_1;
init.init_angle = 90;
Servo_Init(&pitch_servo, &init);
// 偏航舵机
init.TIMx = TIM2;
init.TIM_Channel = TIM_Channel_2;
init.init_angle = 90;
Servo_Init(&yaw_servo, &init);
// PID参数
pitch_pid.Kp = 1.0f;
pitch_pid.Ki = 0.01f;
pitch_pid.Kd = 0.1f;
yaw_pid.Kp = 1.0f;
yaw_pid.Ki = 0.01f;
yaw_pid.Kd = 0.1f;
}
// 稳定云台
void Gimbal_Stabilize(float target_pitch, float target_yaw)
{
float pitch, yaw;
// 获取IMU数据
MPU6050_GetAngle(&pitch, &yaw);
// 计算PID
float pitch_error = target_pitch - pitch;
float yaw_error = target_yaw - yaw;
// 俯仰控制
pitch_pid.integral += pitch_error;
float pitch_output = pitch_pid.Kp * pitch_error +
pitch_pid.Ki * pitch_pid.integral +
pitch_pid.Kd * (pitch_error - pitch_pid.last_error);
// 偏航控制
yaw_pid.integral += yaw_error;
float yaw_output = yaw_pid.Kp * yaw_error +
yaw_pid.Ki * yaw_pid.integral +
yaw_pid.Kd * (yaw_error - yaw_pid.last_error);
// 限制输出
pitch_output = (pitch_output < -45) ? -45 : (pitch_output > 45) ? 45 : pitch_output;
yaw_output = (yaw_output < -45) ? -45 : (yaw_output > 45) ? 45 : yaw_output;
// 更新舵机
Servo_SetAngleImmediate(&pitch_servo, 90 + pitch_output);
Servo_SetAngleImmediate(&yaw_servo, 90 + yaw_output);
pitch_pid.last_error = pitch_error;
yaw_pid.last_error = yaw_error;
}
八、高级功能
8.1 舵机校准
// servo_calibration.c
#include "servo.h"
// 舵机校准参数
typedef struct {
uint16_t pulse_0; // 0度对应的脉冲宽度
uint16_t pulse_180; // 180度对应的脉冲宽度
float offset; // 角度偏移
} Servo_Calibration;
// 校准舵机
void Servo_Calibrate(Servo_TypeDef* servo, Servo_Calibration* cal)
{
// 记录0度和180度时的实际脉冲宽度
// 这需要手动测量
}
// 使用校准参数设置角度
void Servo_SetAngleCalibrated(Servo_TypeDef* servo, float angle, Servo_Calibration* cal)
{
// 计算线性映射
float pulse_range = cal->pulse_180 - cal->pulse_0;
uint16_t pulse = cal->pulse_0 + (uint16_t)(angle * pulse_range / 180.0f);
// 设置比较寄存器
switch(servo->TIM_Channel) {
case TIM_Channel_1:
TIM_SetCompare1(servo->TIMx, pulse);
break;
// ... 其他通道
}
}
8.2 舵机保护
// servo_protection.c
#include "servo.h"
// 舵机限位保护
void Servo_SetAngleWithLimit(Servo_TypeDef* servo, float angle, float min_limit, float max_limit)
{
if (angle < min_limit) angle = min_limit;
if (angle > max_limit) angle = max_limit;
Servo_SetAngle(servo, angle);
}
// 舵机电流检测(需要硬件支持)
uint8_t Servo_CheckOverload(Servo_TypeDef* servo)
{
// 通过ADC检测电流
// 如果电流超过阈值,停止舵机
return 0; // 0表示正常
}
// 舵机温度保护
void Servo_ThermalProtection(Servo_TypeDef* servo)
{
// 检测温度,过热时降低PWM占空比或停止
}
参考代码 基于stm32舵机控制 www.youwenfan.com/contentcnv/103078.html
九、调试与测试
9.1 测试程序
// test_servo.c
#include "servo.h"
#include "delay.h"
void Test_Servo_Sweep(Servo_TypeDef* servo)
{
printf("Servo Sweep Test\n");
// 从0度到180度扫描
for (float angle = 0; angle <= 180; angle += 1) {
Servo_SetAngleImmediate(servo, angle);
printf("Angle: %.1f\n", angle);
Delay_ms(20);
}
// 从180度到0度扫描
for (float angle = 180; angle >= 0; angle -= 1) {
Servo_SetAngleImmediate(servo, angle);
printf("Angle: %.1f\n", angle);
Delay_ms(20);
}
}
void Test_Servo_Precision(Servo_TypeDef* servo)
{
printf("Servo Precision Test\n");
// 测试几个关键角度
float test_angles[] = {0, 45, 90, 135, 180};
for (int i = 0; i < 5; i++) {
Servo_SetAngleImmediate(servo, test_angles[i]);
printf("Set to: %.0f\n", test_angles[i]);
Delay_ms(1000);
}
}
9.2 串口控制
// uart_control.c
#include "servo.h"
#include "usart.h"
void UART_ControlServo(Servo_TypeDef* servo)
{
char buffer[32];
if (UART_Available()) {
fgets(buffer, sizeof(buffer), stdin);
if (strncmp(buffer, "set ", 4) == 0) {
float angle = atof(buffer + 4);
Servo_SetAngle(servo, angle);
printf("Set angle to: %.1f\n", angle);
} else if (strncmp(buffer, "get", 3) == 0) {
printf("Current angle: %.1f\n", servo->current_angle);
} else if (strncmp(buffer, "sweep", 5) == 0) {
Test_Servo_Sweep(servo);
}
}
}
十、性能优化
10.1 使用DMA更新多个舵机
// servo_dma.c
#include "servo.h"
// DMA传输PWM数据
void Servo_DMA_Update(Servo_TypeDef servos[], uint8_t count, uint16_t pulses[])
{
// 配置DMA传输多个PWM比较值
// 可以减少CPU中断开销
}
10.2 定时器同步
// 多个定时器同步启动
void Servo_Timer_Sync(void)
{
// 使用一个定时器作为主定时器
// 其他定时器从模式
}
十一、常见问题解决
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 舵机不转动 | 1. 电源不足 2. 信号线接错 3. PWM频率不对 |
1. 检查5V供电 2. 检查信号线连接 3. 检查PWM周期是否为20ms |
| 舵机抖动 | 1. 电源纹波大 2. 信号不稳定 3. 机械阻力大 |
1. 增加滤波电容 2. 检查信号线长度 3. 检查机械结构 |
| 角度不准 | 1. 舵机精度问题 2. 机械间隙 3. 供电电压低 |
1. 进行校准 2. 调整机械结构 3. 确保5V供电 |
| 响应慢 | 1. 速度设置过慢 2. 更新频率低 3. 舵机扭矩不足 |
1. 增加speed参数 2. 提高Servo_Update调用频率 3. 检查负载是否过重 |
十二、完整工程示例
12.1 主程序
// main.c
#include "stm32f10x.h"
#include "servo.h"
#include "delay.h"
#include "usart.h"
Servo_TypeDef my_servo;
int main(void)
{
// 系统初始化
SystemInit();
Delay_Init();
UART_Init(115200);
printf("Servo Control System Start\n");
// 舵机初始化
Servo_InitTypeDef servo_init;
servo_init.TIMx = TIM2;
servo_init.TIM_Channel = TIM_Channel_1;
servo_init.init_angle = 90;
Servo_Init(&my_servo, &servo_init);
// 设置运动速度
Servo_SetSpeed(&my_servo, 90.0f); // 90度/秒
while (1) {
// 测试序列
printf("Moving to 0 degrees\n");
Servo_SetAngle(&my_servo, 0);
while (Servo_IsMoving(&my_servo)) {
Servo_Update(&my_servo);
Delay_ms(10);
}
Delay_ms(1000);
printf("Moving to 180 degrees\n");
Servo_SetAngle(&my_servo, 180);
while (Servo_IsMoving(&my_servo)) {
Servo_Update(&my_servo);
Delay_ms(10);
}
Delay_ms(1000);
}
}

浙公网安备 33010602011771号