直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转。作为大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作。而这时候就需要用到TB6612模块。作为一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向。
它的功能类似 L298N,但是:
效率更高(采用 MOSFET,导通电阻低,发热小)
体积更小
电压范围更宽(驱动电压 2.5V13.5V,逻辑电压 2.7V5.5V)
最大电流更大(连续 1.2A,每路可达 3.2A 峰值)
TB6612FNG 引脚功能
引脚 | 功能 | 说明 |
---|---|---|
VCC | 逻辑电源 | 2.7V ~ 5.5V(接 STM32 3.3V/5V) |
VM | 电机电源 | 2.5V ~ 13.5V(接电池/电源给电机供电) |
GND | 地 | 系统地,逻辑和电机地要共地 |
PWMA | 电机A PWM | 控制电机A转速(接 STM32 PWM 输出) |
AIN1 | 电机A方向控制1 | 和 AIN2 组合确定方向 |
AIN2 | 电机A方向控制2 | 和 AIN1 组合确定方向 |
AO1、AO2 | 电机A输出 | 接电机A 两端 |
PWMB | 电机B PWM | 控制电机B转速 |
BIN1、BIN2 | 电机B方向控制 | 同 A 通道 |
BO1、BO2 | 电机B输出 | 接电机B 两端 |
STBY | 芯片使能 | 高电平芯片工作,低电平待机(必须接高电平或 MCU 控制) |
1.控制原理
方向由 IN1、IN2 决定,转速由 PWM 控制。
方向控制真值表
IN1 | IN2 | 电机状态 |
---|---|---|
0 | 0 | 停止(制动模式,电机两端短接) |
1 | 0 | 正转 |
0 | 1 | 反转 |
1 | 1 | 停止(制动模式) |
PWM 调速
PWMA/PWMB 接 MCU 的 PWM 输出。
占空比 0% → 电机停止
占空比 50% → 半速
占空比 100% → 全速
2.STM32 控制代码
main.c
cpp
#include "stm32f10x.h" // STM32 标准外设库头文件,包含寄存器定义
#include "Delay.h" // 延时函数
#include "OLED.h" // OLED 显示驱动
#include "Motor.h" // 电机控制模块
#include "Key.h" // 按键输入模块
uint8_t KeyNum; // 存储按键值(0 表示没按,1 表示按下 Key1)
int8_t Speed; // 电机速度变量,范围 -100~100,正负决定方向
int main(void)
{
OLED_Init(); // 初始化 OLED,配置 I2C/SPI
Motor_Init(); // 初始化电机控制相关 IO(PA4/PA5 + PWM 输出 PA2)
Key_Init(); // 初始化按键 GPIO
OLED_ShowString(1, 1, "Speed:"); // OLED 第一行显示文字"Speed:"
while (1)
{
KeyNum = Key_GetNum(); // 扫描按键,返回 0 或 1
if (KeyNum == 1) // 如果按下了按键 1
{
Speed += 20; // 每按一次,速度加 20
if (Speed > 100) // 如果超过 100
{
Speed = -100; // 从 -100 重新开始(反转全速)
}
}
Motor_SetSpeed(Speed); // 设置电机速度和方向(核心函数)
OLED_ShowSignedNum(1, 7, Speed, 3); // 在 OLED 第 1 行第 7 列显示带符号速度值
}
}
Motor.c
cpp
#include "stm32f10x.h" // STM32 标准外设库头文件
#include "PWM.h" // PWM 驱动模块
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;// 选择 PA4 和 PA5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO 速度
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 GPIOA4/A5
PWM_Init(); // 初始化 PWM(PA2 → TIM2_CH3)
// TB6612 接线说明:
// PA4 → AIN1
// PA5 → AIN2
// PA2 → PWMA(PWM 占空比)
}
void Motor_SetSpeed(int8_t Speed)
{
if (Speed >= 0) // Speed >= 0 → 电机正转
{
GPIO_SetBits(GPIOA, GPIO_Pin_4); // AIN1 = 1
GPIO_ResetBits(GPIOA, GPIO_Pin_5); // AIN2 = 0
PWM_SetCompare3(Speed); // 设置 PWM 占空比 = Speed
// TB6612 判定:AIN1=1,AIN2=0 → 正转
// PWM 输入:Speed 值越大,占空比越大,转速越快
}
else // Speed < 0 → 电机反转
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // AIN1 = 0
GPIO_SetBits(GPIOA, GPIO_Pin_5); // AIN2 = 1
PWM_SetCompare3(-Speed); // 占空比取 Speed 的绝对值
// TB6612 判定:AIN1=0,AIN2=1 → 反转
// PWM 输入:|Speed| 值越大,占空比越大,转速越快
}
}
PWM.c
cpp
#include "stm32f10x.h" // STM32 标准外设库头文件
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 开启 TIM2 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 开启 GPIOA 时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA2 → TIM2_CH3
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO 输出速度
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 PA2
TIM_InternalClockConfig(TIM2); // 使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR = 99,决定 PWM 精度(0~99)
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; // PSC = 35,定时器时钟 = 72MHz/36 = 2MHz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 不重复
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
// PWM 周期 = (ARR+1) * (PSC+1) / 72MHz = 100*36/72MHz = 20kHz
// → 电机驱动推荐 20kHz,超声波频率,听不到啸叫
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); // 初始化结构体
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能通道输出
TIM_OCInitStructure.TIM_Pulse = 0; // CCR 初始值=0,占空比=0%
TIM_OC3Init(TIM2, &TIM_OCInitStructure); // 配置 TIM2_CH3 → PA2
TIM_Cmd(TIM2, ENABLE); // 启动 TIM2
}
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM2, Compare); // 设置 TIM2->CCR3 = Compare
// 实际占空比 = Compare / (ARR+1) = Compare / 100
// 例如:Compare=50 → 占空比50% → 电机得到一半电压 → 半速
}
Speed → 判断正负 → 控制 AIN1/AIN2 (PA4/PA5) → 控制电机正反转
Speed 的绝对值 → 写进 CCR3 → 生成 PWM → 控制 PWMA (PA2) → 控制转速
key.c
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 1;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
Delay_ms(20);
KeyNum = 2;
}
return KeyNum;
}