别再只会调角度了!用STM32CubeMX+MG90S舵机,5分钟搞定PWM精准控制

在嵌入式开发中,舵机控制是一个经典的应用场景。对于刚接触STM32的新手来说,手动配置PWM参数往往令人望而生畏——寄存器配置复杂、参数计算繁琐、调试过程耗时。而MG90S作为一款经济实惠的180度舵机,广泛应用于机器人、遥控模型等领域。本文将带你使用STM32CubeMX这一强大工具,快速实现从零到精准控制的完整流程。

1. 环境准备与硬件连接

1.1 所需材料清单

  • STM32开发板(如STM32F103C8T6)
  • MG90S舵机(工作电压4.8-6V)
  • 杜邦线若干
  • USB转TTL模块(用于串口调试)
  • ST-Link调试器(可选)

注意:舵机供电需单独处理,避免开发板5V输出电流不足导致抖动。推荐使用外接电源或稳压模块。

1.2 硬件连接示意图

STM32 PA7(PWM输出) → 舵机信号线(橙色)
STM32 GND → 舵机GND(棕色)
外部5V电源 → 舵机VCC(红色)

提示:若使用开发板供电,需确认其5V输出能力≥1A。MG90S堵转电流可达700mA。

2. STM32CubeMX工程配置

2.1 定时器PWM模式设置

  1. 打开CubeMX,选择对应STM32型号
  2. Pinout & Configuration 标签页:
    • 激活TIM3(或其他可用定时器)
    • 选择Channel2 → PWM Generation CH2
  3. 时钟树配置确保APB1 Timer Clocks为72MHz

2.2 关键参数计算

MG90S的控制信号要求:

  • 周期:20ms(50Hz)
  • 脉宽:0.5ms(0°)至2.5ms(180°)

Parameter Settings 中配置:

Prescaler (PSC) = 71    // 72MHz/(71+1) = 1MHz
Counter Period (ARR) = 19999  // 20ms/(1/1MHz) -1

此时生成的PWM频率为: $$ f_{PWM} = \frac{72MHz}{(71+1) \times (19999+1)} = 50Hz $$

2.3 生成工程代码

  1. Project Manager 中设置Toolchain为MDK-ARM或IDE
  2. 勾选 Generate peripheral initialization as a pair of .c/.h files
  3. 点击 GENERATE CODE 生成Keil工程

3. 角度控制实现

3.1 PWM占空比与角度换算

MG90S的角度-脉宽对应关系:

角度 脉宽(ms) CCR值计算公式
0.5 (ARR+1)*0.5/20
90° 1.5 (ARR+1)*1.5/20
180° 2.5 (ARR+1)*2.5/20

实际代码实现:

void Set_Servo_Angle(TIM_HandleTypeDef *htim, uint32_t Channel, float angle)
{
    if(angle > 180) angle = 180;
    if(angle < 0) angle = 0;
    
    uint32_t pulse = 500 + angle * (2000/180); // 500~2500us
    __HAL_TIM_SET_COMPARE(htim, Channel, pulse * (htim->Instance->ARR+1) / 20000);
}

3.2 动态控制技巧

通过HAL库函数实现平滑转动:

for(int angle=0; angle<=180; angle+=10){
    Set_Servo_Angle(&htim3, TIM_CHANNEL_2, angle);
    HAL_Delay(100); // 每100ms移动10度
}

进阶:可使用PID算法实现位置闭环控制,消除负载变化带来的角度误差。

4. 常见问题排查

4.1 舵机无反应检查清单

  1. 确认电源电压≥4.8V且电流充足
  2. 检查信号线是否连接至PWM输出引脚
  3. 验证定时器配置:
    • 使用逻辑分析仪测量输出波形
    • 确认 HAL_TIM_PWM_Start() 已调用

4.2 角度不准的校准方法

  1. 实测0°和180°对应的CCR值:
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 100); // 逐步调整
    
  2. 修改角度映射公式:
    // 替换原计算公式
    uint32_t pulse = SERVO_MIN + angle * (SERVO_MAX-SERVO_MIN)/180;
    

4.3 减少抖动的硬件方案

  • 在舵机电源端并联1000μF电容
  • 使用带磁环的电源线
  • 确保机械结构无卡顿

5. 进阶应用:多舵机协同控制

5.1 多定时器配置

在CubeMX中激活多个定时器:

  • TIM1_CH1 → 舵机1
  • TIM2_CH2 → 舵机2
  • TIM3_CH3 → 舵机3

5.2 机械臂控制实例

六自由度机械臂控制代码结构:

typedef struct {
    TIM_HandleTypeDef *htim;
    uint32_t channel;
    float current_angle;
} Servo_Instance;

Servo_Instance arm[6];

void Move_All_Joints(float angles[6])
{
    for(int i=0; i<6; i++){
        Set_Servo_Angle(arm[i].htim, arm[i].channel, angles[i]);
        arm[i].current_angle = angles[i];
    }
}

实际项目中建议使用RTOS任务管理各关节运动。

6. 性能优化技巧

6.1 中断方式更新角度

避免频繁调用HAL库函数:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim4){ // 专用定时器触发
        static uint32_t target_ccr = 1500;
        TIM3->CCR2 = target_ccr; // 直接操作寄存器
    }
}

6.2 使用DMA减轻CPU负载

CubeMX配置步骤:

  1. 在TIM3配置中启用DMA
  2. 添加Memory-to-Peripheral传输
  3. 设置数据宽度为Word

应用示例:

uint32_t ccr_values[3] = {1500, 1750, 2000};
HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_2, ccr_values, 3);

6.3 低功耗模式下的控制

在STOP模式下维持PWM输出:

  1. 配置定时器为 Clock Source: LSI
  2. 设置唤醒中断:
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化时钟
SystemClock_Config();
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐