前言
在上一篇文章中,我介绍了经典的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的首选方案。希望本文对你的学习和项目开发有所帮助,有问题欢迎在评论区交流讨论!
往期回顾
如果你还没有看过前几篇文章,建议按顺序阅读:
- STM32标准库驱动HC-SR04超声波测距模块(定时器输入捕获,附完整工程代码)
- STM32标准库驱动L298N双H桥电机驱动模块(调速/正反转/多模式实战,附完整工程代码)
- 本文:STM32标准库驱动TB6612FNG双H桥电机驱动模块
三篇文章的组合可以帮你从零搭建一个完整的避障小车系统:HC-SR04感知前方障碍物距离 → STM32做逻辑判断 → TB6612FNG驱动电机执行前进/后退/转弯/刹车动作。