基于STM32的PWM电机驱动TB6612、A4950
基于STM32的PWM电机驱动TB6612、A4950
一、直流电机与驱动简介
- 直流电机是异种将电能转化为机械能的 装置,有两个电极,当电机正接时,电机正转,当电机反接时,电机反转
- 直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
- TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向
- A4950电机驱动模块是内置一个全桥电路的电机驱动芯片。用于脉宽调制计数(PWM)控制电机的转速。
1、H桥的介绍
图1-1H桥电路图
H桥中由两路推挽电路组成的,上接正极,下接负极,A、C端就是一路推挽电路,当A端MOS管导通,C端MOS管断开,那么左边输出就接在VM的正极,A端断开,C端导通就是接在PGND的电源负极;如果有两路推挽电路,A、D端导通,B、C端断开,电流就是从左往右流动;B、C端导通,A、D端断开,电流就是从右往左流动。H桥可以控制电流流动的反向,所以就可以控制电机的转向。
二、TB6612驱动板
1、驱动引脚介绍
图2-1TB6612驱动模块
VM:电机电源正极,是驱动电压输入端,范围是4.5V~10V
VCC:逻辑电平输入端,范围2.7V~5.5V,需要与控制器的电源保持一致。(这边我们是使用STM32,与STM32共用一个电源即可)
GND:接系统负极即可
AO1/2、BO1/2:两路电机的输出
PWMAB、AIN1/2、BIN1/2:这三个引脚则是控制A、B两路中的一路电机,连接到STM32的GPIO口即可,PWM引脚需要接到PWM信号输出端,其他两个引脚接任意两个普通GPIO口即可
STBY:待机控制引脚,接GND,芯片则不工作,处于待机状态;接逻辑电源VCC,芯片正常工作。这个引脚如果不需要待机模式,直接VCC即可;需要的话接GPIO口给高低电平,既可以控制。
2、驱动逻辑功能
A/BIN1 | A/BIN2 | 模式状态 |
H | H | 制动 |
H | L | 正转 |
L | H | 反转 |
L | L | 制动 |
当加入了PWM后,便可以通过占空比调节速度。
- 一种是IN1和IN2固定,PWM脚输入PWM,此时是配合慢衰减调速。例如:IN1为1,IN2为0,PWM为PWM,则正转和慢衰减相互切换;
- 另外一种是PWM脚为高电平,IN1、IN2中的一个固定另一个为PWM输入,此时是配合快衰减调速。例如,IN1为1,IN2为PWM输入,PWM为1,则正转与快衰减相互切换。
三、A4950驱动板
2、驱动引脚介绍
图3-1A4950引脚
图3-2芯片引脚图说明
2、驱动逻辑介绍
AIN1 | AIN2 | 直流电机状态 (AO1和AO2) |
任意 | 任意 | 停止 |
0 | 0 | 停止 |
0 | 1 | 正转 |
1 | 0 | 反转 |
1 | 1 | 刹车 |
A4950驱动板的四种驱动方式:
标号 1:芯片 IN1 端口输入一定的占空比 PWM,IN2 为低电平,此时芯片的输出端口会出去一个正电流。为电机正转。
标号 2:芯片IN1 端口输入低电平,IN2 端口输入一定的占空比 PWM,此时芯片的输出端口会出去一个负电流。为电机反转。
标号 3:芯片IN1 端口输入高电平,IN2 端口输入一定的占空比 PWM,此时芯片的输出端口会出去一个正电流。为电机正转。
标号 4:芯片IN1 端口输入一定的占空比 PWM,IN2 为高电平,此时芯片的输出端口会出去一个负电流。为电机反转。
我们可以选择标号 1和标号 4,只需要在一个 IN1 输入 pwm.另一个IN2 输入高电平或者低电平就可以实现控制电机的速度和正反转。
- 当xIN中有一个恒为低电平,另一个为PWM时:采取正反转与滑动/快衰减,占空比越大,转速越快。
- 当xIN中有一个恒为高电平,另一个为PWM时:采取正反转与制动/慢衰减,占空比越小,转速越快。(重点看一下,区别于TB6612)
具体信息可以参考这个博主写的驱动芯片原理,写的很详细 电机驱动芯片——DRV8833、TB6612、A4950、L298N的详解与比较_朽木白露的博客-CSDN博客_电机驱动芯片原理
四、代码程序(A4950驱动板)
需要的硬件有:F103C8T6,OLED屏,A4950驱动板,电机,若干杜邦线(公对母),(在这里我使用的是Jlink,所以我需要多加一个电源给驱动板)
Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"void Motor_Init(void)
{PWM_Init();//PWM初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开APB2时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);}void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){ //设置电机的正反转,由高电平和低电平来决定极性GPIO_SetBits(GPIOA,GPIO_Pin_2);//获得高电平PWM_Setcompare1(Speed);}else { GPIO_ResetBits(GPIOA,GPIO_Pin_2);//获得低电平PWM_Setcompare1(-Speed);//这时候setcompare为负数,Setcompare必须传正数,所以speed前面必须加一个负号}
}
在Motor.c中GPIO的模式需要选用 GPIO_Mode_Out_PP(推挽输出模式)。
注意:setcompare为负数时,Setcompare必须传正数,所以speed前面必须加一个负号
PWM.c
#include "stm32f10x.h" // Device headervoid PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//注意是开启APB1的时钟函数,因为TIM2是APB1总线的外设RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//选择时基单元的时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);TIM_InternalClockConfig(TIM2);//定时器上电后默认是使用内部时钟,如果不调用,也是使用内部时钟,可以不写//TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//通过ETR引脚的外部时钟模式2配置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自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;//PSC 预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,是高级计数器才有的TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//配置时基单元TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值,不用一一列出TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2 ;//设置输出比较的模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能TIM_OCInitStructure.TIM_Pulse = 0;//设置CCRTIM_OC1Init(TIM2, &TIM_OCInitStructure);//周期ARR;预分频PSC;CCR这三个值,共同决定输出PWM的周期和占空比 TIM_Cmd(TIM2,ENABLE);//启动定时器
}void PWM_Setcompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}
这里的PWM.c程序是根据上一篇博客修改的,不清楚怎么修改的可以参考上一篇文章喔
PWM的驱动使用(呼吸灯)_tz得像个小孩的博客-CSDN博客
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"
#include "Key.h"
#include "Motor.h"uint8_t KeyNum;//
int8_t Speed;int main(void)
{OLED_Init(); Motor_Init();Key_Init();Motor_SetSpeed(-80);OLED_ShowString(1, 1, "Speed:");while(1){KeyNum = Key_GetNum();if (KeyNum == 1){Speed += 20;if (Speed > 100){Speed = -100;}}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1, 7, Speed, 3);}}
程序效果![](https://img-blog.csdnimg.cn/08f6931333904914a2373a4fda4e4ecc.jpeg)
程序中由于A4950驱动板的逻辑电路与TB6612不同,当Speed显示正数时,电机的转速随着数值的增大而增大;但是在Speed显示为负数时,电机的转速会随着数值(PWM的值)的减小,电机的速度会越来越快。
- 当xIN中有一个恒为低电平,另一个为PWM时:采取正反转与滑动/快衰减,占空比越大,转速越快。
- 当xIN中有一个恒为高电平,另一个为PWM时:采取正反转与制动/慢衰减,占空比越小,转速越快。(重点看一下,区别于TB6612)
五、代码(TB6612驱动板)
PWM.c的程序大差不差,但是在接IO比A4950多了一个引脚,所以具体程序的区别在于Motor.c程序中,程序的呈现效果是Speed的数值为正为正转,负值则为反转,数值越大转速越快。这里TB6612的呈现效果与A4950不一样。
Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"void Motor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开APB2时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5);PWM_Init();//PWM初始化
}void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){ //设置电机的正反转,由高电平和低电平来决定极性GPIO_SetBits(GPIOA,GPIO_Pin_4);//获得高电平GPIO_ResetBits(GPIOA,GPIO_Pin_5);//获得低电平PWM_Setcompare3(Speed);}else{GPIO_SetBits(GPIOA,GPIO_Pin_5);//获得高电平GPIO_ResetBits(GPIOA,GPIO_Pin_4);//获得低电平PWM_Setcompare3(-Speed);//这时候setcompare为负数,Setcompare必须传正数,所以speed前面必须加一个负号}
}
总结:每个驱动板的驱动逻辑不相同,个人认为A4950驱动的程序没有调试好,有待改进。
如果本篇文章部分为个人理解,如果发现错误可以告诉我一下,进行改进,虚心学习。