使用 DRV8833 电机驱动器和 Arduino 控制直流电机

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第1张图片

毫无疑问,L293D和L298N是 Arduino 项目的首选电机驱动器。它们非常可靠,并已在数百个甚至数千个项目中使用。然而,它们有一个主要缺点——它们使用双极结型晶体管 (BJT),这使得它们的效率极低。

BJT 的问题在于它们具有通态压降。来自该电压的能量需要到达某个地方,而且确实如此;它以热量的形式消散。随着时间的推移,这可能会导致大量的能量损失,在某些情况下,还会导致驱动器过热。对于必须长时间运行的项目来说,这可能是一个重大缺点。

值得庆幸的是,像 DRV8833 这样的现代电机驱动器在效率方面确实表现出色。DRV8833 使用 MOSFET,而不是 BJT。MOSFET 的压降几乎可以忽略不计,这意味着几乎所有来自电源的电压都会传递到电机。这就是为什么 DRV8833 不仅比基于 BJT 的电机驱动器更节能,而且产生的热量也少得多,因此长时间使用更安全。

因此,让我们深入了解 DRV8833 电机驱动器的卓越功能。

DRV8833 电机驱动器

该模块的核心是德州仪器 (TI) 的集成 H 桥驱动器 IC,它针对电机驱动应用进行了优化 - DRV8833。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第2张图片

DRV8833 具有两个 NMOS H 桥驱动器,使其能够控制两个直流有刷电机、一个双极步进电机、螺线管和其他电感负载。

它的工作电压范围为 2.7 V 至 10.8 V,每个通道可连续提供高达 1.2 A 的电流。此外,它还可以承受每通道高达 2 A 的峰值电流几秒钟。

DRV8833 还包含多种保护功能,例如欠压锁定、过流和过热保护,提供高水平的可靠性。这些事件中的每一个都会禁用 H 桥 MOSFET。故障情况消除后,设备将恢复运行。

它还包括低功耗睡眠模式,可让您节省电量,尤其是在电机不使用时。

所有这些功能使其成为为小型低压电机供电的绝佳选择。

技术规格

以下是规格:

电机电压 2.7V – 10.8V
逻辑电压 3V 和 5V 兼容
连续输出电流 1.2A(每通道)
峰值输出电流 2A(每通道)
电机通道 2
保护特性 欠压锁定、过流和过热

欲了解更多信息,请参阅下面的数据表。

DRV8833 数据表

DRV8833 电机驱动器引脚分配

DRV8833 驱动器共有 12 个引脚用于将其与外界连接。引脚排列如下:

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第3张图片

让我们一一了解所有引脚。

电源引脚

与大多数电机驱动器不同,DRV8833 只有一个电源连接(因为电机电压与逻辑电压相同)。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第4张图片

VCCGND是连接驱动电机的电源的地方,电压范围为 2.7V 至 10.8V。

请注意,DRV8833 可以在低至 2.7V 的电压下工作。这意味着它非常适合低压项目,例如使用单节锂聚合物电池和低压电机运行的项目。

输出引脚

DRV8825电机驱动器的输出引脚,即OUT1,OUT2,OUT3, 和OUT4,位于模块的一侧,方便连接。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第5张图片

电机 A 应连接到 OUT1 和 OUT2,而电机 B 应连接到 OUT3 和 OUT4。您可以将 2.7 V 至 10.8 V 范围内的任何有刷直流电机连接到这些引脚。

请记住,DRV8833 可以为一对直流电机连续提供每个通道 1.2 A(峰值 2 A)的电流。

控制输入​​引脚

每个电机有两个控制输入;IN1和IN2是电机 A 的控制输入,而IN3IN4用于电机 B。这些控制输入允许您控制电机的速度和旋转方向。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第6张图片

方向控制:

电机的旋转方向可以通过对这些输入施加逻辑高电平 (5V) 或逻辑低电平(接地)来控制。下面的真值表显示了输入如何影响驱动器输出。

输入1/输入3 输入2/输入4 旋转方向
低(0) 低(0) 电机关闭
高(1) 低(0) 向前
低(0) 高(1) 向后
高(1) 高(1) 电机关闭

这里要注意一个问题,如果同时设置为低电平,则电机停止状态,如果同时设置为高电平则电机处于刹车状态,两者的区别是停止状态时电机不会马上停止,还有一个惯性,经过一段时间才能停止;如果是刹车状态,可以理解成紧急停车,电机马上就不转了。

速度控制:

如果您想控制速度,可以在通常为高电平的引脚上使用脉宽调制 (PWM)。如果不需要速度控制,只需将它们设置为“高”或“低”即可。

请注意,控制输入在内部被拉低,默认情况下有效禁用电机驱动器输出。

睡眠模式引脚

sleep引脚(板上丝印上标有 EEP)控制 DRV8833 的睡眠模式。将该引脚设置为低电平会使 DRV8833 进入低功耗睡眠模式,而将其设置为高电平则使其再次激活。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第7张图片

在此模式下,H 桥被禁用,栅极驱动电荷泵被停止,所有内部逻辑被重置,所有内部时钟被停止,并且所有输入被忽略。需要注意的是,从睡眠模式返回时,电机驱动器需要一点时间(最多 1 毫秒)才能再次完全运行。

默认情况下,板上的 SLEEP 引脚被拉高,因此如果您不打算使用低功耗睡眠模式,则可以将其保持断开状态。

DRV8833 模块的背面有一个焊接跳线 J1。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第8张图片

默认情况下,J1 关闭,这会将板载上拉电阻连接到 SLEEP 引脚,从而保持 DRV8833 启用。但是,如果打开 J1,板载上拉电阻将与 SLEEP 引脚断开。此操作启用片上下拉,这意味着 DRV8833 默认情况下将保持禁用状态。因此,如果您选择打开 J1,请记住您需要在需要时手动打开 DRV8833。

故障检测引脚

FAULT引脚(板上丝印上标记为 ULT)是一个开漏输出,每当发生过流、过热或欠压情况时,该输出都会被芯片驱动为低电平。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第9张图片

默认情况下,该引脚保持浮空状态。因此,如果您想监视驱动器上的故障情况,则需要连接一个外部上拉电阻(或使用启用了内置上拉的微控制器输入)。

限流

DRV8833 可以主动限制通过电机的电流。这通常是通过在 AISEN 引脚和地之间连接一个电阻来设置电机 A 的限制,并在 BISEN 引脚和地之间连接另一个电阻来设置电机 B 的限制来实现的。

然而,这个特定的 DRV8833 分线板将这些电流检测引脚直接连接到地,从而有效地禁用电流限制功能。

将 DRV8833 模块连接到 Arduino

现在我们已经了解了该模块的所有信息,我们可以开始将其连接到我们的 Arduino 了!

首先,连接电机电源。VCC 引脚是电机的电源,应根据电机要求(2.7V 至 10.8V)连接到适当的电源。在我们的实验中,我们使用直流变速箱电机,也称为“TT”电机,常见于两轮驱动机器人中。它们的额定电压为 3 至 12V。因此,我们将外部 5V 电源连接到 VCC 引脚。

现在将 DRV8833 的控制输入(IN1、IN2、IN3 和 IN4)连接到 Arduino 上的四个数字输出引脚(10、9、6 和 5)。请注意所有这些引脚均启用 PWM,目的是控制电机的速度

将一个电机连接至端子 A(OUT1 和 OUT2),将另一个电机连接至端子 B(OUT3 和 OUT4)。您可以更换电机的连接。从技术上讲,没有正确或错误的方法。

如果您想监控故障情况,可以将 FAULT 引脚连接到 Arduino 上的数字引脚。请记住为此引脚使用外部上拉电阻或启用 Arduino 中的内置上拉电阻,因为它是开漏输出。

最后,确保您的电路和 Arduino 共享一个公共地。

下表列出了将 DRV8833 电机驱动器连接到 Arduino 的引脚连接:

DRV8833 驱动程序 Arduino
接地 接地
IN1 10
IN2 9
IN3 6
IN4 5

下图显示了如何构建电路。

使用 DRV8833 电机驱动器和 Arduino 控制直流电机_第10张图片

Arduino 示例代码

下面的草图将向您展示如何使用 DRV8833 电机驱动器控制一对直流电机的速度和旋转方向,可以作为更多实际实验和项目的基础。

该草图以不同的速率和方向移动一对直流电机。

当电机加速或减速时,您可能会听到嗡嗡声(说明速度太低了),特别是在较低的 PWM 值下。这个是正常的; 没有什么可担心的。发生这种情况是因为直流电机需要最低电压才能运行。

// Define the control inputs
#define MOT_A1_PIN 10
#define MOT_A2_PIN 9
#define MOT_B1_PIN 6
#define MOT_B2_PIN 5

void setup(void)
{
  // Set all the motor control inputs to OUTPUT
  pinMode(MOT_A1_PIN, OUTPUT);
  pinMode(MOT_A2_PIN, OUTPUT);
  pinMode(MOT_B1_PIN, OUTPUT);
  pinMode(MOT_B2_PIN, OUTPUT);

  // Turn off motors - Initial state
  digitalWrite(MOT_A1_PIN, LOW);
  digitalWrite(MOT_A2_PIN, LOW);
  digitalWrite(MOT_B1_PIN, LOW);
  digitalWrite(MOT_B2_PIN, LOW);

  // Initialize the serial UART at 9600 baud
  Serial.begin(9600);
}

void loop(void)
{
  // Generate a fixed motion sequence to demonstrate the motor modes.

  // Ramp speed up.
  for (int i = 0; i < 11; i++) {
    spin_and_wait(25*i, 25*i, 500);
  }
  // Full speed forward.
  spin_and_wait(255,255,2000);

  // Ramp speed into full reverse.
  for (int i = 0; i < 21 ; i++) {
    spin_and_wait(255 - 25*i, 255 - 25*i, 500);
  }

  // Full speed reverse.
  spin_and_wait(-255,-255,2000);

  // Stop.
  spin_and_wait(0,0,2000);

  // Full speed, forward, turn, reverse, and turn for a two-wheeled base.
  spin_and_wait(255, 255, 2000);
  spin_and_wait(0, 0, 1000);
  spin_and_wait(-255, 255, 2000);
  spin_and_wait(0, 0, 1000);
  spin_and_wait(-255, -255, 2000);
  spin_and_wait(0, 0, 1000);
  spin_and_wait(255, -255, 2000);
  spin_and_wait(0, 0, 1000);
}

/// Set the current on a motor channel using PWM and directional logic.
///
/// \param pwm    PWM duty cycle ranging from -255 full reverse to 255 full forward
/// \param IN1_PIN  pin number xIN1 for the given channel
/// \param IN2_PIN  pin number xIN2 for the given channel
void set_motor_pwm(int pwm, int IN1_PIN, int IN2_PIN)
{
  if (pwm < 0) {  // reverse speeds
    analogWrite(IN1_PIN, -pwm);
    digitalWrite(IN2_PIN, LOW);

  } else { // stop or forward
    digitalWrite(IN1_PIN, LOW);
    analogWrite(IN2_PIN, pwm);
  }
}

/// Set the current on both motors.
///
/// \param pwm_A  motor A PWM, -255 to 255
/// \param pwm_B  motor B PWM, -255 to 255
void set_motor_currents(int pwm_A, int pwm_B)
{
  set_motor_pwm(pwm_A, MOT_A1_PIN, MOT_A2_PIN);
  set_motor_pwm(pwm_B, MOT_B1_PIN, MOT_B2_PIN);

  // Print a status message to the console.
  Serial.print("Set motor A PWM = ");
  Serial.print(pwm_A);
  Serial.print(" motor B PWM = ");
  Serial.println(pwm_B);
}

/// Simple primitive for the motion sequence to set a speed and wait for an interval.
///
/// \param pwm_A  motor A PWM, -255 to 255
/// \param pwm_B  motor B PWM, -255 to 255
/// \param duration delay in milliseconds
void spin_and_wait(int pwm_A, int pwm_B, int duration)
{
  set_motor_currents(pwm_A, pwm_B);
  delay(duration);
}

代码说明:

Arduino 代码相当简单。它不需要任何库即可工作。该草图首先声明连接到 DRV8833 控制引脚的 Arduino 引脚。

// Define the control inputs
#define MOT_A1_PIN 10
#define MOT_A2_PIN 9
#define MOT_B1_PIN 6
#define MOT_B2_PIN 5

代码的设置部分初始化硬件。它将所有电机控制引脚配置为数字输出并将它们设置为低电平,以最初禁用两个电机。然后,以9600的波特率初始化串行通信。

void setup(void)
{
  // Set all the motor control inputs to OUTPUT
  pinMode(MOT_A1_PIN, OUTPUT);
  pinMode(MOT_A2_PIN, OUTPUT);
  pinMode(MOT_B1_PIN, OUTPUT);
  pinMode(MOT_B2_PIN, OUTPUT);

  // Turn off motors - Initial state
  digitalWrite(MOT_A1_PIN, LOW);
  digitalWrite(MOT_A2_PIN, LOW);
  digitalWrite(MOT_B1_PIN, LOW);
  digitalWrite(MOT_B2_PIN, LOW);

  // Initialize the serial UART at 9600 baud
  Serial.begin(9600);
}

代码的循环部分生成固定运动序列来演示电机模式。

它首先逐渐增加电机的速度,然后达到全速,再次减速并反转方向至全速,最后停止。

// Ramp speed up.
for (int i = 0; i < 11; i++) {
  spin_and_wait(25*i, 25*i, 500);
}
// Full speed forward.
spin_and_wait(255,255,2000);

// Ramp speed into full reverse.
for (int i = 0; i < 21 ; i++) {
  spin_and_wait(255 - 25*i, 255 - 25*i, 500);
}

// Full speed reverse.
spin_and_wait(-255,-255,2000);

// Stop.
spin_and_wait(0,0,2000);

停止后,它演示了两轮机器人底座的转弯操作,其中一个轮子向前移动,另一个轮子向后移动,从而使机器人转弯。演示完所有这些动作后,循环会重复。

// Full speed, forward, turn, reverse, and turn for a two-wheeled base.
spin_and_wait(255, 255, 2000);
spin_and_wait(0, 0, 1000);
spin_and_wait(-255, 255, 2000);
spin_and_wait(0, 0, 1000);
spin_and_wait(-255, -255, 2000);
spin_and_wait(0, 0, 1000);
spin_and_wait(255, -255, 2000);
spin_and_wait(0, 0, 1000);

此草图中使用了三个用户定义的函数:set_motor_pwm()set_motor_currents()spin_and_wait()

set_motor_pwm()功能使用 PWM 和方向逻辑设置电机通道上的电流。如果该pwm值为负,则电机朝一个方向旋转。如果该pwm值为 0 或正数,则电机停止或沿另一个方向旋转。

void set_motor_pwm(int pwm, int IN1_PIN, int IN2_PIN)
{
  if (pwm < 0) {  // reverse speeds
    analogWrite(IN1_PIN, -pwm);
    digitalWrite(IN2_PIN, LOW);

  } else { // stop or forward
    digitalWrite(IN1_PIN, LOW);
    analogWrite(IN2_PIN, pwm);
  }
}

set_motor_currents()函数使用前一个函数来设置两个电机上的电流。它将每个电机的当前 PWM 值打印到串行监视器。

void set_motor_currents(int pwm_A, int pwm_B)
{
  set_motor_pwm(pwm_A, MOT_A1_PIN, MOT_A2_PIN);
  set_motor_pwm(pwm_B, MOT_B1_PIN, MOT_B2_PIN);

  // Print a status message to the console.
  Serial.print("Set motor A PWM = ");
  Serial.print(pwm_A);
  Serial.print(" motor B PWM = ");
  Serial.println(pwm_B);
}

spin_and_wait()函数设置速度并等待指定的时间,然后再转到下一个命令。它使用该set_motor_currents()函数设置两个电机的 PWM 值,然后等待以duration毫秒为单位的指定值。

void spin_and_wait(int pwm_A, int pwm_B, int duration)
{
  set_motor_currents(pwm_A, pwm_B);
  delay(duration);
}

你可能感兴趣的:(单片机,嵌入式硬件)