4、基础驱动代码:使用Arduino控制H桥正反转、PWM调速原理、死区时间的软件实现

好,咱们直接进入正题。前面我们把H桥的硬件原理讲透了,现在该让代码跑起来了。

我个人习惯用Arduino来做原型验证,原因很简单:上手快,调试方便。你想想看,如果每次调个PWM都要翻半天手册配寄存器,那多耽误事儿。先用Arduino把逻辑跑通,再移植到STM32或者其它MCU上,这是我最常用的套路。

4.1 基础正反转控制

先来个最简单的。控制两个电机引脚的高低电平,就能让电机转起来。

看下面这段代码,我故意把注释写得很详细,方便你理解:

// H桥电机控制 - 基础正反转
// 引脚定义
#define MOTOR_IN1 9   // H桥输入1
#define MOTOR_IN2 10  // H桥输入2

void setup() {
  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);
  
  // 初始状态:电机停止
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
}

void loop() {
  // 正转:IN1高,IN2低
  digitalWrite(MOTOR_IN1, HIGH);
  digitalWrite(MOTOR_IN2, LOW);
  delay(2000);  // 转2秒
  
  // 停止
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
  delay(1000);  // 停1秒
  
  // 反转:IN1低,IN2高
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, HIGH);
  delay(2000);  // 转2秒
  
  // 停止
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
  delay(1000);  // 停1秒
}
小提示:千万别让IN1和IN2同时为高!那就是短路,我见过有人把驱动芯片烧冒烟的。嗯,真事儿。

4.2 PWM调速原理

光能正反转还不够,速度也得能调。这时候就要请出PWM了。

PWM,说白了就是快速开关电源。你想想看,如果一秒钟开关1000次,每次开的时间长一点,电机得到的平均电压就高,转得就快。反之就慢。

这个比例叫占空比。占空比50%,相当于给电机一半的电压。占空比100%,就是全速。

Arduino的analogWrite()函数就是干这个的。取值范围0到255,对应0%到100%的占空比。

// PWM调速示例
#define MOTOR_IN1 9
#define MOTOR_IN2 10
#define PWM_PIN 9   // 用带PWM功能的引脚

void setup() {
  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);
}

void loop() {
  // 正转,速度逐渐加快
  digitalWrite(MOTOR_IN1, HIGH);
  digitalWrite(MOTOR_IN2, LOW);
  
  for (int speed = 0; speed <= 255; speed += 5) {
    analogWrite(PWM_PIN, speed);
    delay(100);
  }
  
  // 全速转2秒
  delay(2000);
  
  // 减速停止
  for (int speed = 255; speed >= 0; speed -= 5) {
    analogWrite(PWM_PIN, speed);
    delay(100);
  }
  
  delay(1000);
}
关键点:PWM频率不能太低。我试过用50Hz去驱动电机,结果电机嗡嗡响,跟蚊子叫似的。一般电机驱动用1kHz到20kHz比较合适。Arduino默认的PWM频率是490Hz或980Hz,够用。

4.3 死区时间的软件实现

这是个大坑,我得好好说说。

死区时间是什么?就是H桥上下两个管子切换时,故意插入的一段「都关断」的时间。为什么要这么做?

因为MOS管开关需要时间。你让上管关断的同时让下管导通,上管还没完全关断呢,下管已经通了——瞬间短路!这叫「直通」,电流会大得吓人。

我曾经在一个项目中忽略了这个问题,结果驱动板上的MOS管烫得能煎鸡蛋。从那以后,我写驱动代码必加死区。

软件实现死区其实很简单:在切换方向时,先让两个管子都关断,等一小会儿,再打开目标管子。

// 带死区时间的H桥控制
#define MOTOR_IN1 9
#define MOTOR_IN2 10
#define DEAD_TIME 100  // 死区时间,单位微秒

void motor_forward(int speed) {
  // 先全部关断
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
  delayMicroseconds(DEAD_TIME);  // 死区等待
  
  // 设置正转
  digitalWrite(MOTOR_IN1, HIGH);
  digitalWrite(MOTOR_IN2, LOW);
  analogWrite(MOTOR_IN1, speed);
}

void motor_reverse(int speed) {
  // 先全部关断
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
  delayMicroseconds(DEAD_TIME);  // 死区等待
  
  // 设置反转
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, HIGH);
  analogWrite(MOTOR_IN2, speed);
}

void motor_stop() {
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);
}

void setup() {
  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);
  motor_stop();
}

void loop() {
  motor_forward(200);  // 正转,速度200
  delay(3000);
  
  motor_stop();
  delay(1000);
  
  motor_reverse(200);  // 反转,速度200
  delay(3000);
  
  motor_stop();
  delay(1000);
}
警告:死区时间不是越长越好。太长了会影响电机响应速度,而且会产生噪音。一般1到10微秒就够了。具体多少,得看你用的MOS管型号和驱动电路。

4.4 知识结构图

下面这张图,把本章的核心逻辑串起来了:

H桥驱动代码知识结构 H桥驱动代码 正反转控制 PWM调速原理 死区时间实现 IN1=H, IN2=L → 正转 IN1=L, IN2=H → 反转 占空比控制速度 analogWrite(0~255) 切换前先全部关断 delayMicroseconds()等待 三者结合:正反转 + 调速 + 死区 = 完整驱动

4.5 实际项目中的避坑指南

  • 电源要稳:电机启动瞬间电流很大,我见过Arduino直接被拉复位的情况。建议电机和逻辑电路分开供电。
  • 地线要粗:大电流回路的地线,别用细线。我曾经用杜邦线接过电机,结果线都烧化了。
  • PWM频率别太低:低于100Hz电机就会抖动,听着像在打拍子。
  • 死区时间别省:省了死区,省下的钱全得买新MOS管。
我的习惯:调试时先用小电压(比如5V)测试逻辑,确认正反转和PWM都正常了,再接上电机的大电源。这样就算代码写错了,也不至于炸管子。

好了,这一章的内容就到这儿。代码都给你了,找个板子试试吧。记住,理论再漂亮,不如亲手跑一遍来得实在。


专注资料整理