STM32实战总结:HAL之电机

news2025/1/11 18:49:04

电机基础知识参考:

51单片机外设篇:电机_路溪非溪的博客-CSDN博客

无刷电机和有刷电机

先详细了解有刷电机:

带你了解(有刷)电机工作原理_哔哩哔哩_bilibili

再详细了解无刷电机:

无刷直流电机工作原理_哔哩哔哩_bilibili

二者有何异同?

无刷电机和有刷电机都是一种直流电机。

有另外一种说法:很多人在知识上一直有这么个误区,以为无刷电机是直流电机,其实不然,无刷电机属于交流电机,是三相交流永磁电机的一种,输入模型无刷电机3根导线的电流是交流电,只不过这种交流电不是50HZ的市电正弦波,而是从无刷电机控制器(俗称无刷电调)调制出来的三相交变矩形波,频率比50HZ高很多,且随电机转速变化而变化。

输入的都是直流,只是无刷电机通过内部的控制器后,形成了一个交流电。了解即可,不必纠结。

有刷电机是所有电机中最基础的,不仅具有启动快速、制动及时、调速平稳、控制简单等优点,并且结构简单,价格便宜。比如我们小时候玩得四驱车里面就有一个小的装置(马达)这就是有刷电机。

但是电刷也是让有刷电机寿命短的主要原因。由于电刷持续的相互滑动和摩擦,电刷会不断磨损消耗,有刷电机必须经常进行维护更换电刷。

带刷的电机是磁极固定、线圈转动;而无刷马达则为线圈固定、磁极旋转。在无刷电机中,通过霍尔传感器,感知永磁体磁极的位置,然后根据这种感知,利用电子线路,在保证产生正确方向磁力的线圈中适时切换电流的方向来驱动电机。将有刷电机的不足消除。

没有电刷的摩擦,电机里的火花跟电机都没有;无刷电机没有摩擦力、转速快且省电;无刷电机在没有电刷摩擦的情况下,几乎不需要额外保养。
无刷电机比有刷电机在很多性能方面都要高一些,在价格方面也是。无论是控制电路还是电机本身,其成本和价格都比同级别的有刷电机高很多。

再谈步进电机

电机分为直流电机和交流电机,直流电机分为有刷直流电机和无刷直流电机。

那么,步进电机是什么呢?它是直流电机还是交流电机?

步进电机没有分交流与直流,如果是单极性控制方式,步进电机流过的电流是单方向,双极性控制时,步进电机流过电流是交流电。但控制步进电机的驱动器的供电电源分直流版和交流版,不同厂家的产品是有些差异,如EZM872是直流版,工作电压是18~80VDC;EZM872H是交流版,工作电压是18~80VAC。一般情况下,建议用直流版本,交流版本易出现电机急刹车时导致驱动器损坏。

先了解大概原理:

【动画演示】步进电机的原理,学了这么多年电工,终于搞明白了_哔哩哔哩_bilibili

步进电机相对于无刷电机来说,可以精准控制。

更多参考:

什么是步进电机?步进电机的特点,分类与原理!-电子发烧友网

单极性和双极性步进电机:

15.2-步进电机实验--步进电机极性区分_哔哩哔哩_bilibili

电机相数:

所谓“相数”,就是线圈组数(不要认为是定子数)。二、三、四、五相步进电机分别对应有2、3、4、5组线圈。这 N 个绕组要均匀地镶嵌在定子上,因此定子的磁极数必定是 N 的整数倍,因此,转子转一圈的步数应该是 N 的整数倍。步进电机外部的接线和定子相数没有必然的联系。是根据实际运用的需要来决定的。

看这个:

会不会认为是8相的?因为有8个定子;会不会认为是4相的?因为可能两个定子绕一组线圈;其实,相数和定子数并没有必然联系。

上面的是2相的,因为有2组线圈,引出来4根线。

所以该图是两项四线步进电机。

线圈有各种各样的绕法,也有不同的引线方式,所以,相数和线数等并不是固定的,需要针对特定的电机进行具体分析。无特定规律。不必纠结。

四大驱动方式:

步进电机4大驱动方式:单拍、双拍、半步、细分_哔哩哔哩_bilibili

伺服电机

简单来说,步进电机加上反馈电路,就构成了伺服电机。

对比直流电机、步进电机和伺服电机:

3种电机介绍(直交流、步进、伺服)_哔哩哔哩_bilibili

有刷直流电机的功能实现

选择有刷直流电机时通常需要考虑:

尺寸

扭力

驱动电压

驱动电流

等等

要求:实现有刷直流电机的启停、正反转和加减速。

驱动方式1:

只能打开和关闭,不能变速与换向,用继电器、BJT或MOS开关控制通断即可。

驱动方式2:

可以打开和关闭,可以变速但不能换向,此时用PWM波来控制电子开关即可。其实,改变驱动电压也是可以的,但是频繁改变驱动电压比较麻烦。通过改变PWM波地占空比可以灵活地调整电机速度,改变PWM占空比实际上就是改变其有效电流。

驱动方式3:

可以打开和关闭,可以变速,也可以换向,就需要用PWM控制桥路。通常使用集成IC,比如LV8548MC

注意:单片机本身的电压不足以驱动电机,所以通常会通过单片机的高低电平来控制某些开关的通断,以此来接通电路,实现更高电压的接入。

MX初始化

因为是使用PWM波,所以,按照之前的定时器来初始化即可。

这里使用TIM3的其中一个空闲通道即可。

具体参考:

STM32实战总结:HAL之PWM蜂鸣器_路溪非溪的博客-CSDN博客

关键代码实现

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

/* Private define-------------------------------------------------------------*/

/* Private variables----------------------------------------------------------*/

/* Private function prototypes------------------------------------------------*/      
static void Start(void);    //直流电机启动
static void Stop(void);	    //直流电机停止
static void Direction_Adjust(void);        //直流电机方向调整
static void Speed_Adjust(Speed_Change_t);  //直流电机速度调整
	
/* Public variables-----------------------------------------------------------*/

//定义结构体类变量
DC_Motor_t DC_Motor = 
{
  Stop_State,
	Forward_State, 
	Speed_50,
	
	Start,
	Stop,
	Direction_Adjust,
	Speed_Adjust
};

/*
	* @name   Start
	* @brief  直流电机启动
	* @param  None
	* @retval None      
*/
static void Start(void)
{
	//启动电机
	if(DC_Motor.Direction == Forward_State)
	{
		HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
	}
	else
	{
		HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);
	}
	
	//更新电机状态
	DC_Motor.Status = Start_State;
}

/*
	* @name   Stop
	* @brief  直流电机停止
	* @param  None
	* @retval None      
*/
static void Stop(void)
{
	//停止电机
	HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_3);
	HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_4);
	//更新电机状态
	DC_Motor.Status = Stop_State;
}

/*
	* @name   Direction_Adjust
	* @brief  直流电机方向调整
	* @param  None
	* @retval None      
*/
static void Direction_Adjust(void)
{
	if(DC_Motor.Status == Start_State)
	{
		if(DC_Motor.Direction == Reverse_State)
		{
			//停止转动电机
			HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_4);
			//延时100ms,待电机停止
			HAL_Delay(100);
			//正向转动电机
			HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
			//更新电机方向标识
			DC_Motor.Direction = Forward_State;
		}
		else
		{
			//停止转动电机
			HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_3);
			//延时100ms,待电机停止
			HAL_Delay(100);
			//反向转动电机
			HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);
			//更新电机方向标识
			DC_Motor.Direction = Reverse_State;
		}
	}
}

/*
	* @name   Speed_Adjust
	* @brief  直流电机速度调整
	* @param  Speed_Change -> 速度变化
	* @retval None      
*/
static void Speed_Adjust(Speed_Change_t Speed_Change)
{
	if(DC_Motor.Status == Start_State)
	{
		if(Speed_Change == Speed_up)
		{
			//增大电机速度
			switch(DC_Motor.Speed)
			{
				case Speed_50:	DC_Motor.Speed = Speed_60;  break;
				case Speed_60:	DC_Motor.Speed = Speed_70;  break;
				case Speed_70:	DC_Motor.Speed = Speed_80;  break;
				case Speed_80:	DC_Motor.Speed = Speed_90;  break;
				case Speed_90:	DC_Motor.Speed = Speed_100; break;
				case Speed_100:	DC_Motor.Speed = Speed_100; break;
				default: DC_Motor.Speed = Speed_50;         
			}
		}
		else
		{
			//减小电机速度
			switch(DC_Motor.Speed)
			{
				case Speed_50:	DC_Motor.Speed = Speed_50;  break;
				case Speed_60:	DC_Motor.Speed = Speed_50;  break;
				case Speed_70:	DC_Motor.Speed = Speed_60;  break;
				case Speed_80:	DC_Motor.Speed = Speed_70;  break;
				case Speed_90:	DC_Motor.Speed = Speed_80;  break;
				case Speed_100:	DC_Motor.Speed = Speed_90;  break;
				default: DC_Motor.Speed = Speed_90;         
			}
		}
		
		//更新PWM占空比
		TIM3->CCR3 = DC_Motor.Speed;
		TIM3->CCR4 = DC_Motor.Speed;
	}
}
/********************************************************
  End Of File
********************************************************/

单极性步进电机的功能实现

注意:

在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响。

具体驱动的拍数参考:

51单片机外设篇:电机_路溪非溪的博客-CSDN博客

步进电机的转速通常不会太快。有的最大为500HZ,即2ms走一步。

MX中初始化相关的GPIO即可。

另外,可初始化一个定时器,用来实现各节拍之间的延时。

关键代码:

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

/* Private define-------------------------------------------------------------*/

/* Private variables----------------------------------------------------------*/

/* Private function prototypes------------------------------------------------*/      
static void Direction_Adjust(void);        //步进电机方向调整
static void Speed_Adjust(Speed_Change_t);  //步进电机速度调整
static void Step_One_Pulse(void);          //步进电机步进一个脉冲

/* Public variables-----------------------------------------------------------*/

//定义结构体类变量
Unipolar_Step_Motor_t Unipolar_Step_Motor = 
{
  Stop_State,
	Forward_State, 
	Speed_6,
	0,
	Drive_Mode_8_Beats,
	0,
	(uint16_t)4096,
	
	Direction_Adjust,
	Speed_Adjust,
	Step_One_Pulse
};

/*
	* @name   Direction_Adjust
	* @brief  直流电机方向调整
	* @param  None
	* @retval None      
*/
static void Direction_Adjust(void)
{
	if(Unipolar_Step_Motor.Status == Start_State)
	{
		//调整电机运行方向
		if(Unipolar_Step_Motor.Direction == Reverse_State)
		{
			Unipolar_Step_Motor.Direction = Forward_State;
		}
		else
		{
			Unipolar_Step_Motor.Direction = Reverse_State;
		}
		
		Unipolar_Step_Motor.Circle = Circle_Set_Value;
		Unipolar_Step_Motor.Pulse_Cnt = 0;
		Display.Disp_HEX(Disp_NUM_6,Unipolar_Step_Motor.Circle,Disp_DP_OFF);
	}
}

/*
	* @name   Speed_Adjust
	* @brief  直流电机速度调整
	* @param  Speed_Change -> 速度变化
	* @retval None      
*/
static void Speed_Adjust(Speed_Change_t Speed_Change)
{
	uint8_t temp;
	
	if(Unipolar_Step_Motor.Status == Start_State)
	{
		if(Speed_Change == Speed_up)
		{
			//增大电机速度
			switch(Unipolar_Step_Motor.Speed)
			{
				case Speed_1: Unipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
				case Speed_2: Unipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
				case Speed_3: Unipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
				case Speed_4: Unipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
				case Speed_5: Unipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
				case Speed_6: Unipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
				case Speed_7: Unipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
				case Speed_8: Unipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
				case Speed_9: Unipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
				default:Unipolar_Step_Motor.Speed = Speed_6; temp = 6; 
			}
		}
		else
		{
			//减小电机速度
			switch(Unipolar_Step_Motor.Speed)
			{
				case Speed_1: Unipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
				case Speed_2: Unipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
				case Speed_3: Unipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
				case Speed_4: Unipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
				case Speed_5: Unipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
				case Speed_6: Unipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
				case Speed_7: Unipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
				case Speed_8: Unipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
				case Speed_9: Unipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
				default:Unipolar_Step_Motor.Speed = Speed_6; temp = 6; 
			}
		}
		
		//更新定时器7的计时重装载寄存器
		TIM7 ->ARR = Unipolar_Step_Motor.Speed;
		
		//更新数码管速度显示
		Display.Disp_HEX(Disp_NUM_1,temp,Disp_DP_OFF);
	}
}

/*
	* @name   Step_One_Pulse
	* @brief  步进电机步进一个脉冲
	* @param  Speed_Change -> 速度变化
	* @retval None      
*/
static void Step_One_Pulse(void)
{
	static uint8_t Position = 0;
	
	//单四拍
	if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_Single_4_Beats)
	{
		if(Unipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进  A - D - C - B
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 1: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 2: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 3: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				default: System.Error_Handler();
			}
		}
		else
		{
			//反向步进  A - B - C - D
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 1: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 2: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 3: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				default: System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 4)
				Position = 0;
	}
	
	//双四拍
	if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_Double_4_Beats)
	{
		if(Unipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进  DA - CD - BC - AB
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 1: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
				case 2: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 3: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				default: System.Error_Handler();
			}
		}
		else
		{
			//反向步进  DA - AB - BC - CD
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 1: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 2: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 3: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
				default: System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 4)
				Position = 0;
	}
	
	//单八拍
	if(Unipolar_Step_Motor.Drive_Mode == Drive_Mode_8_Beats)
	{
		if(Unipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进 A - DA - D - CD - C - BC - B - AB
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 1: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 2: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 3: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
				case 4: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 5: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 6: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 7: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				default:System.Error_Handler();
			}
		}
		else
		{
			//反向步进 A - AB - B - BC - C -CD - D - DA 
			switch(Position)
			{
				case 0: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 1: SET_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break; 
				case 2: CLR_Motor_A; SET_Motor_B; CLR_Motor_C; CLR_Motor_D; break;
				case 3: CLR_Motor_A; SET_Motor_B; SET_Motor_C; CLR_Motor_D; break;
				case 4: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; CLR_Motor_D; break; 
				case 5: CLR_Motor_A; CLR_Motor_B; SET_Motor_C; SET_Motor_D; break;
				case 6: CLR_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				case 7: SET_Motor_A; CLR_Motor_B; CLR_Motor_C; SET_Motor_D; break;
				default: System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 8)
				Position = 0;
	}
}
/********************************************************
  End Of File
********************************************************/

双极性步进电机的功能实现

双极性成本高(因为有两个电流方向,所以需要2个H桥共8个MOS管),但是结构简单。

驱动方式:

关键代码如下:

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

/* Private define-------------------------------------------------------------*/

/* Private variables----------------------------------------------------------*/

/* Private function prototypes------------------------------------------------*/      
static void Direction_Adjust(void);        //步进电机方向调整
static void Speed_Adjust(Speed_Change_t);  //步进电机速度调整
static void Step_One_Pulse(void);          //步进电机步进一个脉冲

/* Public variables-----------------------------------------------------------*/

//定义结构体类变量
Bipolar_Step_Motor_t Bipolar_Step_Motor = 
{
  Stop_State,
	Forward_State,
	Speed_6,
	0,
	//Drive_Mode_Single_4_Beats,
	Drive_Mode_Double_4_Beats,
	//Drive_Mode_8_Beats,
	0,
	(uint8_t)48,  //4拍,一圈转48次
	//(uint8_t)96,  //8拍,一圈转96次
	
	Direction_Adjust,
	Speed_Adjust,
	Step_One_Pulse
};

/*
	* @name   Direction_Adjust
	* @brief  直流电机方向调整
	* @param  None
	* @retval None      
*/
static void Direction_Adjust(void)
{
	if(Bipolar_Step_Motor.Status == Start_State)
	{
		//调整电机运行方向
		if(Bipolar_Step_Motor.Direction == Reverse_State)
		{
			Bipolar_Step_Motor.Direction = Forward_State;
		}
		else
		{
			Bipolar_Step_Motor.Direction = Reverse_State;
		}
		
		Bipolar_Step_Motor.Circle = Circle_Set_Value;
		Bipolar_Step_Motor.Pulse_Cnt = 0;
		Display.Disp_HEX(Disp_NUM_6,Bipolar_Step_Motor.Circle/10,Disp_DP_OFF);
		Display.Disp_HEX(Disp_NUM_5,Bipolar_Step_Motor.Circle%10,Disp_DP_OFF);
	}
}

/*
	* @name   Speed_Adjust
	* @brief  直流电机速度调整
	* @param  Speed_Change -> 速度变化
	* @retval None      
*/
static void Speed_Adjust(Speed_Change_t Speed_Change)
{
	uint8_t temp;
	
	if(Bipolar_Step_Motor.Status == Start_State)
	{
		if(Speed_Change == Speed_up)
		{
			//增大电机速度
			switch(Bipolar_Step_Motor.Speed)
			{
				case Speed_1: Bipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
				case Speed_2: Bipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
				case Speed_3: Bipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
				case Speed_4: Bipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
				case Speed_5: Bipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
				case Speed_6: Bipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
				case Speed_7: Bipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
				case Speed_8: Bipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
				case Speed_9: Bipolar_Step_Motor.Speed = Speed_9; temp = 9; break;
				default:Bipolar_Step_Motor.Speed = Speed_6; temp = 6; 
			}
		}
		else
		{
			//减小电机速度
			switch(Bipolar_Step_Motor.Speed)
			{
				case Speed_1: Bipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
				case Speed_2: Bipolar_Step_Motor.Speed = Speed_1; temp = 1; break;
				case Speed_3: Bipolar_Step_Motor.Speed = Speed_2; temp = 2; break;
				case Speed_4: Bipolar_Step_Motor.Speed = Speed_3; temp = 3; break;
				case Speed_5: Bipolar_Step_Motor.Speed = Speed_4; temp = 4; break;
				case Speed_6: Bipolar_Step_Motor.Speed = Speed_5; temp = 5; break;
				case Speed_7: Bipolar_Step_Motor.Speed = Speed_6; temp = 6; break;
				case Speed_8: Bipolar_Step_Motor.Speed = Speed_7; temp = 7; break;
				case Speed_9: Bipolar_Step_Motor.Speed = Speed_8; temp = 8; break;
				default:Bipolar_Step_Motor.Speed = Speed_6; temp = 6; 
			}
		}
		
		//更新定时器7的计时重装载寄存器
		TIM7 ->ARR = Bipolar_Step_Motor.Speed;
		
		//更新数码管速度显示
		Display.Disp_HEX(Disp_NUM_1,temp,Disp_DP_OFF);
	}
}

/*
	* @name   Step_One_Pulse
	* @brief  步进电机步进一个脉冲
	* @param  Speed_Change -> 速度变化
	* @retval None      
*/
static void Step_One_Pulse(void)
{
	static uint8_t Position = 0;
	
	//单四拍
	if(Bipolar_Step_Motor.Drive_Mode == Drive_Mode_Single_4_Beats)
	{
		if(Bipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进  A1 - B2 - A2 - B1
			switch(Position)
			{
				case 0: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 1: CLR_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				case 2: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 3: CLR_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				default: System.Error_Handler();
			}
		}
		else
		{
			//反向步进  A1 - B1 - A2 - B2
			switch(Position)
			{
				case 0: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 1: CLR_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 2: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 3: CLR_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				default: System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 4)
				Position = 0;
	}
	
	//双四拍
	if(Bipolar_Step_Motor.Drive_Mode == Drive_Mode_Double_4_Beats)
	{
		if(Bipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进  A1B2 - B2A2 - A2B1 - B1A1
			switch(Position)
			{
				case 0: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				case 1: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; SET_Motor_B2; break;
				case 2: CLR_Motor_A1; SET_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 3: SET_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				default: System.Error_Handler();
			}
		}
		else
		{
			//反向步进  A1B1 - B1A2 - A2B2 - B2A1
			switch(Position)
			{
				case 0: SET_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 1: CLR_Motor_A1; SET_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 2: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; SET_Motor_B2; break;
				case 3: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				default: System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 4)
				Position = 0;
	}
	
	//单八拍
	if(Bipolar_Step_Motor.Drive_Mode == Drive_Mode_8_Beats)
	{
		if(Bipolar_Step_Motor.Direction == Forward_State)
		{
			//正向步进  A1 - A1B2 - B2 - B2A2 - A2 - A2B1 - B1 - B1A1
			switch(Position)
			{
				case 0: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 1: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				case 2: CLR_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				case 3: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; SET_Motor_B2; break;
				case 4: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 5: CLR_Motor_A1; SET_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 6: CLR_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 7: SET_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				default:System.Error_Handler();
			}
		}
		else
		{
			//反向步进 A1 - A1B1 - B1 - B1A2 - A2 - A2B2 - B2 - B2A1
			switch(Position)
			{
				case 0: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 1: SET_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 2: CLR_Motor_A1; SET_Motor_B1; CLR_Motor_A2; CLR_Motor_B2; break;
				case 3: CLR_Motor_A1; SET_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 4: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; CLR_Motor_B2; break;
				case 5: CLR_Motor_A1; CLR_Motor_B1; SET_Motor_A2; SET_Motor_B2; break;
				case 6: CLR_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				case 7: SET_Motor_A1; CLR_Motor_B1; CLR_Motor_A2; SET_Motor_B2; break;
				default:System.Error_Handler();
			}
		}
		
		//更新位置信息
		if((++Position) == 8)
				Position = 0;
	}
}
/********************************************************
  End Of File
********************************************************/

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/24959.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL在centos上的安装

去mysql官网下载mysql 通过mysql官网的download界面,找到community server,然后选择对应linux版本下载对应的安装包 这里直接上链接 https://downloads.mysql.com/archives/community/ 可以通过cat /etc/centos-release命令找到当前centos对应的版本 下…

[附源码]java毕业设计小区供暖收费管理系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

重磅上市《精通Neo4j》

重磅上市《精通Neo4j》重磅上市《精通Neo4j》一、写在前面的话二、主要内容三、更多介绍Here’s the table of contents:重磅上市《精通Neo4j》 《精通Neo4j》是继《Neo4j权威指南》之后第二本由中国人原创的图数据库领域专业书籍。由清华大学出版社于2022年11月出版&#xff0…

【菜菜的sklearn课堂笔记】逻辑回归与评分卡-步长的进一步理解和max_iter

视频作者:菜菜TsaiTsai 链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 既然参数迭代是靠梯度向量的大小d步长α梯度向量的大小d \times步长\alpha梯度向量的大小d步长α来实现的,而J(θ)J(\theta)J(θ)的降…

群推王|如何引爆您的推特流量

推特营销主要吸引力在于其庞大的用户群体。它是最大的社交媒体平台之一,据统计每月有3.3亿活跃用户,为品牌知名度和增长做出了重大贡献。 尽管我们都知道推特营销的重要性,但是在实际运用上大家可能会遇到一些问题,比如您有很多粉…

C/C++ 结构体变量初始化的几种方法总结及内存排列(字节对齐)

前言 最近看到一些别人的代码,对结构体的初始化使用了不同的语法,就决定对结构体的初始化方法做个探索,这里小小的记录一下。 注意,没有初始化的结构体变量是不会输出的,比如 struct SBase{int iNumberOne;int iNum…

Redis的分布式锁问题(八)基于Redis的分布式锁

Redis的分布式锁问题(八)基于Redis的分布式锁 分布式锁 什么是分布式锁? 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。 在…

springboot+vue3+ts实现一个点赞功能

前端&#xff1a;vitevue3tselementplusless 后端&#xff1a;springboot2.7.5mybatisplus 后端&#xff1a; 引入pom依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</…

通俗理解模拟退火算法,小白也看得懂!

模拟退火的实例 齐白石原是木匠&#xff0c;快30岁才正式学画。直到57岁以后画风开始转变&#xff0c;才真正有所成就。 鲁迅原本留日学医&#xff0c;25岁弃医从文&#xff0c;但37岁时才写出第一篇白话文小说《狂人日记》。 项羽在24岁巨鹿之战成名&#xff0c;26岁封王却走…

Advances in Graph Neural Networks笔记2:Fundamental Graph Neural Networks

诸神缄默不语-个人CSDN博文目录 本书网址&#xff1a;https://link.springer.com/book/10.1007/978-3-031-16174-2 本文是本书第二章的学习笔记。 我们学校没买这书&#xff0c;但是谷歌学术给我推文献时给出了一个能免登录直接上的地址&#xff0c;下次就不一定好使了&#…

Web of science,scopus,Google scholar的介绍和区别

Overview 最近为了和实验室同学分享这几个常见的数据库的区别&#xff0c;因此做了一个简单的 从这张图上面可以看到&#xff0c;Web of science (Wos)是在1997年&#xff0c;由Institute for Scientific Information (ISI)合并多种索引建立的&#xff0c;而ISI在1992年加入了…

11.21二叉树oj

目录 一.队列.栈顺序表总结 二.猫狗问题 三.股票价格跨度 四.二叉树的初始化 1.获取树中节点的个数 1.遍历思路 2.子问题思路 2.叶子节点个数 3.获取第K层节点的个数 4.获取二叉树的高度 6.判断一棵树是不是完全二叉树 一.队列.栈顺序表总结 1.顺序表和栈的底层都是…

C++ 单向链表手动实现(课后作业版)

单向链表&#xff0c;并实现增删查改等功能 首先定义节点类&#xff0c;类成员包含当前节点的值和下一个节点的地址 /node definition template <typename T> class Node { public:T value;Node<T>* next;Node() {}Node(const T& value) {this->value va…

ES6 入门教程 19 Generator 函数的语法 19.7 yield星号表达式

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程19 Generator 函数的语法19.7 yield* 表达式19 Generator 函数的语法 19.7 yield* 表达式 如果在 Generator 函数内部&…

windows域控批量创建账号方法

目录 一、收集信息 二、编写脚本 &#xff08;一&#xff09;新建aduser.ps1的powershell脚本 &#xff08;二&#xff09;New-Aduser命令详解 三、生产环境报错 &#xff08;一&#xff09;ConvertTo-SecureString &#xff08;二&#xff09;指定的账号已存在 &#xff…

debian11 安装后必备配置

debian11 安装后必备配置 运行环境&#xff1a;PVE v7.2-11 CT容器 系统版本&#xff1a;Debian-11-standard_11.3-1_amd64.tar.zst 启动信息 Debian GNU/Linux 11 debian tty1debian login: root Password: Linux debian 5.15.64-1-pve #1 SMP PVE 5.15.64-1 (Thu, 13 Oct …

【数据结构】堆的实现堆排序Top-K

文章目录一、堆的概念及结构二、堆实现&#xff08;1&#xff09;创建结构体&#xff08;2&#xff09;具体函数实现及解析1.0 交换函数1.1 堆的打印1.2 堆的初始化1.3 堆的销毁1.4 堆的插入1.5堆的向上调整算法1.6 堆的删除1.7堆的向下调整算法1.8 取堆顶的数据1.9 堆的数据个…

【力扣练习】找一个字符串中不含有重复字符的最长字串的长度

class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # 哈希集合&#xff0c;记录每个字符是否出现过 occ set() n len(s) # 右指针&#xff0c;初始值为 -1&#xff0c;相当于我们在字符串的左边界的左侧&#xff…

【项目实战】Spring Boot项目抵御XSS攻击

本专栏将为大家总结项目实战相关的知识&#xff01; 点击即可关注本专栏&#xff0c;获取更多知识&#xff01; 文章目录前言一、什么是XSS攻击二、如何抵御XSS攻击三、实现抵御XSS攻击结语前言 作为Web网站来说&#xff0c;抵御XSS攻击是必须要做的事情&#xff0c;这是非常常…

C++基础知识

目录 C的基本使用 C数据的输入与输出 C使用命令行 具体案例 C生成随机数 关键字 标识符命名规则 数据类型 整形 实型&#xff08;浮点型&#xff09; 浮点型变量分为2种 表示小数的两种方式 案例演示 字符型 案例演示 字符串类型 两种风格 两种风格字符串之间…