STM32 TB6612驱动的直流有刷减速电机

狂风中的少年 提交于 2020-08-08 02:34:02

title: 减速直流有刷电机
date: 2020-05-20 19:45:11
tags:
categories: STM32学习记录



电机的基本认识

这里呢,平衡小车最常用到的是直流编码有刷电机直流的意思是使用直流电,给引脚通的是恒定电流;编码指的是电机自带编码盘,上面有两个相位正交的编码器,可以利用四倍频技术实现对电机位置和转速的精确追踪;有刷指的是电机内部自带换向器,电机转子每旋转180度,线圈中的电流即自动换向,不需要软件或者硬件驱动的控制。

这种电机通常有6个引脚:电源引脚:5V、GND,PWM输入引脚:IN1、IN2,编码器输出引脚:OUT1、OUT2。

PCB走线时要注意只有编码器引脚是信号线,可以走细一些,其他线建议走粗一些(30mil以上)。

电机驱动:TB6612

由于STM32的引脚只能提供3.3V电压,且功率输出能力很弱,因此需要功率放大器件对电机进行控制,并且为了保持控制的实时性,以及精准性,需要高速的功率控制器件,这就需要一款专用的电机驱动芯片。

这里使用体积较小,同时有较大驱动能力的TB6612驱动芯片,可以同时驱动两路电机,利用其内部的高速H桥,向电机输出PWM波,控制其正传,反转,制动,自由转动(不加动力也不加阻尼力),以及转速的调节。

驱动芯片除了电源引脚以及使能引脚之外,还有各两组,两种功能的引脚:

  • 来自MCU的3个引脚:1个PWM输入引脚,用于控制转速,2个控制引脚,用于控制正反,制动,空挡(不施加力)。

  • 输出给电机的2个引脚:OUT1,OUT2,通过输出PWM波控制电机的全部功能,搭载较大电流。

驱动编写

通过对电机以及电机驱动的功能分析,我们知道了控制1个电机,需要3个引脚,1个输出PWM波用于控制速度,2个高速推挽输出,通过切换高低电平,即可实现对电机的驱动状态控制。

平衡车有2个电机需要控制,因此用于驱动电机的引脚有6个,2个是定时器的PWM功能映射的引脚。

这里我为了节省定时器资源,使用一个定时器TIM1,该定时器的1、4通道(分别对应PA8,PA11引脚),来输出两路频率相同,但是占空比互不影响,独立可调的PWM信号,然后另外找4个普通IO口,用于对电机状态进行控制。

TIM1映射

电机驱动

MOTOR.h

#ifndef __MOTOR_H
#define __MOTOR_H
#include <sys.h>			//包含引脚转换的宏函数,便于编写代码

#define PWMA   TIM1->CCR1  //用于控制A电机的PWM占空比调节
#define AIN2   PBout(15)
#define AIN1   PBout(14)

#define PWMB   TIM1->CCR4  //用于控制B电机的PWM占空比调节
#define BIN1   PBout(13)
#define BIN2   PBout(12)

void MiniBalance_PWM_Init(u16 arr,u16 psc);
void MiniBalance_Motor_Init(void);
#endif

这里干了几件事:

  • 电机控制引脚宏定义

  • PWM占空比改变宏定义

  • 两个初始化函数宏定义

MOTOR.c

首先是对4个控制引脚的初始化,高速下拉推挽输出:

#include "MOTOR.h"

TIM_HandleTypeDef 	TIM1_Handler = {0};	  	//定时器1句柄 
TIM_OC_InitTypeDef 	TIM1_CH14Handler = {0};	//定时器1通道14句柄


void MiniBalance_Motor_Init(void)		//完成4个控制引脚的初始化
{
	GPIO_InitTypeDef GPIO_Initure = {0};	//声明初始化结构体
	__HAL_RCC_GPIOB_CLK_ENABLE();			//开启GPIOB时钟

	GPIO_Initure.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;	//端口配置
	GPIO_Initure.Pull = GPIO_NOPULL;
	GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;	  						//推挽输出
	GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;					 //50M
	
	HAL_GPIO_Init(GPIOB, &GPIO_Initure);				  //根据设定参数初始化GPIOB 
}

然后是对PWM外设的初始化,这里用定时器1的1、4通道,映射到PA8和PA11两个引脚用来控制两个电机的转速:

//TIM1 PWM初始化 
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
void MiniBalance_PWM_Init(u16 arr,u16 psc)		//完成两个PWM输出引脚的初始化
{
	TIM1_Handler.Instance=TIM1;							//定时器1
	TIM1_Handler.Init.Prescaler=psc;					//定时器分频
	TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;	//向上计数模式
	TIM1_Handler.Init.Period=arr;		 				//自动重装载值
	TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_PWM_Init(&TIM1_Handler);	  			 //初始化PWM
	
	TIM1_CH14Handler.OCMode=TIM_OCMODE_PWM1;		 	//模式选择PWM1
	TIM1_CH14Handler.Pulse= 0;						//设置比较值,初始占空比设为0
	TIM1_CH14Handler.OCPolarity=TIM_OCPOLARITY_HIGH; 	//输出极性 高电平有效 
	HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH14Handler,TIM_CHANNEL_1);//初始化TIM1,PWM通道1、4
	HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH14Handler,TIM_CHANNEL_4);//初始化TIM1,PWM通道1、4
	
	HAL_TIM_PWM_Start(&TIM1_Handler,TIM_CHANNEL_1);	//开启PWM通道1、4
	HAL_TIM_PWM_Start(&TIM1_Handler,TIM_CHANNEL_4);	//开启PWM通道1、4
}

在HAL_TIM_PWM_Init()中会调用端口初始化MSP函数,需要用户重定义覆盖HAL库的若定义函数:

//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef GPIO_Initure;
	
    if(htim->Instance==TIM1)
	{
		__HAL_RCC_TIM1_CLK_ENABLE();			//使能TIM1时钟
		__HAL_AFIO_REMAP_TIM1_PARTIAL();		//TIM1通道引脚部分重映射使能
		__HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
		
		GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_11;           	//PA8 PA11
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//复用推挽输出,用于输出PWM
		GPIO_Initure.Pull=GPIO_PULLDOWN;          //下拉
		GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
		HAL_GPIO_Init(GPIOA,&GPIO_Initure); 	
	}
}

然后是中断服务函数,等等,我们设置了自动重装填,不需要中断控制,OK结束。

如何使用电机:实践

控制集成封装

这里集成了控制小车所需的代码,现在只添加电机控制这一模块

CONTROL.h

#ifndef __CONTROL_H
#define __CONTROL_H
#include "sys.h"

void Set_Pwm(int moto1,int moto2);
int myabs(int a);					//绝对值函数

#endif

两个函数,核心是第一个,设置PWM的重装填阈值,相当于控制了占空比,这样就实现了调速的功能。

CONTROL.c

#include "CONTROL.h"

/**************************************************************************
函数功能:赋值给PWM寄存器
入口参数:左轮PWM、右轮PWM
返回  值:无
**************************************************************************/
void Set_Pwm(int moto1,int moto2)
{
   int siqu=500;//死区补偿,防止数值过小无法驱动
			if(moto1<0)			BIN2=0,			BIN1=1;		//正转
			else 	          BIN2=1,			BIN1=0;		//反转
			PWMB=myabs(moto1)+siqu;
		  if(moto2<0)	AIN1=0,			AIN2=1;				//正转
			else        AIN1=1,			AIN2=0;				//反转
			PWMA=myabs(moto2)+siqu;	
}

/**************************************************************************
函数功能:绝对值函数
入口参数:int
返回  值:unsigned int
**************************************************************************/
int myabs(int a)
{ 		   
	  int temp;
		if(a<0)  temp=-a;  
	  else temp=a;
	  return temp;
}

上面这个是实现功能的函数,Set_pwm函数是根据TB6612电机驱动芯片的真值表来计算的,通过直接访问TIM1的CCR寄存器,注意考虑两个电机的中心对称分布,所以写的时候将一个反向,实现输入两个正数,两个电机的转动都使小车向前走即可。

mian函数:

//头文件略去
int main(void)
{
	HAL_Init();
	Stm32_Clock_Init(RCC_CFGR_PLLMULL9);
	JTAG_Set(SWD_ENABLE);
	//uart_init(115200);
	delay_init(72);
	KEY_Init();
	MiniBalance_Motor_Init();
	MiniBalance_PWM_Init(7199,0);   //PWM输出,溢出值7200,不分频,10KHz频率,100um周期
	while(1)
	{
		Set_Pwm(3000, 3000);
		delay_ms(1000);
		Set_Pwm(-3000, -3000);
		delay_ms(1000);
	}
}

这里放了一个最简单的一秒正转,一秒反转,因为还没有研究PID的原理,后面会结合MPU6050触发中断来进行数据处理,反馈给电机,来进行最基本的控制。网上找不到HAL库的历程,就搞来FW3.5标准库来研究,慢慢摸索终于把这电机弄转起来了,实现了多轮运动嘿嘿。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!