STM32标准库驱动TB6612FNG双H桥电机驱动模块(PWM调速/正反转/制动/多模式实战,附完整工程代码)

前言

在上一篇文章中,我介绍了经典的L298N电机驱动模块。L298N虽然在入门领域非常普及,但其采用双极型晶体管结构,导通压降较大、发热严重、体积笨重,已逐渐难以满足现代小型化、高效率的应用需求。

TB6612FNG是东芝半导体推出的一款双H桥直流电机驱动IC,采用MOSFET-H桥结构,具有导通电阻低、发热小、体积紧凑等显著优势,被广泛应用于智能小车、机器人、云台等嵌入式项目中。与L298N相比,它的驱动效率更高,且引脚逻辑与L298N高度兼容,迁移成本极低。

本文将详细介绍TB6612FNG的工作原理,并基于STM32F103C8T6最小系统,采用标准外设库 编程,实现电机的正反转、停止、制动、PWM无级调速、差速转向等完整功能,代码可直接整合到你的工程中运行。

一、TB6612FNG模块介绍

1.1 模块外观与组成

典型的TB6612FNG电机驱动模块通常包含以下几个主要部分:

  • TB6612FNG主芯片:东芝半导体出品,采用BiCDMOS工艺,内部集成双H桥及保护电路。
  • 电源输入接口 :VM(电机驱动电源,2.515V)、VCC(逻辑电源,3.35V)、GND。
  • 电机输出接口:AO1/AO2对应电机A,BO1/BO2对应电机B。
  • 控制信号输入接口:AIN1/AIN2/BIN1/BIN2为方向控制信号;PWMA/PWMB为PWM速度控制信号;STBY为待机控制引脚。

特别提醒 :市面上常见的TB6612FNG模块(如DFRobot出品),已经对原始芯片引脚进行了逻辑简化 。它将原本的IN1/IN2方向控制合成为一个DIR引脚,仅需4根控制线即可驱动两个电机(PWM1 + DIR1 + PWM2 + DIR2),极大节约了单片机IO资源。本文同时涵盖两种模块的驱动方案。

1.2 引脚功能速查表

方案一:DFRobot简化版模块(仅4个控制引脚)
引脚 功能说明
VCC 逻辑电源,3.3~5V
VM 电机驱动电源,2.5~12V
GND 逻辑和电机公共地
DIR1 电机M1方向控制(1=正转,0=反转)
PWM1 电机M1速度控制(PWM输入)
DIR2 电机M2方向控制
PWM2 电机M2速度控制
M1+/M1- 电机M1输出
M2+/M2- 电机M2输出
方案二:标准版模块(控制引脚保留原始芯片逻辑)
引脚 功能说明
VCC 逻辑电源,2.7~5.5V
VM 电机驱动电源,2.5~15V
GND 公共地
AIN1/AIN2 电机A方向控制
PWMA 电机A速度控制(PWM输入)
BIN1/BIN2 电机B方向控制
PWMB 电机B速度控制(PWM输入)
STBY 待机控制(高电平=正常工作,低电平=待机)
AO1/AO2 电机A输出
BO1/BO2 电机B输出

本文以方案二(标准版模块)为主要讲解对象,DFRobot简化版模块的驱动代码将在第九章给出。

1.3 核心参数对比:TB6612FNG vs L298N

参数 TB6612FNG L298N
功率器件 MOSFET(低导通电阻) 双极型晶体管
导通电阻 典型0.5Ω 约2~3Ω
持续电流(单通道) 1.2A 2A
峰值电流 3.2A(单脉冲) 3A
逻辑电压VCC 2.7~5.5V 4.5~7V
电机电压VM 2.5~15V 5~35V
PWM最高频率 100kHz 约40kHz
待机功能 有(STBY引脚)
芯片封装 SSOP24(小型贴片) Multiwatt15(大体积)
发热量

总结:TB6612FNG体积更小、发热更低、效率更高,适合空间受限和电池供电场景;L298N的驱动电压范围更宽、持续电流更大,适合驱动大功率电机。

二、H桥工作原理回顾

TB6612FNG与L298N一样,内部也是基于H桥电路结构,此处简要回顾:

复制代码
            +VM (电机电源)
             │
        Q1 ──┴── Q2
             │
             M   (电机)
             │
        Q4 ──┴── Q3
             │
            GND

四种工作模式

模式 导通MOSFET 电流路径 效果
正转 Q1 + Q3 VM → Q1 → 电机 → Q3 → GND 电机正向旋转
反转 Q2 + Q4 VM → Q2 → 电机 → Q4 → GND 电机反向旋转
滑行停止 全部断开 无电流 电机惯性自由滑行
短路制动 Q2 + Q3(下桥臂全开) 电机两端短路到GND 电磁制动,快速停止

由于TB6612FNG采用MOSFET而非三极管,其导通电阻典型值仅0.5Ω(L298N约为23Ω),在1A负载下压降仅0.5V,而L298N可达23V,这意味着TB6612FNG在相同供电电压下能输出更高的有效电压,且发热显著减少。

三、TB6612FNG真值表与控制逻辑

3.1 STBY引脚

TB6612FNG相比L298N多了一个STBY(待机)控制引脚

  • STBY = 高电平(1) :芯片正常工作,可通过IN1/IN2和PWM控制电机。
  • STBY = 低电平(0) :芯片进入待机模式,所有电机停止,内部电路断电以节省功耗。

在程序初始化时必须将STBY置高,否则电机不会响应任何控制信号。

3.2 电机控制真值表(以电机A为例)

AIN1 AIN2 PWMA STBY 电机状态
1 0 1/PWM 1 正转
0 1 1/PWM 1 反转
1 1 × 1 短路制动
0 0 × 1 滑行停止
× × × 0 待机(全部停止)

电机B 的逻辑与A完全相同,对应BIN1 / BIN2 / PWMB

3.3 与L298N的核心差异

控制特性 TB6612FNG L298N
制动方式 下桥臂短路制动(安全) 上下桥臂同时导通制动(危险)
待机功能 有,STBY=0停止全部电机
IN1=1, IN2=1 短路制动(电机短路到GND) 快速制动(电机两端短路)
PWM控制对象 PWMA引脚 ENA引脚
制动安全性 较高,制动电流仅走MOSFET下桥臂 较低,长时间制动可能导致芯片过热烧毁

⚠️ 重要:TB6612FNG的制动机制是下桥臂短路制动(两个下桥臂MOSFET同时导通),与L298N的全桥短路制动不同,制动电流更小、更安全,但仍不建议长时间保持制动状态。

四、硬件接线

以STM32F103C8T6驱动两个直流电机(标准版TB6612FNG模块)为例:

TB6612FNG引脚 STM32引脚 说明
VM 外部电池正极(7~12V) 电机驱动电源
VCC STM32 3.3V或5V 逻辑电源
GND 电池负极 + STM32 GND 必须共地!
STBY PB12 待机控制(高电平使能)
AIN1 PB13 电机A方向控制
AIN2 PB14 电机A方向控制
PWMA PA2(TIM2_CH3) 电机A PWM调速
BIN1 PB15 电机B方向控制
BIN2 PA4 电机B方向控制
PWMB PA3(TIM2_CH4) 电机B PWM调速
AO1、AO2 电机A两端 正负极任意接,互换可改变旋转方向
BO1、BO2 电机B两端 正负极任意接

PWM频率选择

TB6612FNG官方支持PWM频率高达100kHz 。实际使用中推荐10kHz ~ 20kHz

  • 频率太低(<1kHz):电机会发出明显的高频啸叫声。
  • 频率太高(>20kHz):MOSFET开关损耗增加,发热加重。
  • 推荐10kHz:既超出人耳敏感范围(电机静音),又保持较高驱动效率。

本文采用10kHz PWM频率,定时器配置详见代码部分。

五、完整代码(标准库版,可直接使用)

5.1 工程结构

复制代码
├── Core
│   ├── Inc
│   │   └── tb6612.h             # TB6612FNG模块头文件
│   └── Src
│       ├── tb6612.c             # TB6612FNG模块源文件
│       └── main.c               # 主函数

5.2 tb6612.h

c 复制代码
#ifndef __TB6612_H
#define __TB6612_H

#include "stm32f10x.h"

/* ---------- 引脚宏定义(可根据实际接线修改) ---------- */

/* STBY 待机控制引脚 */
#define STBY_GPIO_PORT        GPIOB
#define STBY_GPIO_PIN         GPIO_Pin_12
#define STBY_RCC              RCC_APB2Periph_GPIOB

/* 电机 A(PWMA / AIN1 / AIN2) */
#define MOTOR_A_PWM_GPIO      GPIOA
#define MOTOR_A_PWM_PIN       GPIO_Pin_2
#define MOTOR_A_PWM_RCC       RCC_APB2Periph_GPIOA

#define MOTOR_A_IN1_GPIO      GPIOB
#define MOTOR_A_IN1_PIN       GPIO_Pin_13
#define MOTOR_A_IN1_RCC       RCC_APB2Periph_GPIOB

#define MOTOR_A_IN2_GPIO      GPIOB
#define MOTOR_A_IN2_PIN       GPIO_Pin_14
#define MOTOR_A_IN2_RCC       RCC_APB2Periph_GPIOB

/* 电机 B(PWMB / BIN1 / BIN2) */
#define MOTOR_B_PWM_GPIO      GPIOA
#define MOTOR_B_PWM_PIN       GPIO_Pin_3
#define MOTOR_B_PWM_RCC       RCC_APB2Periph_GPIOA

#define MOTOR_B_IN1_GPIO      GPIOB
#define MOTOR_B_IN1_PIN       GPIO_Pin_15
#define MOTOR_B_IN1_RCC       RCC_APB2Periph_GPIOB

#define MOTOR_B_IN2_GPIO      GPIOA
#define MOTOR_B_IN2_PIN       GPIO_Pin_4
#define MOTOR_B_IN2_RCC       RCC_APB2Periph_GPIOA

/* PWM 定时器定义 */
#define MOTOR_PWM_TIM         TIM2            // PWMA 使用 TIM2_CH3 (PA2),PWMB 使用 TIM2_CH4 (PA3)
#define MOTOR_A_PWM_CHANNEL   3               // TIM2 通道3
#define MOTOR_B_PWM_CHANNEL   4               // TIM2 通道4

#define PWM_PERIOD            899             // ARR值,PSC=7 → PWM频率 = 72MHz/[(7+1)*(899+1)] = 10kHz
                                              // 占空比调节范围:0 ~ 899

/* ---------- 公开接口 ---------- */

void TB6612_Init(void);                        // 初始化所有 GPIO 和定时器 PWM

/* 电机 A 控制 */
void MotorA_SetSpeed(uint16_t speed);           // 设置速度(0 ~ PWM_PERIOD)
void MotorA_Forward(uint16_t speed);            // 正转
void MotorA_Backward(uint16_t speed);           // 反转
void MotorA_Stop(void);                         // 滑行停止
void MotorA_Brake(void);                        // 短路制动

/* 电机 B 控制 */
void MotorB_SetSpeed(uint16_t speed);
void MotorB_Forward(uint16_t speed);
void MotorB_Backward(uint16_t speed);
void MotorB_Stop(void);
void MotorB_Brake(void);

#endif /* __TB6612_H */

5.3 tb6612.c

c 复制代码
#include "tb6612.h"

/**
 * @brief  初始化 TB6612FNG 的所有控制引脚和 PWM 定时器
 * @note   使用 TIM2_CH3 (PA2) 控制 PWMA,TIM2_CH4 (PA3) 控制 PWMB
 *         PWM 频率 = 72MHz / [(7+1) × (899+1)] = 10kHz
 */
void TB6612_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    /* ====== 1. 使能时钟 ====== */
    RCC_APB2PeriphClockCmd(STBY_RCC | MOTOR_A_IN1_RCC | MOTOR_A_IN2_RCC |
                           MOTOR_B_IN1_RCC | MOTOR_B_IN2_RCC |
                           MOTOR_A_PWM_RCC | MOTOR_B_PWM_RCC |
                           RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    /* ====== 2. STBY 引脚配置为推挽输出,初始拉高(使能芯片) ====== */
    GPIO_InitStructure.GPIO_Pin = STBY_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(STBY_GPIO_PORT, &GPIO_InitStructure);
    GPIO_SetBits(STBY_GPIO_PORT, STBY_GPIO_PIN);   // STBY = 1,芯片正常工作

    /* ====== 3. 方向控制引脚(AIN1/AIN2/BIN1/BIN2)配置为推挽输出 ====== */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    /* AIN1、AIN2(电机 A 方向) */
    GPIO_InitStructure.GPIO_Pin = MOTOR_A_IN1_PIN | MOTOR_A_IN2_PIN;
    GPIO_Init(MOTOR_A_IN1_GPIO, &GPIO_InitStructure);

    /* BIN1(电机 B 方向) - PB15 */
    GPIO_InitStructure.GPIO_Pin = MOTOR_B_IN1_PIN;
    GPIO_Init(MOTOR_B_IN1_GPIO, &GPIO_InitStructure);

    /* BIN2(电机 B 方向) - PA4 */
    GPIO_InitStructure.GPIO_Pin = MOTOR_B_IN2_PIN;
    GPIO_Init(MOTOR_B_IN2_GPIO, &GPIO_InitStructure);

    /* 初始状态:全部拉低(停止) */
    GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN | MOTOR_A_IN2_PIN);
    GPIO_ResetBits(MOTOR_B_IN1_GPIO, MOTOR_B_IN1_PIN);
    GPIO_ResetBits(MOTOR_B_IN2_GPIO, MOTOR_B_IN2_PIN);

    /* ====== 4. PWM 输出引脚(PA2、PA3)配置为复用推挽输出 ====== */
    GPIO_InitStructure.GPIO_Pin = MOTOR_A_PWM_PIN | MOTOR_B_PWM_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   // 复用推挽输出
    GPIO_Init(MOTOR_A_PWM_GPIO, &GPIO_InitStructure);

    /* ====== 5. TIM2 配置(双通道 PWM:CH3=PA2, CH4=PA3) ====== */
    TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD;          // ARR = 899
    TIM_TimeBaseStructure.TIM_Prescaler = 7;                // PSC = 7 → 72M/(7+1) = 9MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    /* PWM 模式配置 - 通道 3(PWMA) */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;       // PWM 模式 1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;                      // 初始占空比 0%
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);                // 通道 3

    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);       // 预装载使能

    /* PWM 模式配置 - 通道 4(PWMB) */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC4Init(TIM2, &TIM_OCInitStructure);                // 通道 4

    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);

    TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_Cmd(TIM2, ENABLE);                                  // 启动 TIM2
}

/* ================================================================
 *                         电机 A 控制函数
 * ================================================================ */

/**
 * @brief  设置电机 A 的 PWM 占空比
 * @param  speed: 0 ~ PWM_PERIOD(899),0 = 停止,899 = 全速
 */
void MotorA_SetSpeed(uint16_t speed)
{
    if (speed > PWM_PERIOD)
        speed = PWM_PERIOD;
    TIM_SetCompare3(TIM2, speed);   // 更新 TIM2 通道 3 的比较值
}

/**
 * @brief  电机 A 正转
 * @param  speed: 速度值(0 ~ PWM_PERIOD)
 */
void MotorA_Forward(uint16_t speed)
{
    GPIO_SetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);   // AIN1 = 1
    GPIO_ResetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN); // AIN2 = 0
    MotorA_SetSpeed(speed);
}

/**
 * @brief  电机 A 反转
 * @param  speed: 速度值(0 ~ PWM_PERIOD)
 */
void MotorA_Backward(uint16_t speed)
{
    GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN); // AIN1 = 0
    GPIO_SetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);   // AIN2 = 1
    MotorA_SetSpeed(speed);
}

/**
 * @brief  电机 A 滑行停止(自由停止)
 */
void MotorA_Stop(void)
{
    GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN); // AIN1 = 0
    GPIO_ResetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN); // AIN2 = 0
    MotorA_SetSpeed(0);
}

/**
 * @brief  电机 A 短路制动(快速停止)
 * @warning 不建议长时间保持,会产生制动电流!
 */
void MotorA_Brake(void)
{
    GPIO_SetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);   // AIN1 = 1
    GPIO_SetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);   // AIN2 = 1
    MotorA_SetSpeed(0);                                 // PWM 关闭,下桥臂短路制动
}

/* ================================================================
 *                         电机 B 控制函数
 * ================================================================ */

/**
 * @brief  设置电机 B 的 PWM 占空比
 * @param  speed: 0 ~ PWM_PERIOD(899)
 */
void MotorB_SetSpeed(uint16_t speed)
{
    if (speed > PWM_PERIOD)
        speed = PWM_PERIOD;
    TIM_SetCompare4(TIM2, speed);   // 更新 TIM2 通道 4 的比较值
}

/**
 * @brief  电机 B 正转
 */
void MotorB_Forward(uint16_t speed)
{
    GPIO_SetBits(MOTOR_B_IN1_GPIO, MOTOR_B_IN1_PIN);   // BIN1 = 1
    GPIO_ResetBits(MOTOR_B_IN2_GPIO, MOTOR_B_IN2_PIN); // BIN2 = 0
    MotorB_SetSpeed(speed);
}

/**
 * @brief  电机 B 反转
 */
void MotorB_Backward(uint16_t speed)
{
    GPIO_ResetBits(MOTOR_B_IN1_GPIO, MOTOR_B_IN1_PIN); // BIN1 = 0
    GPIO_SetBits(MOTOR_B_IN2_GPIO, MOTOR_B_IN2_PIN);   // BIN2 = 1
    MotorB_SetSpeed(speed);
}

/**
 * @brief  电机 B 滑行停止
 */
void MotorB_Stop(void)
{
    GPIO_ResetBits(MOTOR_B_IN1_GPIO, MOTOR_B_IN1_PIN); // BIN1 = 0
    GPIO_ResetBits(MOTOR_B_IN2_GPIO, MOTOR_B_IN2_PIN); // BIN2 = 0
    MotorB_SetSpeed(0);
}

/**
 * @brief  电机 B 短路制动
 */
void MotorB_Brake(void)
{
    GPIO_SetBits(MOTOR_B_IN1_GPIO, MOTOR_B_IN1_PIN);   // BIN1 = 1
    GPIO_SetBits(MOTOR_B_IN2_GPIO, MOTOR_B_IN2_PIN);   // BIN2 = 1
    MotorB_SetSpeed(0);
}

5.4 main.c

c 复制代码
#include "stm32f10x.h"
#include "tb6612.h"
#include "delay.h"        // 使用 SysTick 实现的延时函数

int main(void)
{
    /* 系统初始化 */
    SystemInit();           // 配置系统时钟为 72MHz
    delay_init();           // SysTick 延时初始化(自行实现)

    /* TB6612FNG 模块初始化 */
    TB6612_Init();

    /* 初始化后 STBY 已拉高,芯片处于工作状态 */

    while (1)
    {
        /* ====== 演示一:电机 A 正转加速 ====== */
        MotorA_Forward(0);
        for (uint16_t speed = 0; speed <= PWM_PERIOD; speed += 30)
        {
            MotorA_SetSpeed(speed);
            delay_ms(30);   // 每 30ms 加速一档
        }
        delay_ms(1000);     // 保持全速 1 秒

        /* ====== 演示二:电机 A 反转减速 ====== */
        MotorA_Backward(PWM_PERIOD);
        delay_ms(2000);     // 反转全速 2 秒

        /* ====== 演示三:电机 A 短路制动 ====== */
        MotorA_Brake();
        delay_ms(500);      // 制动 0.5 秒(时间不宜过长)
        MotorA_Stop();
        delay_ms(1000);     // 等待停止

        /* ====== 演示四:双电机同步控制(小车前进/后退/转弯) ====== */

        /* 小车前进:两电机同向正转 */
        MotorA_Forward(700);   // 约 78% 占空比
        MotorB_Forward(700);
        delay_ms(2000);

        /* 小车后退:两电机同向反转 */
        MotorA_Backward(700);
        MotorB_Backward(700);
        delay_ms(2000);

        /* 小车左转:左轮慢、右轮快(差速转向) */
        MotorA_Forward(250);   // 左轮 28%
        MotorB_Forward(700);   // 右轮 78%
        delay_ms(1500);

        /* 小车右转:左轮快、右轮慢 */
        MotorA_Forward(700);
        MotorB_Forward(250);
        delay_ms(1500);

        /* 小车原地旋转:一侧正转、一侧反转 */
        MotorA_Forward(450);
        MotorB_Backward(450);
        delay_ms(1000);

        /* 小车停止 */
        MotorA_Stop();
        MotorB_Stop();
        delay_ms(2000);

        /* ====== 演示五:STBY 待机功能 ====== */
        /* 拉低 STBY,所有电机立即停止并进入低功耗模式 */
        GPIO_ResetBits(STBY_GPIO_PORT, STBY_GPIO_PIN);
        delay_ms(3000);     // 待机 3 秒

        /* 恢复 STBY,芯片重新进入工作状态 */
        GPIO_SetBits(STBY_GPIO_PORT, STBY_GPIO_PIN);
        delay_ms(500);      // 等待芯片唤醒
    }
}

5.5 stm32f10x_it.c 中断服务函数

由于本代码直接使用硬件PWM,所有控制都由定时器硬件完成,不需要在中断服务函数中添加额外代码,保持默认即可。

六、代码详解

6.1 定时器 PWM 参数计算

以 72MHz 主频为例:

复制代码
PWM 频率 = 72MHz / [(PSC + 1) × (ARR + 1)]
        = 72MHz / [8 × 900]
        = 10kHz
  • 预分频器 PSC = 7 ,则定时器计数频率 = 72MHz / (7 + 1) = 9MHz
  • 自动重装载 ARR = 899 ,则 PWM 周期 = 900 个计数周期,频率 = 9MHz / 900 = 10kHz

相比L298N常用的1kHz,10kHz的PWM频率可以使电机运转完全静音,超出人耳听觉范围(20Hz~20kHz),同时保持在TB6612FNG的高效工作区间内。

6.2 占空比的控制

c 复制代码
TIM_SetCompare3(TIM2, speed);   // speed 范围 0 ~ PWM_PERIOD(899)
  • speed = 899 → 占空比 ≈ 100%(全速)。
  • speed = 700 → 占空比 ≈ 78%(中高速)。
  • speed = 250 → 占空比 ≈ 28%(低速)。
  • speed = 0 → 占空比 = 0%(停止)。

6.3 正反转实现

以电机A为例:

  • 正转:AIN1 = 1,AIN2 = 0,PWMA 提供PWM。
  • 反转:AIN1 = 0,AIN2 = 1,PWMA 提供PWM。

封装后的MotorA_Forward(speed)MotorA_Backward(speed)直接调用即可,无需手动操作GPIO。

6.4 制动与停止

方法 AIN1 AIN2 效果 适用场景
Stop() 0 0 H桥全关,电机自由滑行 正常停车,缓慢减速
Brake() 1 1 下桥臂MOSFET导通,短路制动 紧急停车,快速响应

⚠️ TB6612FNG的制动是下桥臂短路制动(内部将电机两端都拉到GND),比L298N的全桥制动更安全,但仍会产生制动电流和热量,不建议长时间保持制动状态

6.5 STBY待机控制

TB6612FNG的STBY引脚是其相比L298N的一大亮点:

c 复制代码
/* 进入待机模式 */
GPIO_ResetBits(STBY_GPIO_PORT, STBY_GPIO_PIN);

/* 退出待机模式,恢复正常工作 */
GPIO_SetBits(STBY_GPIO_PORT, STBY_GPIO_PIN);
delay_ms(500);   // 等待芯片唤醒

在待机模式下,芯片内部大部分电路断电,功耗极低,适用于电池供电场景中的节能控制。

6.6 差速转向

两轮小车转弯的核心原理是左右轮速度不同

c 复制代码
/* 小车左转:左轮 28%、右轮 78% */
MotorA_Forward(250);
MotorB_Forward(700);

/* 小车原地旋转:左轮正转、右轮反转 */
MotorA_Forward(450);
MotorB_Backward(450);

由于TB6612FNG的MOSFET导通电阻低、效率高,差速转向的响应更加灵敏、平顺。

七、与HC-SR04超声波模块联动:避障小车示例

将TB6612FNG与前面的HC-SR04超声波模块配合,可实现一个简单的避障小车

c 复制代码
/* 伪代码:超声波避障逻辑(需配合HC-SR04驱动代码) */
while (1)
{
    /* 触发超声波测距 */
    HC_SR04_Trigger();
    HAL_Delay(100);  // 等待测距完成
    float distance = HC_SR04_GetDistance();

    if (distance > 30.0f && distance < 400.0f)
    {
        /* 前方无障碍,全速前进 */
        MotorA_Forward(800);
        MotorB_Forward(800);
    }
    else if (distance > 0 && distance <= 30.0f)
    {
        /* 前方有障碍:刹车 → 后退 → 转向避障 */
        MotorA_Brake();
        MotorB_Brake();
        delay_ms(200);

        MotorA_Backward(600);
        MotorB_Backward(600);
        delay_ms(500);

        /* 右转避障:原地旋转 */
        MotorA_Forward(500);
        MotorB_Backward(500);
        delay_ms(600);
    }
    else
    {
        /* 超出范围或其他异常,缓慢前进 */
        MotorA_Forward(400);
        MotorB_Forward(400);
    }
    delay_ms(50);
}

八、DFRobot简化版模块适配代码

如果你使用的是DFRobot出品的TB6612FNG简化版模块(DIR1/PWM1/DIR2/PWM2),逻辑更加简单。以下是适配代码(PWM频率同样为10kHz,使用PSC=7, ARR=899):

8.1 tb6612_simple.h(简化版头文件)

c 复制代码
#ifndef __TB6612_SIMPLE_H
#define __TB6612_SIMPLE_H

#include "stm32f10x.h"

/* 简化版模块引脚定义 */
#define DIR1_GPIO_PORT        GPIOB
#define DIR1_GPIO_PIN         GPIO_Pin_13
#define DIR1_RCC              RCC_APB2Periph_GPIOB

#define DIR2_GPIO_PORT        GPIOB
#define DIR2_GPIO_PIN         GPIO_Pin_15
#define DIR2_RCC              RCC_APB2Periph_GPIOB

#define PWM_PERIOD            899   // PSC=7, ARR=899 → 10kHz

void TB6612_Simple_Init(void);
void Motor1_Run(int16_t speed);   // speed > 0 正转, speed < 0 反转, speed = 0 停止
void Motor2_Run(int16_t speed);

#endif

8.2 tb6612_simple.c(简化版源文件)

c 复制代码
#include "tb6612_simple.h"

void TB6612_Simple_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB2PeriphClockCmd(DIR1_RCC | DIR2_RCC | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = DIR1_GPIO_PIN;
    GPIO_Init(DIR1_GPIO_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = DIR2_GPIO_PIN;
    GPIO_Init(DIR2_GPIO_PORT, &GPIO_InitStructure);
    GPIO_ResetBits(DIR1_GPIO_PORT, DIR1_GPIO_PIN);
    GPIO_ResetBits(DIR2_GPIO_PORT, DIR2_GPIO_PIN);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD;
    TIM_TimeBaseStructure.TIM_Prescaler = 7;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC4Init(TIM2, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
}

void Motor1_Run(int16_t speed)
{
    if (speed > 0) {
        GPIO_SetBits(DIR1_GPIO_PORT, DIR1_GPIO_PIN);
        if ((uint16_t)speed > PWM_PERIOD) speed = PWM_PERIOD;
        TIM_SetCompare3(TIM2, (uint16_t)speed);
    } else if (speed < 0) {
        GPIO_ResetBits(DIR1_GPIO_PORT, DIR1_GPIO_PIN);
        speed = -speed;
        if ((uint16_t)speed > PWM_PERIOD) speed = PWM_PERIOD;
        TIM_SetCompare3(TIM2, (uint16_t)speed);
    } else {
        GPIO_ResetBits(DIR1_GPIO_PORT, DIR1_GPIO_PIN);
        TIM_SetCompare3(TIM2, 0);
    }
}

void Motor2_Run(int16_t speed)
{
    if (speed > 0) {
        GPIO_SetBits(DIR2_GPIO_PORT, DIR2_GPIO_PIN);
        if ((uint16_t)speed > PWM_PERIOD) speed = PWM_PERIOD;
        TIM_SetCompare4(TIM2, (uint16_t)speed);
    } else if (speed < 0) {
        GPIO_ResetBits(DIR2_GPIO_PORT, DIR2_GPIO_PIN);
        speed = -speed;
        if ((uint16_t)speed > PWM_PERIOD) speed = PWM_PERIOD;
        TIM_SetCompare4(TIM2, (uint16_t)speed);
    } else {
        GPIO_ResetBits(DIR2_GPIO_PORT, DIR2_GPIO_PIN);
        TIM_SetCompare4(TIM2, 0);
    }
}

8.3 简化版主函数示例

c 复制代码
int main(void)
{
    SystemInit();
    delay_init();
    TB6612_Simple_Init();

    while (1)
    {
        Motor1_Run(450);   // 电机1正转,约50%占空比
        delay_ms(2000);
        Motor1_Run(-450);  // 反转
        delay_ms(2000);
        Motor1_Run(0);     // 停止
        delay_ms(1000);
    }
}

九、常见问题排查

现象 可能原因 解决方案
电机完全不转 ① STBY未拉高;② 未共地;③ 供电不足 检查STBY是否为高电平;确认GND与单片机相通;确认VM≥2.5V
电机只能正转不能反转 IN1/IN2方向控制引脚接线错误 对照真值表重新检查引脚连接
调速无效,电机始终全速 PWMA/PWMB未接PWM引脚或未配置定时器 检查PA2、PA3的复用功能配置
电机低速抖动严重 PWM频率太低 确认PSC=7, ARR=899,确保频率为10kHz
电机发出高频啸叫声 PWM频率在人耳范围内(<20kHz) 将PWM频率提高到10kHz以上
芯片工作一段时间后停止 过热保护触发 检查负载电流是否超过1.2A;加装散热措施
STBY拉低后电机仍转 STBY引脚未正确连接或初始化错误 检查PB12引脚配置和连接

十、总结

本文详细介绍了TB6612FNG双H桥电机驱动模块的工作原理和STM32标准库驱动方法,涵盖了MOSFET-H桥原理、引脚功能、真值表、STBY待机控制、PWM调速、正反转控制、差速转向等核心内容,并与L298N进行了全面的对比分析。代码结构清晰、函数封装完善,可直接移植到你的项目中使用。

核心要点回顾:

  • TB6612FNG的核心优势:MOSFET输出级、低导通电阻(0.5Ω)、高PWM频率支持(100kHz)、内置STBY待机功能、SSOP24小型封装。
  • 控制四要素
    • IN1/IN2 → 控制方向(IN1=1,IN2=0正转;IN1=0,IN2=1反转;IN1=IN2=1制动)
    • PWMA → 接收PWM控制速度
    • STBY → 高电平使能,低电平待机
    • GND → 必须与单片机共地
  • PWM参数 :PSC=7, ARR=899 → 10kHz 频率,占空比通过TIM_SetCompare3()/TIM_SetCompare4()调整。
  • 与L298N的制动差异:TB6612FNG的制动是下桥臂短路制动,比L298N的全桥制动更安全。
  • 与HC-SR04联动:可轻松构建避障小车等经典嵌入式项目。

TB6612FNG凭借其高效率、小体积、低功耗、PWM高频支持等特性,已经成为智能小车和机器人项目中替代L298N的首选方案。希望本文对你的学习和项目开发有所帮助,有问题欢迎在评论区交流讨论!

往期回顾

如果你还没有看过前几篇文章,建议按顺序阅读:

  1. STM32标准库驱动HC-SR04超声波测距模块(定时器输入捕获,附完整工程代码)
  2. STM32标准库驱动L298N双H桥电机驱动模块(调速/正反转/多模式实战,附完整工程代码)
  3. 本文:STM32标准库驱动TB6612FNG双H桥电机驱动模块

三篇文章的组合可以帮你从零搭建一个完整的避障小车系统:HC-SR04感知前方障碍物距离 → STM32做逻辑判断 → TB6612FNG驱动电机执行前进/后退/转弯/刹车动作。

相关推荐
Tech_D3 小时前
AVA系列音圈电机技术拆解:直驱无间隙+高响应,适配精密自动化场景
单片机·自动化·制造
小+不通文墨3 小时前
树莓派接温湿度传感器显示温度湿度
经验分享·笔记·单片机·嵌入式硬件·学习
我要成为嵌入式大佬3 小时前
正点原子MP157问题详解--烧录出错在ssb1(ox6)
单片机·嵌入式硬件
嵌入式Q3 小时前
FreeRTOS源码解析(10)软件定时器
单片机·mcu·freertos
都在酒里3 小时前
STM32 ADC采样详解(标准库版):普通模式与DMA模式,附完整可用代码
stm32·单片机·嵌入式硬件
XTIOT6663 小时前
工业数据采集设备选型 —— 实体键盘 PDA 的技术优势与场景适配(基于 XT8001D 实践)摘要
大数据·嵌入式硬件·物联网·计算机外设
你疯了抱抱我3 小时前
【自用】Kicad 导入嘉立创元器件封装(NLBN插件)
嵌入式硬件·嵌入式·pcb·电路·电子
a83331964 小时前
C语言嵌入汇编详解
汇编·单片机·语言
三佛科技-134163842124 小时前
LED化妆镜方案开发, LED化妆镜MCU主控芯片如何选择?(FT60F011、FT60F021、FT61FC4F、FT62FC33、FT32F103)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺