STM32 电机控制基础:从 PWM 原理到调速实现
👁 3 阅读 · 2026-08-15 · STM32 电机
电机控制是嵌入式开发中的经典场景,而 PWM(脉冲宽度调制)则是驱动直流电机、舵机等执行器的核心手段。本文从 PWM 工作原理出发,基于 STM32 定时器讲解如何生成可调占空比的 PWM 信号,并配合 H 桥电路实现直流电机调速。内容涵盖寄存器级配置步骤、HAL 库代码示例、死区与防抖注意事项,帮助开发者快速搭建可靠的电机控制基础框架。
## 一、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 中):
```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 控制。