一、PWM 驱动电机的原理

PWM 通过固定频率的方波信号,改变高电平占空比(0%~100%)来调整输出功率。对于直流电机,平均电压 = 电源电压 × 占空比,从而改变电枢电流,实现转速调节。STM32 的定时器(如 TIM1~TIM8)具有硬件 PWM 生成能力,无需 CPU 干预即可持续输出波形。

关键参数:

  • 频率:通常 10kHz~20kHz,避免 audible noise,同时保证电流纹波可控。
  • 占空比:决定平均电压,正转/反转需配合 H 桥方向引脚。
  • 分辨率:取决于定时器重载值(ARR),如 ARR=999 时,占空比步进为 0.1%。

二、STM32 定时器 PWM 工作原理

以通用定时器 TIM3 为例,PWM 输出基于以下寄存器:

  • TIMx_PSC(预分频器):将时钟分频,得到计数频率。
  • TIMx_ARR(自动重装载):决定 PWM 频率。
  • TIMx_CCR(捕获/比较):与计数器值比较,控制占空比。

输出模式为 PWM1 时:

  • 计数器 < CCR → 输出有效电平(默认高)
  • 计数器 ≥ CCR → 输出无效电平(默认低)

因此,占空比 = CCR / (ARR+1)。通过修改 CCR 即可在线调速。

三、硬件连接与 H 桥简介

MCU 的 GPIO 输出电流有限,不能直接驱动电机。常用方案是使用 H 桥(如 L298N、DRV8833)或集成 MOS 驱动。H 桥需要两个控制端:

  • PWM 输入:接收占空比信号
  • 方向引脚:控制正反转

例如,L298N 的 ENA 接 PWM,IN1/IN2 决定方向。注意共地,避免电流干扰。

四、STM32CubeMX 配置步骤

1. 选择定时器

  • 打开 STM32CubeMX,配置 TIM3。
  • 时钟源选择 Internal Clock
  • Channel1 选择 PWM Generation CH1
  • 设置 Prescaler = 71(72MHz/72 = 1MHz 计数时钟)
  • 设置 Counter Period (ARR) = 999(则 PWM 频率 = 1MHz / 1000 = 1kHz)
  • 初始占空比设为 500(50%)

2. 配置 GPIO

  • 若使用 L298N,需额外配置两个 GPIO 为输出,用于方向控制。

3. 生成工程

  • 选择 HAL 库,生成代码。

五、HAL 库代码示例

以下为核心代码(基于 STM32F103,已包含在 main.c 中):

// 启动 PWM 输出(由 CubeMX 生成的初始化函数中已调用)
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

// 方向控制引脚定义(假设 PA4=IN1, PA5=IN2)
#define MOTOR_FORWARD  {HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, SET); \
                        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, RESET);}
#define MOTOR_BACKWARD {HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, RESET); \
                        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, SET);}
#define MOTOR_STOP      {HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, RESET); \
                        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, RESET);}

// 调速函数(speed: 0~1000,对应 0%~100%)
void Motor_SetSpeed(uint16_t speed) {
    if (speed > 1000) speed = 1000;
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, speed);
}

// 使用示例
int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM3_Init();

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    
    while (1) {
        MOTOR_FORWARD;
        Motor_SetSpeed(600);  // 60% 占空比正转
        HAL_Delay(3000);
        
        MOTOR_BACKWARD;
        Motor_SetSpeed(400);  // 40% 占空比反转
        HAL_Delay(3000);
        
        MOTOR_STOP;
        HAL_Delay(1000);
    }
}

六、调试与优化技巧

  • 若电机有高频啸叫,检查 PWM 频率是否在 16kHz 以上(人耳听不见)。
  • 低速时会出现死区(电机不转),可在软件中做非线性映射,或用 PID 补偿。
  • 使用示波器观察 PWM 波形,确保占空比与预期一致,同时检查是否有毛刺(可能导致电机抖动)。

七、注意事项

  1. 共地问题:电机电源和单片机必须共地,否则逻辑电平不稳定。
  2. 电源滤波:电机启动电流大,需在电源端并联 100μF~470μF 电解电容和 0.1μF 陶瓷电容。
  3. 隔离与保护:若电机功率较大,建议使用光耦隔离驱动信号;并对 PWM 引脚进行限流保护。
  4. 死区时间:若使用 H 桥全桥驱动,必须在上下管切换时插入死区,避免直通短路。可配置 STM32 高级定时器的死区寄存器(如 TIM1_BDTR)。
  5. 频率选择:不宜过高(>100kHz),否则开关损耗增大;也不宜过低(<5kHz),会引起扭矩波动。

总结

本文从 PWM 原理切入,演示了 STM32 定时器生成 PWM 的配置与 HAL 代码。实际工程中,需根据电机型号、驱动器特性调整频率与死区,并配合速度闭环(如 PID)实现精准控制。基础打好,后续可扩展至 FOC 或 BLDC 控制。