文章目录
前言
采用两块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的程序编写。