STM32驱动LV8731V【CubeMX+可调速+可控制数量的PWM+DMA】注:DRV8825也可用

目录

价格:

引脚简介:

引脚配置:

·设定工作/待机

·设定驱动电机种类

·设定励磁模式

·设定衰减比从而控制输出电流

·设定间隙频率

·设定输出使能

·设定正、反转

·短路检测

硬件电路:

MX配置:

PWM配置:

DMA配置:

代码:

DrvLV8731V.H

DrvLV8731V.C

AppLV8731V.H

AppLV8731V.C


 

价格:

        一个是安森美的,一个是德州仪器的,同为步进电机驱动芯片,LV8731V差不多是DRV8825的两倍价格。当然,市面上的同类芯片很多,但驱动方式都是差不多的,都是用PWM输入到step脚控制步进,其它引脚配置相应的功能,比如说细分,输出电流等等。我这里使用的是LV8731V,所以以LV8731V为例。

引脚简介:

        这款分别有驱动直流电机和步进电机两种模式,这里以驱动步进电机为例,用这款芯片驱动直流电机属实大材小用,想看直流电机驱动的可以看我这篇文章:http://t.csdnimg.cn/O9EMx

电平标准:

引脚配置:

        这里我只写一些关键的引脚功能及配置,其它详细信息大家可以去看手册,附上LV8731V的中文手册:通过百度网盘分享的文件:步进电机驱动LV8731V.pdf
链接:https://pan.baidu.com/s/14_tquvj3gTdAwXWe0dxH4g?pwd=3569 
提取码:3569 

·设定工作/待机

这里我们在电路接VDD(3.3V),配置成工作模式。

·设定驱动电机种类

这里我们在电路上接GND,配置成STM模式。

·设定励磁模式

这里我把MD2接的VDD,MD1接的单片机,当MD1低时为W1-2相励磁(4细分),高时为4W1-2相励磁(16细分)和模式。最终我使用的时候是配置成的16细分,毕竟有最多的就用最多的,来都来了,你懂的。

·设定衰减比从而控制输出电流

可以看出,输出电流由参考电压和RF电阻共同决定。

·设定间隙频率

·设定输出使能

接在单片机上。

·设定正、反转

接在单片机上。

·短路检测

接在单片机上,当检测到这个引脚为低电平时判断电机短路。

硬件电路:

这里我用到了两个步进,所以用两块芯片

MX配置:

我这里使用的单片机是STM32G0B1CBTX,其它款的STM32单片机也是一样的。

用到了两个通道:

配置定时器的可以看下这篇文章:http://t.csdnimg.cn/6Ca7D

这里对定时时长的配置没有那么严格,我们在代码里会重新更改分频和计数次数以更改电机速度。

PWM配置:

DMA配置:

DMA配置可以看一下我这篇文章:http://t.csdnimg.cn/Wk0vc

代码:

我这里把代码分成了DrvLV8731V和AppLV8731V,一个为驱动层,一个为应用层,AppLV8731V对DrvAT8870再封装了一次供用户调用。

DrvLV8731V.H
#ifndef _DRV_LV8731V_H_
#define _DRV_LV8731V_H_
#include "DrvSys.h"

#define ONCE_PWM_CNT    	100	//一次传送的pwm个数

//GPIO配置
//LV8731V输出使能,低电平使能
#define LV8731VEnable1()  	HAL_GPIO_WritePin(OE1_GPIO_Port, OE1_Pin, GPIO_PIN_RESET)	
#define LV8731VEnable2()  	HAL_GPIO_WritePin(OE2_GPIO_Port, OE2_Pin, GPIO_PIN_RESET)
#define LV8731VDisable1()  	HAL_GPIO_WritePin(OE1_GPIO_Port, OE1_Pin, GPIO_PIN_SET)
#define LV8731VDisable2()  	HAL_GPIO_WritePin(OE2_GPIO_Port, OE2_Pin, GPIO_PIN_SET)
//LV8731V励磁模式配置,低电平4细分,高电平16细分
#define LV8731V_4divide_1()  	HAL_GPIO_WritePin(MODE1_1_GPIO_Port, MODE1_1_Pin, GPIO_PIN_RESET)	
#define LV8731V_4divide_2()  	HAL_GPIO_WritePin(MODE1_2_GPIO_Port, MODE1_2_Pin, GPIO_PIN_RESET)
#define LV8731V_16divide_1()  	HAL_GPIO_WritePin(MODE1_1_GPIO_Port, MODE1_1_Pin, GPIO_PIN_SET)
#define LV8731V_16divide_2()  	HAL_GPIO_WritePin(MODE1_2_GPIO_Port, MODE1_2_Pin, GPIO_PIN_SET)
//LV8731V输出电流配置,低电平100%,高电平50%
#define LV8731V_100I_1()  	HAL_GPIO_WritePin(ATT2_1_GPIO_Port, ATT2_1_Pin, GPIO_PIN_RESET)	
#define LV8731V_100I_2()  	HAL_GPIO_WritePin(ATT2_2_GPIO_Port, ATT2_2_Pin, GPIO_PIN_RESET)
#define LV8731V_50I_1()  	HAL_GPIO_WritePin(ATT2_1_GPIO_Port, ATT2_1_Pin, GPIO_PIN_SET)
#define LV8731V_50I_2()  	HAL_GPIO_WritePin(ATT2_2_GPIO_Port, ATT2_2_Pin, GPIO_PIN_SET)
//LV8731V方向控制,低电平正转
#define LV8731VFrForeward1()  	HAL_GPIO_WritePin(FR1_GPIO_Port, FR1_Pin, GPIO_PIN_RESET)	
#define LV8731VFrForeward2()  	HAL_GPIO_WritePin(FR2_GPIO_Port, FR2_Pin, GPIO_PIN_RESET)
#define LV8731VFrReversal1()  	HAL_GPIO_WritePin(FR1_GPIO_Port, FR1_Pin, GPIO_PIN_SET)
#define LV8731VFrReversal2()  	HAL_GPIO_WritePin(FR2_GPIO_Port, FR2_Pin, GPIO_PIN_SET)
//LV8731V短路EMO信号读取
#define LV8731VReadEmo1()  	HAL_GPIO_ReadPin(EMO1_GPIO_Port, EMO1_Pin)
#define LV8731VReadEmo2()  	HAL_GPIO_ReadPin(EMO2_GPIO_Port, EMO2_Pin)


enum 
{
    LV0 = 0,			//升降电机
    LV1,				//晶向电机
    LVNum
};//LV8731V驱动的个数

void PWMStart(u8 idx, u8 fr, u32 cstep);
void PWMStop(u8 idx);
void SetPWMFre(u8 idx, u16 cnt);
u8 GetLV8731VEmo(u8 idx);
DrvLV8731V.C
#include "DrvLV8731V.h"

/**************************************************
说明:
使用PWM+DMA输出指定频率、指定占空比、指定个数的脉冲。
LV8731V的频率0~13K,
**************************************************/

static struct
{
	u16 pwm_dma_cnt;			//进行的DMA次数
	u16 pwmcnt_residue;			//剩余的pwm脉冲数
	u16 callback_mode;			//回调方式 0:什么都不执行	1:直接关闭PWM(=<100)	2:(>100)
}LV8731VPara[2]={0};

static u32 Data[LVNum][ONCE_PWM_CNT];//发送区缓存

/*******************************
开始发送pwm,DMA模式
idx:电机索引		0升降电机			1晶向电机
fr:旋转方向			0正转				1反转
指定的pwm数量		0一直发送pwm		非0:发送对应个数的pwm
*******************************/
void PWMStart(u8 idx, u8 fr, u32 cstep)
{
	switch(idx)
	{
		case 0:
			LV8731VEnable1();				//电机使能
			
			if(fr)							//方向
				LV8731VFrReversal1();
			else
				LV8731VFrForeward1();
			
			if(cstep == 0)
			{
				LV8731VPara[LV0].callback_mode = 0;
				HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, Data[LV0], ONCE_PWM_CNT);
			}
			else
			{
				if(cstep < 100)
				{
					LV8731VPara[LV0].callback_mode = 1;
					HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, Data[LV0], cstep);
				}
				else
				{
					LV8731VPara[LV0].callback_mode = 2;
					LV8731VPara[LV0].pwm_dma_cnt = cstep / 100;
					LV8731VPara[LV0].pwmcnt_residue = cstep % 100;
					HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, Data[LV0], ONCE_PWM_CNT);
				}
			}
			
			break;
		case 1:
			LV8731VEnable2();
			
			if(fr)
				LV8731VFrReversal2();
			else
				LV8731VFrForeward2();
			
			if(cstep == 0)
			{
				LV8731VPara[LV1].callback_mode = 0;
				HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, Data[LV1], ONCE_PWM_CNT);
			}
			else
			{
				if(cstep <= 100)
				{
					LV8731VPara[LV1].callback_mode = 1;
					HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, Data[LV1], cstep);
				}
				else
				{
					LV8731VPara[LV1].callback_mode = 2;
					LV8731VPara[LV1].pwm_dma_cnt = cstep / 100;
					LV8731VPara[LV1].pwmcnt_residue = cstep % 100;
					HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, Data[LV1], ONCE_PWM_CNT);
				}
			}
			
			break;
		default:
			break;
	}

}

/*******************************
停止发送pwm,DMA模式
0:升降电机	1:晶向电机
*******************************/
void PWMStop(u8 idx)
{    
	switch(idx)
	{
		case 0:		
			HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
			LV8731VDisable1();	//失能
			break;
		case 1:		
			HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_1);
			LV8731VDisable2();
			break;
		default:
			break;
	}
}


/*******************************
设置pwm的频率
0升降电机 1晶向电机
*******************************/
void SetPWMFre(u8 idx, u16 cnt)
{    
	u16 i;

	if(idx!=0 && idx!=1)
		return;
	
	//__HAL_TIM_SET_PRESCALER(&htim3, prescaler);	//配置PSC预分频值

	if(idx == 0)
		__HAL_TIM_SET_AUTORELOAD(&htim3, cnt);		//配置PWM频率 ARR
	else
		__HAL_TIM_SET_AUTORELOAD(&htim2, cnt);
		
    for(i = 0; i < ONCE_PWM_CNT; i++)
    {
        Data[idx][i] = cnt/2;             			//占空比50%
    }
}

/*******************************
获取短路警告信号
idx:电机索引号 0升降电机 1晶向电机
返回1为警告
*******************************/
u8 GetLV8731VEmo(u8 idx)
{    
	u8 level;
	if(idx == 0)
		level = LV8731VReadEmo1();
	else
		level = LV8731VReadEmo2();

	if(level == 0)
		return 1;
	
	return 0;
}

/*******************************
pwm中断回调,DMA模式,全发送完才进中断
*******************************/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef * htim)
{
	u8 lv_idx;
	
    if(htim == &htim3)
		lv_idx = LV0;
	else if(htim == &htim2)
		lv_idx = LV1;
	
	if(LV8731VPara[lv_idx].callback_mode == 0)		//什么也不执行
	{

	}
	else if(LV8731VPara[lv_idx].callback_mode == 1)	//直接关闭pwm
	{
		if(lv_idx == LV0)
		{
			HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
			//LV8731VDisable1();//如果想要电机停止后任然保持使能状态就注释掉
		}
		else
		{
			HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_1);
			LV8731VDisable2();
		}
			
	}
	else if(LV8731VPara[lv_idx].callback_mode == 2)	//step个数大于100的情况
	{
		
		if(LV8731VPara[lv_idx].pwm_dma_cnt == 1)	//等于1时就要判断了
		{
			if(LV8731VPara[lv_idx].pwmcnt_residue == 0)
			{
				if(lv_idx == LV0)
				{
					HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
					LV8731VDisable1();
				}
				else
				{
					HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_1);
					LV8731VDisable2();
				}
			}
			else
			{				
				if(lv_idx == LV0)
				{
					HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
					HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, Data[lv_idx], LV8731VPara[lv_idx].pwmcnt_residue);//停止再打开不会有时间间隙
				}
				else
				{
					HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_1);
					HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, Data[lv_idx], LV8731VPara[lv_idx].pwmcnt_residue);//停止再打开不会有时间间隙
				}
				
				LV8731VPara[lv_idx].pwmcnt_residue = 0;
			}
		}
		else
		{
			LV8731VPara[lv_idx].pwm_dma_cnt--;
		}

	}

}

这里DMA选择一次发送100个是减小数组大小,如果发送大于一百的pwm个数则在回调函数里循环发送,回调函数是HAL库里给的函数,一次DMA传输完成便进一次。

AppLV8731V.H
#ifndef _APP_LV8731V_H_
#define _APP_LV8731V_H_
#include "DrvLV8731V.h"
#include "AppSystemConfig.h"

/****************操作***************************/
void AppLV8731VSetSpeed(u8 idx, u16 speed);
void AppLV8731VStart(u8 idx, u8 fr, u32 cstep);
void AppLV8731VCircleStart(u8 idx, u8 fr, u16 r_cnt);
void AppLV8731VPositionStart(u8 idx, u8 fr, u16 len_or_angle);
void AppLV8731VStop(u8 idx);
void AppLV8731VResetLocation(u8 idx);
void AppLV8731VAngleStart(u16 angle);

/****************初始化***************************/
void AppLV8731VInit(void);
/****************主循环接口***************************/
void AppLV8731VProcess(void);


#endif


AppLV8731V.C
#include "AppLV8731V.h"

/**************************************************
说明:

**************************************************/
static s32 location[LVNum];//电机位置

/***************************
设置速度,单位:r/s
***************************/
void AppLV8731VSetSpeed(u8 idx, u16 speed)
{
	float load_cnt;
	load_cnt = 100000 / (speed * SysCfg.Lv[idx].egear_in) - 1;
	SetPWMFre(idx,(u16)load_cnt);//设置初始速度
}

/***************************
按指定步数开始旋转
0:升降电机	1:晶向电机
0:正转(升,逆)	1:反转
0:一直旋转	非0:旋转指定个step
***************************/
void AppLV8731VStart(u8 idx, u8 fr, u32 cstep)
{
	s32 temp = 0;
	
	if(cstep != 0)
	{
		temp = location[idx];
		
		if(fr == 1)
			location[idx] += cstep;
		else
			location[idx] -= cstep;

		if(idx == 1)
		{
			if(location[idx] > 110592)//限位300度
			{
				location[idx] = location[idx] % 110592;
				
				PWMStart(idx, 0, (u32)(temp - location[idx]));//反转回去
				return;

			}

		}

	}
	PWMStart(idx, fr, cstep);
}

/***************************
按指定圈数开始旋转
0:升降电机	1:晶向电机
0:正转	1:反转
0:一直旋转	非0:旋转指定圈数
***************************/
void AppLV8731VCircleStart(u8 idx, u8 fr, u16 r_cnt)
{
	if(SysCfg.Lv[idx].egear_in == 0)
		return;
	
	AppLV8731VStart(idx, fr, (r_cnt * SysCfg.Lv[idx].egear_in));
}

/***************************
按距离开始运动
0:升降电机	1:晶向电机
0:升(逆)	1:降(顺)
0:一直运动	非0:升降距离(mm)	旋转角度(度)
***************************/
void AppLV8731VPositionStart(u8 idx, u8 fr, u16 len_or_angle)
{	
	if(SysCfg.Lv[idx].egear_out * SysCfg.Lv[idx].egear_in == 0)
		return;

	AppLV8731VStart(idx, fr, (len_or_angle * SysCfg.Lv[idx].egear_out * SysCfg.Lv[idx].egear_in));
}

/***************************
晶向电机旋转至指定角度
***************************/
void AppLV8731VAngleStart(u16 angle)
{
	s16 step = 0;
	u16 ch_angle = 0;
	u8 fr;
	
	if(SysCfg.Lv[LV1].egear_out * SysCfg.Lv[LV1].egear_in == 0)
		return;

	step = angle * SysCfg.Lv[LV1].egear_out * SysCfg.Lv[LV1].egear_in - location[LV1];
	fr = (step>=0) ? 1:0;
	step = abs(step);
	ch_angle = step / (SysCfg.Lv[LV1].egear_out * SysCfg.Lv[LV1].egear_in);
	
	AppLV8731VPositionStart(LV1, fr, ch_angle);
}

/***************************
停止
0:升降电机	1:晶向电机
***************************/
void AppLV8731VStop(u8 idx)
{
	PWMStop(idx);
}


/***************************
LV8731V初始化
***************************/
void AppLV8731VInit(void)
{
	LV8731V_16divide_1();
	LV8731V_16divide_2();
	LV8731V_50I_1();
	LV8731V_50I_2();
	AppLV8731VSetSpeed(LV0,SysCfg.Lv[LV0].speed);
	AppLV8731VSetSpeed(LV1,SysCfg.Lv[LV1].speed);
}


/***************************
LV8731V短路警告检测,主循环接口
***************************/
void AppLV8731VProcess(void)
{

	DevStatus.Lv[LV0].emo = GetLV8731VEmo(0);
	DevStatus.Lv[LV1].emo = GetLV8731VEmo(1);
}

/***************************
复位位置
0升降 1晶向
***************************/
void AppLV8731VResetLocation(u8 idx)
{
	location[idx] = 0;
}


这段代码有对电机2的限位及记位置操作,用不上的可以删去。已经应用层的一些数据操作,也可以删去,AppLV8731VProcess()函数放主循环里。

上机可以正常运行。

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值