Bootstrap

玩转电机驱动——DRV8848驱动直流减速电机(STM32F103)



前言

采用两块DRV8848驱动四路电机,程序部分参考https://blog.csdn.net/weixin_44808082/article/details/113465107?spm=1001.2014.3001.5501


一、硬件基础

单片机:STM32F103RCT6
电机驱动芯片:DRV8848,两块驱动四路电机
直流减速电机:GB37-520

二、DRV8848驱动

1. DDRV8848芯片特性

在这里插入图片描述
(1)工作电源电压范围为4V至18V;
(2)双路H桥电机驱动器,可驱动单/双通道刷式直流、步进电机;
(3)每个H桥均提供高输出电流,最大驱动器电流为2A(12V,25℃),并联模式下最大驱动器电流为4A(12V,25℃);
(4)VM欠压闭锁(UVLO);
(5)过流保护(OCP);
(6)热关断(TSD);
(7)故障条件指示引脚(nFAULT)。

2. 引脚的功能及类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(1)VCC不是DRV8848上的引脚,但开漏输出nFAULT需要VCC电源电压上拉;nFAULT可能被拉上到VINT

3. DRV8848电路图

四路驱动的DRV8848电路图。
在这里插入图片描述

三、STM32驱动程序

1. 电路分析

MCU电路图如下图所示。
在这里插入图片描述
结合DRV8848电路图确定引脚,此文暂未用到编码器,因此HALL引脚未列出。
在这里插入图片描述

2. 程序编写

利用了TIM2 4个通道产生PWM输出到AIN1、AIN2、BIN1、BIN2,利用AIN1和AIN2之间的PWM差,驱动电机转动。另一个DRV8848同理,其占用了TIM4的4个通道,驱动两组电机。

还有要注意,PA15、PC0接nSLEEP,此引脚需要输出高电平才能使能DRV8848,否则进入低功耗休眠模式。但是PA15默认为JTAG调试的引脚,所以要关闭JTAG,只用SWD调试模式。

2.1 main.c

代码如下:

# 	include "stm32f10x.h"
#	include "LED.h"
#	include "Delay.h"
#	include "PWM.h"
/***************************************************
TIM2通道1/2控制前左轮电机正反转,CCR1>CCR2时正传
TIM2通道3/4控制前右轮电机正反转,CCR3>CCR4时正传
TIM4通道1/2控制后左轮电机正反转,CCR1>CCR2时正传
TIM4通道3/4控制后右轮电机正反转,CCR3>CCR4时正传
***************************************************/
int main(void)
{ 
	JTAG_Init();	
	LED_Init();                     //LED 连接的硬件接口	
	MotorEn_Init();
	Delay_ms(100);   
	Motor_EN();	
	PWM_TIM2_Init();                //TIM2_PWM输出初始化
    PWM_TIM4_Init();                //TIM4_PWM输出初始化
	Delay_ms(1000);                 //延时等待初始化稳定

	GPIO_SetBits(GPIOC, GPIO_Pin_3);      //设置LED高电平输出
	Delay_ms(100);
	GPIO_ResetBits(GPIOC, GPIO_Pin_3);    //设置LED高电平输出
	Delay_ms(100);
	GPIO_SetBits(GPIOC, GPIO_Pin_3);      //设置LED高电平输出

	while(1)
		{		
			GPIO_SetBits(GPIOC, GPIO_Pin_3);  //设置LED高电平输出
			Delay_us(20);   				  //延时500毫秒

			TIM_SetCompare1(TIM2,750);        //设置TIM2  CH1占空比输出  PA0
			TIM_SetCompare2(TIM2,0);          //设置TIM2  CH2占空比输出  PA1
			TIM_SetCompare3(TIM2,1000);       //设置TIM2  CH1占空比输出  PA2
			TIM_SetCompare4(TIM2,0);          //设置TIM2  CH2占空比输出  PA3
		
			TIM_SetCompare1(TIM4,0);          //设置TIM4  CH1占空比输出  PB6
			TIM_SetCompare2(TIM4,1500);       //设置TIM4  CH2占空比输出  PB7
			TIM_SetCompare3(TIM4,0);          //设置TIM4  CH3占空比输出  PB8
			TIM_SetCompare4(TIM4,2000);       //设置TIM4  CH4占空比输出  PB9
			
		} 
}

2.2 PWM.c

代码如下:

# include "PWM.h"

/*  关闭JTAG调试模式,以使用PA15引脚 */
void JTAG_Init(void)

{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //先开启开启AFIO复用时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JTAG,保留SWD(选择GPIO_Remap_SWJ_Disable,将失去两个调试模式,勿用!)
}

/*  配置PC0、PA15的GPIO,初始化DRV8848芯片的使能引脚 */
void MotorEn_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  	//使能C口GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  	//使能A口GPIO时钟

	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     		//选择推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;					//指定引脚PC0,MotEn2
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;			//设置输出速率10MHz
	GPIO_Init(GPIOC,&GPIO_InitStruct);						//初始化外设GPIOC寄存器
	GPIO_ResetBits(GPIOC, GPIO_Pin_0);
	

	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;				//选择推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;					//指定引脚PA15,MotEn1
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;			//设置输出速率10MHz
	GPIO_Init(GPIOA,&GPIO_InitStruct);						//初始化外设GPIOA寄存器
	GPIO_ResetBits(GPIOA, GPIO_Pin_15);	
}

/*  使能DRV8848芯片的nSLEEP引脚 */
void Motor_EN(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_15);                     //PA15_MotorAB_EN
	GPIO_SetBits(GPIOC, GPIO_Pin_0);                      //PC0_MotorAB_EN
}

/*    配置TIM2定时器输出PWM       */
void PWM_TIM2_Init(void)
{
	
	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //开启AFIO复用时钟,重映射使用TIM2定时器
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);    //使能TIM2时钟 
	
	/* GPIO初始化结构体 */
	GPIO_InitTypeDef  GPIO_InitStructure;                 
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;   //TIM2 Ch1/2/3/4
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);                  //初始化 GPIOA
	
    /* TIM时间基数初始化结构体 */
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseSrtructure;     
	TIM_TimeBaseSrtructure.TIM_Period= TIM2_Reload_Num_ARR;           //计数器TIMx_CNT计数,从0累加到ARR次后溢出,设置自动重装载值
	TIM_TimeBaseSrtructure.TIM_Prescaler=TIM2_Frequency_Divide_PSC;   //设置预分频系数 PSC
	TIM_TimeBaseSrtructure.TIM_ClockDivision=0;                       //1分频,用于滤波信号抖动
	TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up;        //向上计数模式溢出
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseSrtructure);					  //初始化TIM2的时钟参数
	
    /* TIM输出比较功能初始化结构体 */
	TIM_OCInitTypeDef	TIM_OCInitStructure;             
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;     			  //选择定时器模式为比较低输出。
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;     //比较输出使能
	TIM_OCInitStructure.TIM_Pulse =(TIM2_Reload_Num_ARR+1)*0;         //比较输出脉冲宽度,设置占空比(初始化用),即CCR
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;           //输出极性:TIM输出比较极性高
	
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);          				  //初始化TIM2  CH1的时钟,下同	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
	TIM_OC4Init(TIM2,&TIM_OCInitStructure);


	
	
	/* 初始化CH1/2/3/4 */
	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
	TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH2 预装载使能
	TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH3 预装载使能
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH4 预装载使能
	TIM_ARRPreloadConfig(TIM2,ENABLE);                                //使能 TIMx在ARR上的预装载寄存器
	
	TIM_Cmd(TIM2, ENABLE);                                            //使能 TIM2

	
}

void PWM_TIM4_Init(void)
{
	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //开启AFIO复用时钟,重映射使用TIM4定时器
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //使能GPIOB外设时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);    //使能TIM4时钟 
	
	/* GPIO初始化结构体 */
	GPIO_InitTypeDef  GPIO_InitStructure;                 
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;   //TIM4 Ch1/2/3/4
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOB,&GPIO_InitStructure);                  //初始化 GPIOB
	
    /* TIM时间基数初始化结构体 */
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseSrtructure;     
	TIM_TimeBaseSrtructure.TIM_Period= TIM4_Reload_Num_ARR;           //计数器TIMx_CNT计数,从0累加到ARR次后溢出,设置自动重装载值
	TIM_TimeBaseSrtructure.TIM_Prescaler=TIM4_Frequency_Divide_PSC;   //设置预分频系数 PSC
	TIM_TimeBaseSrtructure.TIM_ClockDivision=0;                       //1分频,用于滤波信号抖动
	TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up;        //向上计数模式溢出
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseSrtructure);					  //初始化TIM4的时钟参数
	
    /* TIM输出比较功能初始化结构体 */
	TIM_OCInitTypeDef	TIM_OCInitStructure;             
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;     			  //选择定时器模式为比较低输出。
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;     //比较输出使能
	TIM_OCInitStructure.TIM_Pulse =(TIM4_Reload_Num_ARR+1)*0;         //比较输出脉冲宽度,设置占空比(初始化用),即CCR
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;           //输出极性:TIM输出比较极性高
	
	
	TIM_OC1Init(TIM4,&TIM_OCInitStructure);          				  //初始化TIM4  CH1的时钟,下同	
	TIM_OC2Init(TIM4,&TIM_OCInitStructure);
	TIM_OC3Init(TIM4,&TIM_OCInitStructure);
	TIM_OC4Init(TIM4,&TIM_OCInitStructure);
	
	/* 初始化CH1/2/3/4 */
	TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
	TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH2 预装载使能
	TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH3 预装载使能
	TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH4 预装载使能
	TIM_ARRPreloadConfig(TIM4,ENABLE);                                //使能 TIMx在ARR上的预装载寄存器
	
	TIM_Cmd(TIM4, ENABLE);                                            //使能 TIM4


}
	

2.2 PWM.h

代码如下:

# ifndef  _PWM_H
# define  _PWM_H
# include "stm32f10x.h"

#define TIM2_Reload_Num_ARR  1999             //自动重装载寄存器值
#define TIM2_Frequency_Divide_PSC   35    	  //TIM时钟预分频值

#define TIM4_Reload_Num_ARR  1999             //自动重装载寄存器值
#define TIM4_Frequency_Divide_PSC   35        //TIM时钟预分频值


void JTAG_Init(void);
void MotorEn_Init(void);
void Motor_EN(void);	
void PWM_TIM2_Init(void);                       //TIM2_PWM输出初始化
void PWM_TIM4_Init(void);                       //TIM4_PWM输出初始化

#endif


总结

本文利用两个DRV8848驱动四路电机,含STM32F103的程序编写。

;