4、电机驱动原理:H桥电路详解、直流电机正反转与调速原理、PWM基础知识

好,咱们进入第四章。前面几章我们把 GPIO 和 UART 的基础打牢了,现在终于要碰电机了。说实话,电机驱动是嵌入式开发里最容易出“烟火表演”的环节——我早年就烧过好几个驱动芯片,那味道,记忆犹新。

这一章的核心就三件事:H桥怎么让电机转起来、怎么让它反转、怎么用PWM调速。说白了,就是控制电机的“方向”和“速度”。

4.1 H桥电路详解

直流电机最简单的玩法:给电就转,断电就停。但你要让它反转怎么办?换电源极性。可单片机不能直接换极性啊,这时候就需要 H 桥了。

H桥的名字很形象——四个开关管(通常是 MOSFET 或三极管)搭成一个“H”形状,电机接在中间横杠上。

核心思想:通过控制四个开关的通断组合,改变流过电机的电流方向,从而控制正反转。

4.1.1 基本结构

一个标准的 H 桥由四个开关管组成:

  • Q1(左上)、Q2(右上)——高端开关,接电源正极
  • Q3(左下)、Q4(右下)——低端开关,接电源负极(GND)
  • 电机接在 Q1/Q3 连接点和 Q2/Q4 连接点之间

下面这张图把 H 桥的结构和四种工作状态都画出来了,建议你多看两眼。

H桥电路结构与工作状态 Q1 Q2 Q3 Q4 M 电机 VCC (电源正极) GND (电源负极) 状态1:正转 Q1导通 Q4导通 Q2关断 Q3关断 电流:左→右 状态2:反转 Q2导通 Q3导通 Q1关断 Q4关断 电流:右→左 状态3:刹车 Q3导通 Q4导通 Q1关断 Q2关断 电机两端短接GND 状态4:惰行 全部开关关断 电机自由旋转 靠惯性继续转 ⚠ 注意:Q1和Q2、Q3和Q4不能同时导通! 否则电源直接短路,瞬间冒烟。

4.1.2 四种工作状态

H桥有四种基本状态,我整理成了一张表,方便你对照:

状态 导通的开关 电流方向 电机行为
正转 Q1 + Q4 左 → 右 正向旋转
反转 Q2 + Q3 右 → 左 反向旋转
刹车 Q3 + Q4 无(短接) 急停
惰行 全部关断 无 自由停止

致命陷阱:直通(Shoot-Through)

我曾经调试一个电机驱动板,上电瞬间芯片直接冒烟。查了半天,发现是软件里 Q1 和 Q2 同时导通了——电源正极直接对地短路,电流瞬间几十安培。记住:同一侧的上下管绝对不能同时导通。切换方向时,必须先关断所有开关,留一个“死区时间”,再打开另一组。

4.2 直流电机正反转与调速原理

有了 H 桥,正反转就很简单了。但调速呢?直流电机的转速和两端电压成正比——电压越高,转得越快。可单片机只能输出 0V 或 3.3V/5V,怎么调出中间电压?

答案就是:PWM(脉冲宽度调制)。

4.2.1 PWM 基础知识

PWM 说白了就是“快速开关电源”。你以很高的频率(比如 1kHz)不停地开、关,电机由于机械惯性,不会跟着每个脉冲抖动,而是感受到一个“平均电压”。

举个例子:

  • 5V 电源,50% 时间开,50% 时间关 → 平均电压 ≈ 2.5V
  • 5V 电源,80% 时间开,20% 时间关 → 平均电压 ≈ 4.0V

这个“开的时间比例”就叫占空比(Duty Cycle)。

核心公式:

平均电压 = 电源电压 × 占空比

占空比 = 高电平时间 / (高电平时间 + 低电平时间) × 100%

4.2.2 关键参数

参数 说明 典型值
频率 每秒开关次数 1kHz ~ 20kHz
周期 一次开关的总时间 1ms(1kHz时)
占空比 高电平时间占比 0% ~ 100%
分辨率 占空比可调节的步进数 8位(256级)或16位(65536级)

频率怎么选?

我个人习惯:

  • 普通直流电机:1kHz ~ 5kHz 就够了,频率太低电机会“咔咔”响
  • 带减速箱的电机:可以低一些,500Hz ~ 1kHz
  • 有刷电机:超过 20kHz 人耳听不到,但开关损耗会增加

我在一个项目中用过 50Hz 的 PWM,结果电机像在打拍子,嗡嗡响得头疼。后来改到 2kHz,世界清净了。

4.2.3 用 PWM 控制电机转速

结合 H 桥和 PWM,我们就可以同时控制方向和速度了:

  1. 方向控制:通过 H 桥的开关组合决定
  2. 速度控制:对导通的那一组开关管施加 PWM 信号

举个例子,正转调速:

  • Q1 和 Q4 导通,但 Q1 的栅极接 PWM 信号
  • 占空比 100% → 全速正转
  • 占空比 50% → 半速正转
  • 占空比 0% → 停止

反转同理,把 PWM 加到 Q2 或 Q3 上就行。

4.3 实战:用 STM32 输出 PWM 控制电机

理论说完了,来点实际的。下面是一个用 STM32 定时器输出 PWM 的代码片段,控制电机正转并调速。

// 使用 TIM2 的通道1(PA0)输出 PWM
// 配置:频率 1kHz,占空比 50%

void Motor_PWM_Init(void) {
    // 1. 使能定时器和GPIO时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;

    // 2. 配置 PA0 为复用功能(AF2 = TIM2_CH1)
    GPIOA->MODER &= ~(3 << 0);   // 清零
    GPIOA->MODER |= (2 << 0);    // 复用功能模式
    GPIOA->AFR[0] &= ~(0xF << 0);
    GPIOA->AFR[0] |= (1 << 0);   // AF1 = TIM2

    // 3. 配置定时器
    TIM2->PSC = 83;               // 预分频:84MHz / (83+1) = 1MHz
    TIM2->ARR = 999;              // 自动重装:1MHz / (999+1) = 1kHz
    TIM2->CCR1 = 500;             // 占空比:500 / 1000 = 50%

    // 4. 配置 PWM 模式1
    TIM2->CCMR1 &= ~(7 << 4);    // 清零 OC1M
    TIM2->CCMR1 |= (6 << 4);     // PWM 模式1
    TIM2->CCER |= TIM_CCER_CC1E;  // 使能输出

    // 5. 启动定时器
    TIM2->CR1 |= TIM_CR1_CEN;
}

// 调速函数
void Motor_SetSpeed(uint16_t duty) {
    if(duty > 1000) duty = 1000;  // 限制范围
    TIM2->CCR1 = duty;            // 更新占空比
}

避坑指南:

我曾经在调试时发现电机转速不稳,用示波器一看,PWM 波形偶尔会“丢脉冲”。查了半天,原来是定时器中断优先级太低,被其他中断打断了。解决办法:把定时器更新中断优先级设高,或者干脆不用中断,只靠硬件自动输出。

4.4 常见问题与注意事项

最后总结几个我踩过的坑:

  • 电机启动电流很大:堵转时电流可能是额定电流的 5~10 倍。选驱动芯片时一定要留余量,别卡着额定值选。
  • 续流二极管不能省:电机是感性负载,关断时会产生反向电动势。不加续流二极管,电压尖峰能击穿 MOSFET。
  • PWM 频率别太低:低于 100Hz 电机就会“步进式”转动,噪音大、抖动厉害。
  • 死区时间要留够:切换方向时,先关断所有开关,等几十微秒再打开另一组。我一般设 1~5μs。

安全第一:

电机驱动电路调试时,手边一定要放个急停开关。我第一次做电机驱动时,程序跑飞了,电机直接全速撞到限位块,把机械结构都撞坏了。从那以后,我所有电机项目都会加硬件急停和软件看门狗。