这个文章是手把手教你使用STM32F103C8T6单片机来配置TB6612FNG电机驱动的驱动程序,也是我自己刚搞清楚,分享出来也是一种总结记录。
我们先从硬件上简单认识一下TB6612FNG电机驱动。
<>硬件介绍
图片不是重点,就直接从CSDN上其他的博客里搬运过来了。
可以很明确的看到左右各八个引脚,总计十六个引脚,可能数量有些多,现在来把他们分类一下。
左上角的PWMA、AIN1、AIN2为第一组,PWMA为A驱动的速度控制引脚,需要输出PWM波
。AIN1和AIN2是控制此路驱动的正反装方向的,两个都为低电平则停止,AIN1为高电平AIN2为低电平则正转,反之则反转。所以这里是需要
两个高低电平的GPIO输出。
左下角的PWMB、BIN1、BIN2为第二组,和第一组同理。
STBY和GND为第三组
STBY引脚可以理解为此驱动器的总开关,高电平的情况下驱动器才可以正常工作,当STBY为低电平的时候,整个驱动器停止工作。
左下角的GND连接单片机的GNG,由此可以看出,TB6612电机驱动的左边八个引脚全部为连接单片机的信号端。
右边就比较好分了,VM和VCC都接电源正极,两个GND连接电源负极。
A01接A电机的正极,A02连接A电机的负极。
B01连接B电机的正极,B02连接B电机负极。
<>软件程序部分
从硬件部分可知,我们现在需要两路PWM波和五路的GPIO输出高低电平通道。
PWM波又需要配置STM32定时器。
以下为部分核心代码
这是一个配置了四路定时器的文件,但是目前注释掉了两路,只留了两路。
#include "bsp_GeneralTim_3.h" static void GENERAL_TIM_GPIO_Config(void) {
GPIO_InitTypeDef GPIO_InitStructure; // 输出比较通道1 GPIO 初始化 RCC_APB2PeriphClockCmd(
GENERAL_TIM_CH1_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin =
GENERAL_TIM_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GENERAL_TIM_CH1_PORT
, &GPIO_InitStructure); // 输出比较通道2 GPIO 初始化 RCC_APB2PeriphClockCmd(
GENERAL_TIM_CH2_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin =
GENERAL_TIM_CH2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GENERAL_TIM_CH2_PORT
, &GPIO_InitStructure); // // 输出比较通道3 GPIO 初始化 //
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_GPIO_CLK, ENABLE); //
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //
GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure); // // // 输出比较通道4 GPIO 初始化
// RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_GPIO_CLK, ENABLE); //
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH4_PIN; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //
GPIO_Init(GENERAL_TIM_CH4_PORT, &GPIO_InitStructure); } ///* // *
注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有 // *
TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可, // *
另外三个成员是通用定时器和高级定时器才有. //
*-----------------------------------------------------------------------------
// *typedef struct // *{ TIM_Prescaler 都有 // * TIM_CounterMode
TIMx,x[6,7]没有,其他都有 // * TIM_Period 都有 // * TIM_ClockDivision TIMx,x[6,7]没有,其他都有
// * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有 // *}TIM_TimeBaseInitTypeDef;
//
*-----------------------------------------------------------------------------
// */ /* ---------------- PWM信号 周期和占空比的计算--------------- */ // ARR :自动重装载寄存器的值
// CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1) // PWM 信号的周期 T = ARR *
(1/CLK_cnt) = ARR*(PSC+1) / 72M // 占空比P=CCR/(ARR+1) static void
GENERAL_TIM_Mode_Config() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //
开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
/*--------------------时基结构体初始化-------------------------*/ // 配置周期,这里配置为100K //
自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=
GENERAL_TIM_Period; // 驱动CNT计数器的时钟 = Fck_int/(psc+1) TIM_TimeBaseStructure.
TIM_Prescaler= GENERAL_TIM_Prescaler; // 时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(
GENERAL_TIM, &TIM_TimeBaseStructure); } void GENERAL_ccr1_Mode_Config(int a) {
TIM_OCInitTypeDef TIM_OCInitStructure; // 占空比配置 uint16_t CCR1_Val = a; //
配置为PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出比较通道 1
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; TIM_OC1Init(GENERAL_TIM, &
TIM_OCInitStructure); TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); } void GENERAL_ccr2_Mode_Config(int a) {
TIM_OCInitTypeDef TIM_OCInitStructure; // 占空比配置 uint16_t CCR1_Val = a; //
配置为PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出比较通道 2
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; TIM_OC2Init(GENERAL_TIM, &
TIM_OCInitStructure); TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 使能计数器 TIM_Cmd(GENERAL_TIM, ENABLE); } // void GENERAL_ccr3_Mode_Config(int a)
//{ // TIM_OCInitTypeDef TIM_OCInitStructure; // // 占空比配置 // uint16_t CCR1_Val
= a; // // 配置为PWM模式1 // TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // //
输出使能 // TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // //
输出通道电平极性配置 // TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // //
// 输出比较通道 3 // TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //
TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure); //
TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // // 使能计数器 //
TIM_Cmd(GENERAL_TIM, ENABLE); //} // void GENERAL_ccr4_Mode_Config(int a) //{
// TIM_OCInitTypeDef TIM_OCInitStructure; // // 占空比配置 // uint16_t CCR1_Val = a;
// // 配置为PWM模式1 // TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // // 输出使能
// TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // //
输出通道电平极性配置 // TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // //
// 输出比较通道 4 // TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //
TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure); //
TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable); // // 使能计数器 //
TIM_Cmd(GENERAL_TIM, ENABLE); //} void GENERAL_TIM_3_Init() {
GENERAL_TIM_GPIO_Config(); GENERAL_TIM_Mode_Config(); }
/*********************************************END OF FILE**********************/
#ifndef __BSP_GENERALTIME_H #define __BSP_GENERALTIME_H #include"stm32f10x.h"
/************通用定时器TIM参数定义,只限TIM2、3、4、5************/ //
当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意 // 我们这里默认使用TIM3 #define GENERAL_TIM TIM3
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #defineGENERAL_TIM_CLK
RCC_APB1Periph_TIM3 #define GENERAL_TIM_Period99 #define GENERAL_TIM_Prescaler
71 // TIM3 输出比较通道1 #define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define
GENERAL_TIM_CH1_PORT GPIOA #define GENERAL_TIM_CH1_PIN GPIO_Pin_6 // TIM3
输出比较通道2 #define GENERAL_TIM_CH2_GPIO_CLK RCC_APB2Periph_GPIOA #define
GENERAL_TIM_CH2_PORT GPIOA #define GENERAL_TIM_CH2_PIN GPIO_Pin_7 TIM3 输出比较通道3
//#define GENERAL_TIM_CH3_GPIO_CLK RCC_APB2Periph_GPIOB //#define
GENERAL_TIM_CH3_PORT GPIOB //#define GENERAL_TIM_CH3_PIN GPIO_Pin_0 TIM3
输出比较通道4 //#define GENERAL_TIM_CH4_GPIO_CLK RCC_APB2Periph_GPIOB //#define
GENERAL_TIM_CH4_PORT GPIOB //#define GENERAL_TIM_CH4_PIN GPIO_Pin_1
/**************************函数声明********************************/ void
GENERAL_TIM_3_Init(void); void GENERAL_ccr1_Mode_Config(int a); void
GENERAL_ccr2_Mode_Config(int a); //void GENERAL_ccr3_Mode_Config(int a); //void
GENERAL_ccr4_Mode_Config(int a); #endif /* __BSP_GENERALTIME_H */
这是配置GPIO推挽输出高低电平的部分程序。
#include "TB6612.h" #include "bsp_GeneralTim_3.h" #include "stm32f10x.h" void
AIN1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(AIN1_GPIO_CLK,ENABLE); GPIO_InitStruct.GPIO_Pin =
AIN1_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(AIN1_GPIO_PORT,&
GPIO_InitStruct); } void AIN2_GPIO_Config(void) { GPIO_InitTypeDef
GPIO_InitStruct; RCC_APB2PeriphClockCmd(AIN2_GPIO_CLK,ENABLE); GPIO_InitStruct.
GPIO_Pin= AIN2_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(AIN2_GPIO_PORT,&
GPIO_InitStruct); } void BIN1_GPIO_Config(void) { GPIO_InitTypeDef
GPIO_InitStruct; RCC_APB2PeriphClockCmd(BIN1_GPIO_CLK,ENABLE); GPIO_InitStruct.
GPIO_Pin= BIN1_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BIN1_GPIO_PORT,&
GPIO_InitStruct); } void BIN2_GPIO_Config(void) { GPIO_InitTypeDef
GPIO_InitStruct; RCC_APB2PeriphClockCmd(BIN2_GPIO_CLK,ENABLE); GPIO_InitStruct.
GPIO_Pin= BIN2_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BIN2_GPIO_PORT,&
GPIO_InitStruct); } void PWMA_STOP(void)//00为停止 { AIN1_OFF; AIN2_OFF;
GENERAL_ccr1_Mode_Config(0); GENERAL_ccr2_Mode_Config(0); } void PWMA_Forward(
int a)//01为正转 { AIN1_OFF; AIN2_ON; GENERAL_ccr1_Mode_Config(a);
GENERAL_ccr2_Mode_Config(a); } void PWMA_Reverse(int a)//10为反转 { AIN1_ON;
AIN2_OFF; GENERAL_ccr1_Mode_Config(a); GENERAL_ccr2_Mode_Config(a); } void
PWMB_STOP(void)//00为停止 { BIN1_OFF; BIN2_OFF; GENERAL_ccr1_Mode_Config(0);
GENERAL_ccr2_Mode_Config(0); } void PWMB_Forward(int a)//01为正转 { BIN1_OFF;
BIN2_ON; GENERAL_ccr1_Mode_Config(a); GENERAL_ccr2_Mode_Config(a); } void
PWMB_Reverse(int a)//10为反转 { BIN1_ON; BIN2_OFF; GENERAL_ccr1_Mode_Config(a);
GENERAL_ccr2_Mode_Config(a); } void STOP(void) { PWMA_STOP(); PWMB_STOP(); }
void Forward(int a) { PWMA_Forward(a); PWMB_Forward(a); } void Reverse(int a) {
PWMA_Reverse(a); PWMB_Reverse(a); } #ifndef TB6612_H #define TB6612_H #include
"stm32f10x.h" /*B0端口*/ #define AIN1_GPIO_PIN GPIO_Pin_0 #define AIN1_GPIO_PORT
GPIOB #define AIN1_GPIO_CLK RCC_APB2Periph_GPIOB /*输出高电平*/ #define AIN1_ON
GPIO_SetBits(AIN1_GPIO_PORT,AIN1_GPIO_PIN) /*输出低电平*/ #define AIN1_OFF
GPIO_ResetBits(AIN1_GPIO_PORT,AIN1_GPIO_PIN) /*B1端口*/ #define AIN2_GPIO_PIN
GPIO_Pin_1 #defineAIN2_GPIO_PORT GPIOB #define AIN2_GPIO_CLK
RCC_APB2Periph_GPIOB/*输出高电平*/ #define AIN2_ON GPIO_SetBits(AIN2_GPIO_PORT,
AIN2_GPIO_PIN) /*输出低电平*/ #define AIN2_OFF GPIO_ResetBits(AIN2_GPIO_PORT,
AIN2_GPIO_PIN) /*B10端口*/ #define BIN1_GPIO_PIN GPIO_Pin_10 #define
BIN1_GPIO_PORT GPIOB #define BIN1_GPIO_CLK RCC_APB2Periph_GPIOB /*输出高电平*/
#defineBIN1_ON GPIO_SetBits(BIN1_GPIO_PORT,BIN1_GPIO_PIN) /*输出低电平*/ #define
BIN1_OFF GPIO_ResetBits(BIN1_GPIO_PORT,BIN1_GPIO_PIN) /*B11端口*/ #define
BIN2_GPIO_PIN GPIO_Pin_11 #define BIN2_GPIO_PORT GPIOB #define BIN2_GPIO_CLK
RCC_APB2Periph_GPIOB/*输出高电平*/ #define BIN2_ON GPIO_SetBits(BIN2_GPIO_PORT,
BIN2_GPIO_PIN) /*输出低电平*/ #define BIN2_OFF GPIO_ResetBits(BIN2_GPIO_PORT,
BIN2_GPIO_PIN) void AIN1_GPIO_Config(void); void AIN2_GPIO_Config(void); void
PWMA_STOP(void); void PWMA_Forward(int a); void PWMA_Reverse(int a); void
BIN1_GPIO_Config(void); void BIN2_GPIO_Config(void); void PWMB_STOP(void); void
PWMB_Forward(int a); void PWMB_Reverse(int a); void STOP(void); void Forward(
int a); void Reverse(int a); #endif
我个人认为只有右边的VM和VCC还有为什么会有两个GND,这一部分没有说清楚,接下来我会实际的测试一下这四个引脚,搞清楚了再来更新。
遇到好多初学者来问这篇文章的相关问题,我最近抽空写一个手把手教学。——2022.2.27
【如果忘了,提醒我一下。】