1. 直流电机原理

下面是分析直流电机的物理模型图。其中,固定部分有磁铁,这里称作主磁
极;固定部分还有电刷。转动部分有环形铁心和绕在环形铁心上的绕组。(其中2 个小圆圈是为了方便表示该位置上的导体电势或电流的方向而设置的)
在这里插入图片描述

它的固定部分(定子)上,装设了一对直流励磁的静止的主磁极N 和S,在旋转部分(转子)上装设电枢铁心。在电枢铁心上放置了两根导体连成的电枢线圈,线圈的首端和末端分别连到两个圆弧形的铜片上,此铜片称为换向片。换向片之间互相绝缘,由换向片构成的整体称为换向器。换向器固定在转轴上,换向片与转轴之间亦互相绝缘。在换向片上放置着一对固定不动的电刷B1 和B2,当电枢旋转时,电枢线圈通过换向片和电刷与外电路接通。

在电刷上施加直流电压U,电枢线圈中的电流流向为:N 极下的有效边中的电流总是一个方向,而S 极下的有效边中的电流总是另一个方向。这样两个有效边所受的洛伦兹力的方向一致(可以根据左手法则判定),电枢开始转动。

具体来说,就是把上图中的+和-分别接到电池的正极和负极,电机即可转动;如果是把上图中的+和-分别接到电池的负极和正极,则电机会反方向转动。电机的转速可以理解为和外接的电压是正相关的(实际是由电枢电流决定)。

总而言之,如果我们可以调节施加在电机上面的直流电压大小,即可实现直流电机调速,改变施加电机上面直流电压的极性,即可实现电机换向。

2. 减速器

一般直流电机的转速都是一分钟几千上万转的,所以一般需要安装减速器。减速器是一种相对精密的机械零件,使用它的目的是降低转速,增加转矩。减速后的直流电机力矩增大、可控性更强。按照传动级数不同可分为单级和多级减速器;按照传动类型可分为齿轮减速器、蜗杆减速器和行星齿轮减速器。

在这里插入图片描述
齿轮减速箱体积较小,传递扭矩大,但是有一定的回程间隙。

蜗轮蜗杆减速机的主要特点是具有反向自锁功能,可以有较大的减速比,但是一般体积较大,传动效率不高,精度不高。

行星减速机其优点是结构比较紧凑,回程间隙小、精度较高,使用寿命很长,额定输出扭矩可以做的很大,但价格略贵。

以下是一款搭配多级齿轮减速箱的电机MG513。
在这里插入图片描述

3.电机实物接线图解

具体到我们的电机,我们可以看看电机后面的图解。
在这里插入图片描述


上面介绍了一大堆说直流电机只引出两个线,怎么这个电机有6 个线,而且还有两个大焊点呢?其实,根据上面的图解也知道,那两个焊点分别和黄线和棕线是连接在一起的。也就是说只有6 个线,而6P 排线中,中间的四根线(红绿白黑)是编码器的线,只是用于测速,和直流电机本身没有联系。我们在实现开环控制的时候无需使用。

综上所述,我们只需控制施加在黄线和棕色线两端的直流电压大小和极性即可实现调试和换向。

4.TB6612FNG 使用说明

要实现上面的调试和换向功能,我们可以使用单片机实现的,但是单片机IO 的带负载能力较弱,而直流电机是大电流感性负载,所以我们需要功率放大器件,在这里,我们选择了TB6612FNG。

TB6612FNG 是东芝半导体公司生产的一款直流电机驱动器件,它具有大电流MOSFET-H 桥结构,双通道电路输出,可同时驱动2 个电机。也许大家更熟悉L298N,其实这两者的使用基本一致的。而且,相比L298N 的热耗性和外围二极管续流电路,它无需外加散热片,外围电路简单,只需外接电源滤波电容就可以直接驱动电机,利于减小系统尺寸。对于PWM 信号输入频率范围,高达100 kHz 的频率更是足以满足我们大部分的需求了。

在这里插入图片描述
在这里插入图片描述
以下是TB6612FNG 的主要参数:

  • 最大输入电压:VM = 15V
  • 最大输出电流:Iout = 1.2A(平均)/3.2A(峰值)
  • 正反转/短路刹车/停机功能模式
  • 内置过热保护和低压检测电路

VM 直接接电池即可,VCC 是内部的逻辑供电,一般给3.3 或者5V 都行,模块的3 个GND 接任意一个即可,因为都是导通的,STBY 置高模块才能正常工作。

完成上面的接线之后,我们就可以开始控制电机了,上图中红色部分的5个引脚控制一路电机,蓝色部分的控制另外一路电机,这里只讲其中的A 路,B路的使用是一样的。AO1 和AO2 分别接到电机的+和-。然后通过PWMA、AIN2、AIN1控制电机。其中PWMA 接到单片机的PWM 引脚,一般10Khz 的PWM 即可,并通过改变占空比来调节电机的速度。下面是真值表:

在这里插入图片描述

5. STM32F1电机驱动例程

此例程用于初始化小车底盘上的两个直流电机,需要自己根据实际情况修改定时器和引脚

#.c文件
#include "motor.h"

void Motor_IO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能端口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能端口时钟
	
	GPIO_InitStructure.GPIO_Pin = IN1_PIN_A;			//端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//50M
	GPIO_Init(IN1_PORTA, &GPIO_InitStructure);			//根据设定参数初始化GPIO
	
	GPIO_InitStructure.GPIO_Pin = IN2_PIN_A;			//端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//50M
	GPIO_Init(IN2_PORTA, &GPIO_InitStructure);			//根据设定参数初始化GPIO
	
	GPIO_InitStructure.GPIO_Pin = IN1_PIN_B;			//端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//50M
	GPIO_Init(IN1_PORTB, &GPIO_InitStructure);			//根据设定参数初始化GPIO
	
	GPIO_InitStructure.GPIO_Pin = IN2_PIN_B;			//端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//50M
	GPIO_Init(IN2_PORTB, &GPIO_InitStructure);			//根据设定参数初始化GPIO
	
	GPIO_ResetBits(IN1_PORTA,IN1_PIN_A);	//io输出0,防止电机乱转
	GPIO_ResetBits(IN2_PORTA,IN2_PIN_A);	//io输出0,防止电机乱转
	GPIO_ResetBits(IN1_PORTB,IN1_PIN_B);	//io输出0,防止电机乱转
	GPIO_ResetBits(IN2_PORTB,IN2_PIN_B);	//io输出0,防止电机乱转
}

void Motor_PWM_Init(u16 arr,u16 psc) //初始化时arr=10-1,psc=7200-1,则占空比区间为0-7200
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);  //使能定时器8 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIO外设时钟
	
	GPIO_InitStructure.GPIO_Pin = PWM_PIN_A;  //端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //50M
	GPIO_Init(PWM_PORTA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = PWM_PIN_B;  //端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //50M
	GPIO_Init(PWM_PORTB, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

 	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;                            //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set; 
	TIM_OC1Init(TIM8, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);  //CH1预装载使能	 
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;                            //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set; 
	TIM_OC2Init(TIM8, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);  //CH2预装载使能

	TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIMx在ARR上的预装载寄存器	
	
	TIM_Cmd(TIM8, ENABLE);  //使能TIM8
	
	TIM_CtrlPWMOutputs(TIM8,ENABLE); //高级定时器输出必须使能这句
}


/**************************************************************************
函数功能:电机驱动
入口参数:两个电机的pwm值
返回  值:无 
注    意:700<pwm<7200
**************************************************************************/
void Motor_Run(float pwmA,float pwmB)
{
	if(pwmA>0)AIN1=1,AIN2=0;
	else if(pwmA<0)AIN1=0,AIN2=1;
	else AIN1=0,AIN2=0;
	PWMA = abs(pwmA);
	
	if(pwmB>0)BIN1=1,BIN2=0;
	else if(pwmB<0)BIN1=0,BIN2=1;
	else BIN1=0,BIN2=0;
	PWMB = abs(pwmB);
}

#endif

#.h文件
#ifndef __MOTOR_H
#define __MOTOR_H
#include "init.h" //这里面include了所有需要的头文件

/*--------Motor_A control pins--------*/

#define PWM_PORTA GPIOC			//PWMA
#define PWM_PIN_A GPIO_Pin_6	//PWMA
#define PWMA 	  TIM8->CCR1	//PWMA

#define IN1_PORTA GPIOA			//AIN1
#define IN1_PIN_A GPIO_Pin_3	//AIN1
#define AIN1 	  PAout(3)		//AIN1

#define IN2_PORTA GPIOA			//AIN2
#define IN2_PIN_A GPIO_Pin_2	//AIN2
#define AIN2 	  PAout(2)		//AIN2
/*------------------------------------*/

/*--------Motor_B control pins--------*/

#define PWM_PORTB GPIOC			//PWMB
#define PWM_PIN_B GPIO_Pin_7	//PWMB
#define PWMB 	  TIM8->CCR2	//PWMB

#define IN1_PORTB GPIOA			//BIN1
#define IN1_PIN_B GPIO_Pin_4	//BIN1
#define BIN1 	  PAout(4)		//BIN1

#define IN2_PORTB GPIOA			//BIN2
#define IN2_PIN_B GPIO_Pin_5	//BIN2
#define BIN2 	  PAout(5)		//BIN2
/*------------------------------------*/

void Motor_IO_Init(void);
void Motor_PWM_Init(u16 arr,u16 psc);
void Motor_Run(float pwmA,float pwmB);