官方文档:
一、驱动原理
1.1. 模块框图
1.1.1. 内部结构框图
VM负责提供驱动电压,逻辑控制电平最终通过H桥控制电机正反转。
1.1.2. 经典应用框图
1.2. 引脚功能
1.2.1. 引脚功能列表
1.2.2. 控制功能列表
TB6612FNG有两路H桥驱动输出{[AO1,AO2], [BO1,BO2]},可以直接用于直流电机驱动。
两路驱动输出分别受两路输入控制{[AIN1,AIN2,PWMA], [BIN1,BIN2,PWMB]},IN1、IN2负责控制正转/反转/制动/停止,PWM负责通过占空比调速。
STBY引脚控制芯片是否进入待机模式。
控制逻辑表如下:
由控制逻辑表可以发现有两种控制方案:
1. PWM引脚使用PWM波进行调速, IN1 IN2 使用IO电平控制正反转
优点:实现简单直观
缺点:IN1 IN2更改转向时,可能因为延时导致两端同时导通形成短时间的短路
2. PWM引脚接VDD, IN1 IN2 使用带死区互补PWM控制转向和速度
优点:死区PWM在切换转向时防止短路
缺点:除了关闭定时器,无法使用高阻抗制动
1.3. 电气特性
1.3.1. 最大电压
1.3.2. 工作电压
VCC是芯片电压,一般3V即可满足,VM是电机驱动电压,建议使用5V的电压源,否则只要电源电压稍不稳定就会导致板上的其他器件使用受影响,或者电机直接起不来。
PWM保证在100kHz以内,一般5~20kHz就足够了
二、驱动代码
下面是使用stm32f103 HAL库开发的驱动代码。采用的是PWM接VDD,IN1 IN2 使用带死区互补PWM控制的策略。
2.1. GPIO配置代码
#define TB6612_BIN2_GPIO_PORT GPIOB
#define TB6612_BIN2_GPIO_MODE GPIO_MODE_AF_PP
#define TB6612_BIN2_GPIO_PIN GPIO_PIN_14
#define TB6612_BIN2_GPIO_PULL GPIO_NOPULL
#define TB6612_BIN2_GPIO_SPEED GPIO_SPEED_FREQ_HIGH
#define TB6612_BIN2_HIGH() HAL_GPIO_WritePin(TB6612_BIN2_GPIO_PORT, TB6612_BIN2_GPIO_PIN, GPIO_PIN_SET)
#define TB6612_BIN2_LOW() HAL_GPIO_WritePin(TB6612_BIN2_GPIO_PORT, TB6612_BIN2_GPIO_PIN, GPIO_PIN_RESET)
#define TB6612_BIN1_GPIO_PORT GPIOA
#define TB6612_BIN1_GPIO_MODE GPIO_MODE_AF_PP
#define TB6612_BIN1_GPIO_PIN GPIO_PIN_9
#define TB6612_BIN1_GPIO_PULL GPIO_NOPULL
#define TB6612_BIN1_GPIO_SPEED GPIO_SPEED_FREQ_HIGH
#define TB6612_BIN1_HIGH() HAL_GPIO_WritePin(TB6612_BIN1_GPIO_PORT, TB6612_BIN1_GPIO_PIN, GPIO_PIN_SET)
#define TB6612_BIN1_LOW() HAL_GPIO_WritePin(TB6612_BIN1_GPIO_PORT, TB6612_BIN1_GPIO_PIN, GPIO_PIN_RESET)
#define TB6612_AIN1_GPIO_PORT GPIOA
#define TB6612_AIN1_GPIO_MODE GPIO_MODE_AF_PP
#define TB6612_AIN1_GPIO_PIN GPIO_PIN_8
#define TB6612_AIN1_GPIO_PULL GPIO_NOPULL
#define TB6612_AIN1_GPIO_SPEED GPIO_SPEED_FREQ_HIGH
#define TB6612_AIN1_HIGH() HAL_GPIO_WritePin(TB6612_AIN1_GPIO_PORT, TB6612_AIN1_GPIO_PIN, GPIO_PIN_SET)
#define TB6612_AIN1_LOW() HAL_GPIO_WritePin(TB6612_AIN1_GPIO_PORT, TB6612_AIN1_GPIO_PIN, GPIO_PIN_RESET)
#define TB6612_AIN2_GPIO_PORT GPIOB
#define TB6612_AIN2_GPIO_MODE GPIO_MODE_AF_PP
#define TB6612_AIN2_GPIO_PIN GPIO_PIN_13
#define TB6612_AIN2_GPIO_PULL GPIO_NOPULL
#define TB6612_AIN2_GPIO_SPEED GPIO_SPEED_FREQ_HIGH
#define TB6612_AIN2_HIGH() HAL_GPIO_WritePin(TB6612_AIN2_GPIO_PORT, TB6612_AIN2_GPIO_PIN, GPIO_PIN_SET)
#define TB6612_AIN2_LOW() HAL_GPIO_WritePin(TB6612_AIN2_GPIO_PORT, TB6612_AIN2_GPIO_PIN, GPIO_PIN_RESET)
void GpioInit(void)
{
GPIO_InitTypeDef tGpioInit;
/* -1- Enable GPIO Clock (to be able to program the configuration registers) */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
tGpioInit.Mode = TB6612_BIN2_GPIO_MODE;
tGpioInit.Pull = TB6612_BIN2_GPIO_PULL;
tGpioInit.Speed = TB6612_BIN2_GPIO_SPEED;
tGpioInit.Pin = TB6612_BIN2_GPIO_PIN;
HAL_GPIO_Init(TB6612_BIN2_GPIO_PORT, &tGpioInit);
tGpioInit.Mode = TB6612_BIN1_GPIO_MODE;
tGpioInit.Pull = TB6612_BIN1_GPIO_PULL;
tGpioInit.Speed = TB6612_BIN1_GPIO_SPEED;
tGpioInit.Pin = TB6612_BIN1_GPIO_PIN;
HAL_GPIO_Init(TB6612_BIN1_GPIO_PORT, &tGpioInit);
tGpioInit.Mode = TB6612_AIN1_GPIO_MODE;
tGpioInit.Pull = TB6612_AIN1_GPIO_PULL;
tGpioInit.Speed = TB6612_AIN1_GPIO_SPEED;
tGpioInit.Pin = TB6612_AIN1_GPIO_PIN;
HAL_GPIO_Init(TB6612_AIN1_GPIO_PORT, &tGpioInit);
tGpioInit.Mode = TB6612_AIN2_GPIO_MODE;
tGpioInit.Pull = TB6612_AIN2_GPIO_PULL;
tGpioInit.Speed = TB6612_AIN2_GPIO_SPEED;
tGpioInit.Pin = TB6612_AIN2_GPIO_PIN;
HAL_GPIO_Init(TB6612_AIN2_GPIO_PORT, &tGpioInit);
return ;
}
2.2. PWM输出配置代码
#define MOTOR_TB6112_A_TIMER TIM1
#define MOTOR_TB6112_A_TIMER_CHANNEL TIM_CHANNEL_1
#define MOTOR_TB6112_A_TIMER_PRESCALER (64-1)
#define MOTOR_TB6112_A_TIMER_PERIOD_VALUE (100-1)
#define MOTOR_TB6112_A_TIMER_COUNT_VALUE ((MOTOR_TB6112_A_TIMER_PERIOD_VALUE + 1) >> 1)
#define MOTOR_TB6112_A_TIMER_DEADTIME (0x02) // DTG[7:5]=0xx => DT = DTG[7:0] * TDS = DTG[7:0] * 1/(CLK/PRESCALER)
#define MOTOR_TB6112_A_TIMER_BREAKFILTER (0x1) // 随便配一个先
#define MOTOR_TB6112_B_TIMER_CHANNEL TIM_CHANNEL_2
#define MOTOR_TB6112_TIMER_ENABLE() __HAL_RCC_TIM1_CLK_ENABLE()
TIM_HandleTypeDef tb6612ATimHandle;
void TB6612_A_Timer_Init(void)
{
MOTOR_TB6112_TIMER_ENABLE();
// Timer3挂在APB1总线下, APB1为2分频时, Timer3_CLK = APB1_CLK * 2 = 64M
// TB6612需要 5k ~ 20kHz PWM, 最大100kHz
// 1.先得到1MHz的计数时钟, 即 Prescaler = 64M / 1MHz -1 = 64 -1
// 2.再得到10kHz的PWM输出, 即 Period = 1MHz / 10kHz - 1 = 10 -1
// 3.默认采用半速, 50 - 1
/* 1.定时器基础配置 */
tb6612ATimHandle.Instance = MOTOR_TB6112_A_TIMER;
tb6612ATimHandle.Init.Prescaler = MOTOR_TB6112_A_TIMER_PRESCALER;
tb6612ATimHandle.Init.Period = MOTOR_TB6112_A_TIMER_PERIOD_VALUE;
tb6612ATimHandle.Init.ClockDivision = 0;
tb6612ATimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
tb6612ATimHandle.Init.RepetitionCounter = 0;
tb6612ATimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&tb6612ATimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler("TB6612A PWM Init Err.");
}
/* 2.PWM配置 */
TIM_OC_InitTypeDef sConfig;
/*
OC1M[2:0]:
110:PWM模式1- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
111:PWM模式2- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
*/
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性
/*
OC1FE: Output compare 1 fast enable
This bit is used to accelerate the effect of an event on the trigger in input on the CC output.
0: CC1 behaves normally depending on the counter and CCR1 values even when the trigger is ON.
The minimum delay to activate the CC1 output when an edge occurs on the trigger input is 5 clock cycles
1: An active edge on the trigger input acts like a compare match on the CC1 output. Then, OC is set to the compare level independently of the result of the comparison.
Delay to sample the trigger input and to activate CC1 output is reduced to 3 clock cycles.
OC1FE acts only if the channel is configured in PWM1 or PWM2 mode.
*/
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 互补输出极性
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 互补输出空闲状态
sConfig.OCIdleState = TIM_OCIDLESTATE_RESET; // 输出空闲状态
sConfig.Pulse = MOTOR_TB6112_A_TIMER_COUNT_VALUE;
if (HAL_TIM_PWM_ConfigChannel(&tb6612ATimHandle, &sConfig, MOTOR_TB6112_A_TIMER_CHANNEL) != HAL_OK)
{
/* Configuration Error */
Error_Handler("TB6612A PWM Con Err.");
}
if (HAL_TIM_PWM_ConfigChannel(&tb6612ATimHandle, &sConfig, MOTOR_TB6112_B_TIMER_CHANNEL) != HAL_OK)
{
/* Configuration Error */
Error_Handler("TB6612A PWM Con Err.");
}
/* 3.死区时间配置 */
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
/*
OSSR:运行模式下“关闭状态”选择 (Off-state selection for Run mode) 位11
该位用于当MOE=1且通道为互补输出时。没有互补输出的定时器中不存在OSSR位。
参考OC/OCN使能的详细说明(13.4.9 249/754 节,TIM1和TIM8捕获/比较使能寄存器(TIMx_CCER))。
0:当定时器不工作时,禁止OC/OCN输出(OC/OCN使能输出信号=0);
1:当定时器不工作时,一旦CCxE=1或CCxNE=1,首先开启OC/OCN并输出无效电平,然后置OC/OCN使能输出信号=1。
注:一旦LOCK级别(TIMx_BDTR寄存器中的LOCK位)设为2,则该位不能被修改。
*/
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
/*
OSSI: 空闲模式下“关闭状态”选择 (Off-state selection for Idle mode) 位10
该位用于当MOE=0且通道设为输出时。
参考OC/OCN使能的详细说明(13.4.9节,TIM1和TIM8捕获/比较使能寄存器(TIMx_CCER))。
0:当定时器不工作时,禁止OC/OCN输出(OC/OCN使能输出信号=0);
1:当定时器不工作时,一旦CCxE=1或CCxNE=1,OC/OCN首先输出其空闲电平,然后
OC/OCN使能输出信号=1。
注:一旦LOCK级别(TIMx_BDTR寄存器中的LOCK位)设为2,则该位不能被修改。
*/
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
/*
00:锁定关闭,寄存器无写保护;
01:锁定级别1,不能写入TIMx_BDTR寄存器的DTG、BKE、BKP、AOE位和TIMx_CR2寄存器的OISx/OISxN位;
10:锁定级别2,不能写入锁定级别1中的各位,也不能写入CC极性位(一旦相关通道通过CCxS位设为输出,CC极性位是TIMx_CCER寄存器的CCxP/CCNxP位)以及OSSR/OSSI位;
11:锁定级别3,不能写入锁定级别2中的各位,也不能写入CC控制位(一旦相关通道通过CCxS位设为输出,CC控制位是TIMx_CCMRx寄存器的OCxM/OCxPE位);
注:在系统复位后,只能写一次LOCK位,一旦写入TIMx_BDTR寄存器,则其内容冻结直至复位。
*/
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = MOTOR_TB6112_A_TIMER_DEADTIME; // 死区时间配置, 死区时间时基取决于定时器工作频率, 系数取决于死区时间DTG[0:7]的配置
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; // 刹车功能使能, 用于及时中断PWM输出(暂不使用)
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; // 刹车引脚极性
sBreakDeadTimeConfig.BreakFilter = MOTOR_TB6112_A_TIMER_BREAKFILTER; // 滤波器选择0x0~0xF
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; // 刹车后自动输出恢复使能, 使能后, 下次事件自动恢复输出, 否则只能由软件恢复MOE位
if (HAL_TIMEx_ConfigBreakDeadTime(&tb6612ATimHandle, &sBreakDeadTimeConfig) != HAL_OK)
{
/* Configuration Error */
Error_Handler("TB6612A PWM Con Err.");
}
/* 4.启用通道 */
if (HAL_TIM_PWM_Start(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL) != HAL_OK)
{
/* PWM Generation Error */
Error_Handler("TB6612A PWM Chan Err.");
}
if (HAL_TIMEx_PWMN_Start(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL) != HAL_OK)
{
/* PWM Generation Error */
Error_Handler("TB6612A PWM ChanN Err.");
}
if (HAL_TIM_PWM_Start(&tb6612ATimHandle, MOTOR_TB6112_B_TIMER_CHANNEL) != HAL_OK)
{
/* PWM Generation Error */
Error_Handler("TB6612B PWM Chan Err.");
}
if (HAL_TIMEx_PWMN_Start(&tb6612ATimHandle, MOTOR_TB6112_B_TIMER_CHANNEL) != HAL_OK)
{
/* PWM Generation Error */
Error_Handler("TB6612B PWM ChanN Err.");
}
}
2.3. TB6612驱动代码
/* ***************** 常量 ***************** */
#define TB6612_BRAKE_VALUE ((MOTOR_TB6112_A_TIMER_PERIOD_VALUE+1) >> 1)
#define TB6612_CWHALF_VALUE (((MOTOR_TB6112_A_TIMER_PERIOD_VALUE+1) >> 1) + ((MOTOR_TB6112_A_TIMER_PERIOD_VALUE+1) >> 2))
#define TB6612_CWFULL_VALUE (MOTOR_TB6112_A_TIMER_PERIOD_VALUE)
#define TB6612_CCWHALF_VALUE (((MOTOR_TB6112_A_TIMER_PERIOD_VALUE+1) >> 1) - ((MOTOR_TB6112_A_TIMER_PERIOD_VALUE+1) >> 2))
#define TB6612_CCWFULL_VALUE (0)
#include "tb6612M.h"
/* 本模块内部使用接口声明 */
/* 本模块对外公布接口声明 */
void TB6612_Init(void);
void TB6612_A_STOP(void);
void TB6612_A_BRAKE(void);
void TB6612_A_CW(void);
void TB6612_A_CWHALF(void);
void TB6612_A_CCW(void);
void TB6612_B_STOP(void);
void TB6612_B_BRAKE(void);
void TB6612_B_CW(void);
void TB6612_B_CCW(void);
void TB6612_A_Toggle(void);
void TB6612_B_Toggle(void);
void TB6612_Init(void)
{
TB6612_A_BRAKE();
TB6612_B_BRAKE();
}
void TB6612_A_STOP(void)
{
Delay_us(1);
}
void TB6612_A_BRAKE(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL, TB6612_BRAKE_VALUE);
}
void TB6612_A_CW(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL, TB6612_CWFULL_VALUE);
}
void TB6612_A_CWHALF(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL, TB6612_CWHALF_VALUE);
}
void TB6612_A_CCW(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_A_TIMER_CHANNEL, TB6612_CCWFULL_VALUE);
}
void TB6612_B_STOP(void)
{
Delay_us(1);
}
void TB6612_B_BRAKE(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_B_TIMER_CHANNEL, TB6612_BRAKE_VALUE);
}
void TB6612_B_CW(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_B_TIMER_CHANNEL, TB6612_CWFULL_VALUE);
}
void TB6612_B_CCW(void)
{
__HAL_TIM_SET_COMPARE(&tb6612ATimHandle, MOTOR_TB6112_B_TIMER_CHANNEL, TB6612_CCWFULL_VALUE);
}
void TB6612_A_Toggle(void)
{
TB6612_A_CW();
Delay_ms(1000);
TB6612_A_CCW();
Delay_ms(1000);
}
void TB6612_B_Toggle(void)
{
TB6612_B_CW();
Delay_ms(1000);
TB6612_B_CCW();
Delay_ms(1000);
}