艾思控AQMD6008BLS-TE无刷电机驱动使用笔记(配合STM32)

一、介绍

艾思控AQMD6008BLS-TE无刷电机驱动使用笔记(配合STM32)_第1张图片

本驱动器使用的电机电流精确检测技术、有感无刷电机自测速、有感无刷电机转动位置检测、再生电流恒电流制动(或称刹车)技术和强大的PID调节技术可地控制电机平稳正反转、换向及制动,输出电流实时调控防止过流,精准控制电机转速和转动位置,电机响应时间短且反冲力小。

二、使用方法

艾思控AQMD6008BLS-TE无刷电机驱动使用笔记(配合STM32)_第2张图片

该款无刷电机驱动有多种使用方法,就stm32而言,可以通过输出PWM信号对电机进行调速,也可通过485通讯或CAN通讯与电机驱动进行通讯(电机驱动内部应该也是另外一块32)。项目使用过程中,经导师建议,优先采用485通讯方式。在使用此种通讯方式时,注意设备地址和通讯参数(波特率、奇偶校验等)的设置。

在通过速度控制寄存器进行速度控制时,可以通过0x0042寄存器设定占空比,也可通过0x0043寄存器设定换向频率。另外,在正确配置电机极个数和减速比之后,可以通过0x0034寄存器读取电机的转速。

三、代码

在编写代码的过程中,有参考硬件家园刘工的工程代码,在此表示感谢。

Motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__

#include "MyApplication.h"

//定义枚举类型
typedef enum
{
	M1 = (uint8_t)0x01,
	M2 = (uint8_t)0x02,
}Motor_Num_t;

//定义结构体类型
typedef struct
{
	uint8_t M1_Addr;
	uint8_t M2_Addr;
	FlagStatus_t Motor_Move_State;
	uint16_t M1_Read_Value;
	uint16_t M2_Read_Value;
	void (*Motor_Set_PWM)(uint8_t, float, UART_t*); 
	void (*Motor_Read_Value)(uint8_t, UART_t*);
	void (*Protocol_Read_Speed)(uint8_t, UART_t*);
	void (*Motor_PWM_Acc_Buffer)(uint8_t, float, UART_t*);
	void (*Motor_PWM_Rv_Buffer)(uint8_t, float, UART_t*);
	void (*Motor_Brake)(uint8_t, UART_t*);
} Motor_t;



/* extern variables-----------------------------------------------------------*/
extern Motor_t  Motor;
/* extern function prototypes-------------------------------------------------*/

#endif
/********************************************************
  End Of File
********************************************************/

Motor.c

/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"

/* Private define-------------------------------------------------------------*/
#define FunctionCode_Read_Motor 		(uint8_t)0x03
#define FunctionCode_Write_Motor 	(uint8_t)0x06
#define UART3_Read_Speed_LENGTH		(uint8_t)7

/* Private variables----------------------------------------------------------*/
static void Motor_Set_PWM(uint8_t, float, UART_t*); 
static void Motor_Read_Value(uint8_t, UART_t*);
static void Protocol_Read_Speed(uint8_t, UART_t*);
static void Motor_PWM_Acc_Buffer(uint8_t, float, UART_t*);
static void Motor_PWM_Rv_Buffer(uint8_t, float, UART_t*);
static void Motor_Brake(uint8_t, UART_t*); 

/* Public variables-----------------------------------------------------------*/
Motor_t Motor = 
{
	0x01, 
	0x02,
	FALSE,
	0,
	0,
	Motor_Set_PWM,
	Motor_Read_Value,
	Protocol_Read_Speed,
	Motor_PWM_Acc_Buffer,
	Motor_PWM_Rv_Buffer,
	Motor_Brake
};

/* Private function prototypes------------------------------------------------*/      

/*
	* @name   Motor_Set_PWM
	* @brief  设置驱动PWM占空比
	* @param  Motor_Num -> 编号, pwm -> 占空比, UART -> 串口
	* @retval None      
*/
static void Motor_Set_PWM(uint8_t Motor_Num, float pwm, UART_t* UART)
{
	UART_t* const COM = UART;
	uint16_t SpeedTemp = (uint16_t)(pwm * 10);
	
	//条件选择语句
	switch(Motor_Num)
	{	
		case M1: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M1_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x42;

			*(COM->pucSend_Buffer + 4) = (uint8_t)(SpeedTemp >> 8);
			*(COM->pucSend_Buffer + 5) = (uint8_t)SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		case M2:
		{
			*(COM->pucSend_Buffer + 0) = Motor.M2_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x42;

			*(COM->pucSend_Buffer + 4) = (uint8_t)(SpeedTemp >> 8);
			*(COM->pucSend_Buffer + 5) = (uint8_t)SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		default: System.Assert_Failed();
	}
	HAL_Delay(30);
}

/*
	* @name   Motor_Read_Speed
	* @brief  通过驱动读取转速
	* @param  UART -> 串口
	* @retval None      
*/
static void Motor_Read_Value(uint8_t Motor_Num, UART_t* UART)
{
	UART_t* const  COM = UART;
	
	//条件选择语句
	switch(Motor_Num)
	{
		case M1: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M1_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Read_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x34;
			
			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = 0x01;
			
			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			Modbus.Sensor_To_Read_Flag = 1;
			UART3.SendArray(COM->pucSend_Buffer, 8);
			break;			
		}
		
		case M2: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M2_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Read_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x34;
			
			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = 0x01;
			
			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			Modbus.Sensor_To_Read_Flag = 2;
			UART3.SendArray(COM->pucSend_Buffer, 8);
			break;			
		}	
		default: System.Assert_Failed();
	}
	
	HAL_Delay(30);
}

/*
	* @name   Protocol_Read_Speed
	* @brief  分析串口值
	* @param  UART_t* -> 串口
	* @retval None      
*/
static void Protocol_Read_Speed(uint8_t Motor_Num, UART_t* UART)
{
	UART_t* const  COM = UART;
	uint8_t i = 0, Index = 0;

	//串口3停止DMA接收
	HAL_UART_DMAStop(&huart3);

	switch(Motor_Num)
	{
		case M1:
		{
			//过滤干扰数据,首字节为modbus地址,共8字节
			for(i = 0; i < UART3_Rec_LENGTH; i++)
			{
				//检测键值起始数据Modbus.Addr
				if(Index == 0)
				{
					if(*(COM->pucRec_Buffer+i) != Motor.M1_Addr)
						continue;
				}
				
				*(COM->pucRec_Buffer + Index) = *(COM->pucRec_Buffer + i);

				//已读取7个字节
				if(Index == UART3_Read_Speed_LENGTH - 1)
					break;
				
				Index++;
			}
			
			//计算CRC-16
			CRC_16.CRC_Value   = CRC_16.CRC_Check(COM->pucRec_Buffer, 5); //计算CRC值
			CRC_16.CRC_H       = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L       = (uint8_t)CRC_16.CRC_Value;	

			//校验CRC-16
			if(((*(COM->pucRec_Buffer + 5) == CRC_16.CRC_L) && (*(COM->pucRec_Buffer + 6) == CRC_16.CRC_H))
																										||
				 ((*(COM->pucRec_Buffer + 5) == CRC_16.CRC_H) && (*(COM->pucRec_Buffer + 6) == CRC_16.CRC_L)))
			{
				//校验地址
				
				if(((*(COM->pucRec_Buffer + 0)) == Motor.M1_Addr) && ((*(COM->pucRec_Buffer + 1)) == FunctionCode_Read_Motor) && ((*(COM->pucRec_Buffer + 2)) == 0x02))
				{
					
					Motor.M1_Read_Value = ((*(COM->pucRec_Buffer + 3)) << 8) | ((*(COM->pucRec_Buffer + 4)));
				}
			}	
			break;
		}
		case M2:
		{
			//过滤干扰数据,首字节为modbus地址,共8字节
			for(i = 0; i < UART3_Rec_LENGTH; i++)
			{
				//检测键值起始数据Modbus.Addr
				if(Index == 0)
				{
					if(*(COM->pucRec_Buffer+i) != Motor.M2_Addr)
						continue;
				}
				
				*(COM->pucRec_Buffer + Index) = *(COM->pucRec_Buffer + i);

				//已读取7个字节
				if(Index == UART3_Read_Speed_LENGTH - 1)
					break;
				
				Index++;
			}
			
			//计算CRC-16
			CRC_16.CRC_Value   = CRC_16.CRC_Check(COM->pucRec_Buffer, 5); //计算CRC值
			CRC_16.CRC_H       = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L       = (uint8_t)CRC_16.CRC_Value;	

			//校验CRC-16
			if(((*(COM->pucRec_Buffer + 5) == CRC_16.CRC_L) && (*(COM->pucRec_Buffer + 6) == CRC_16.CRC_H))
																										||
				 ((*(COM->pucRec_Buffer + 5) == CRC_16.CRC_H) && (*(COM->pucRec_Buffer + 6) == CRC_16.CRC_L)))
			{
				//校验地址
				if(((*(COM->pucRec_Buffer + 0)) == Motor.M2_Addr) && ((*(COM->pucRec_Buffer + 1)) == FunctionCode_Read_Motor) && ((*(COM->pucRec_Buffer + 2)) == 0x02))
				{
					Motor.M2_Read_Value = ((*(COM->pucRec_Buffer + 3)) << 8) | ((*(COM->pucRec_Buffer + 4)));
				}
			}				
			break;
		}
		default: break;
	}
	
	//清缓存
	for(i = 0; i < UART3_Rec_LENGTH; i++)
	{
		*(COM->pucRec_Buffer + i) = 0x00;
	}

}

/*
	* @name   Motor_PWM_Acc_Buffer
	* @brief  电机PWM加速缓冲
	* @param  Motor_Num -> 编号, time -> 时间, UART -> 串口
	* @retval None      
*/
static void Motor_PWM_Acc_Buffer(uint8_t Motor_Num, float time, UART_t* UART)
{
	UART_t* const  COM = UART;
	uint8_t SpeedTemp = (uint8_t)(time * 10);
	

	//条件选择语句
	switch(Motor_Num)
	{	
		case M1: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M1_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x60;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		case M2:
		{
			*(COM->pucSend_Buffer + 0) = Motor.M2_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x60;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		default: System.Assert_Failed();
	}
	HAL_Delay(30);	
}

/*
	* @name   Motor_PWM_Rv_Buffer
	* @brief  电机PWM减速缓冲
	* @param  Motor_Num -> 编号, time -> 时间, UART -> 串口
	* @retval None      
*/
static void Motor_PWM_Rv_Buffer(uint8_t Motor_Num, float time, UART_t* UART)
{
	UART_t* const  COM = UART;
	uint8_t SpeedTemp = (uint8_t)(time * 10);
	

	//条件选择语句
	switch(Motor_Num)
	{	
		case M1: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M1_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x51;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		case M2:
		{
			*(COM->pucSend_Buffer + 0) = Motor.M2_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x51;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = SpeedTemp;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		default: System.Assert_Failed();
	}
	HAL_Delay(30);	
}

/*
	* @name   Motor_Brake
	* @brief  电机刹车
	* @param  Motor_Num -> 编号, UART -> 串口
	* @retval None      
*/
static void Motor_Brake(uint8_t Motor_Num, UART_t* UART)
{
	UART_t* const  COM = UART;

	//条件选择语句
	switch(Motor_Num)
	{	
		case M1: 
		{
			*(COM->pucSend_Buffer + 0) = Motor.M1_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x40;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = 0x01;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		case M2:
		{
			*(COM->pucSend_Buffer + 0) = Motor.M2_Addr;
			*(COM->pucSend_Buffer + 1) = FunctionCode_Write_Motor;
			
			*(COM->pucSend_Buffer + 2) = 0x00;
			*(COM->pucSend_Buffer + 3) = 0x40;

			*(COM->pucSend_Buffer + 4) = 0x00;
			*(COM->pucSend_Buffer + 5) = 0x01;

			CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer, 6);
			CRC_16.CRC_H     = (uint8_t)(CRC_16.CRC_Value >> 8);
			CRC_16.CRC_L     = (uint8_t)CRC_16.CRC_Value;

			*(COM->pucSend_Buffer + 6) = CRC_16.CRC_H;
			*(COM->pucSend_Buffer + 7) = CRC_16.CRC_L;

			UART3.SendArray(COM->pucSend_Buffer, 8);
			
			break;
		}
		default: System.Assert_Failed();
	}
	HAL_Delay(30);	
}



/********************************************************
  End Of File
********************************************************/

你可能感兴趣的:(笔记,stm32,嵌入式硬件)