STM32物联网项目——单极性步进电机

程序功能

单极性步进电机 

极性

  单极性:电流只有一个方向。用ULN2003A驱动(内含反相器),比较简单。

  双极性:电流有两个方向,桥路驱动。

步进电机原理

 步进电机驱动方法

  步进电机不能直接使用电流源来工作,必须使用专用的步进电机驱动器,它由脉冲发生控制单元,功率驱动单元,保护单元等组成。

28BYJ-48步进电机

28:步进电机的有效最大外径是28毫米
B:表示是步进电机
Y:表示是永磁式
J:表示是减速型(减速比1:64)
48:表示四相八拍

此电机部分参数如图

 根据百度搜索和b站视频理解,我认为步进角度就是电机一个脉冲转动的角度,结合下面所讲的驱动方式和后续代码,可以理解为步进电机转动一个脉冲,即1拍,也就转动了一个步进角。减速比我没有理解清楚,根据查询的资料,我感觉应该是,电机内部的某个转动部位转动了64圈后,外部的转轴才转动一圈。

驱动方式

单四拍和双四拍转一周需要2048个脉冲,八拍需要4096个脉冲。

 转动位置和通电情况如图(图为自画,比较粗糙)

接线方式 

 红5接5V电源,其他四个色接驱动的输出端,单片机输出接驱动输入。

皆从红5流入,从各自相中流出

步进电机原理图

ULN2003A驱动

 左边为输入,右边为输出,当输入1时,输出0;输入0时,输出1.中间是达林顿管,可以放大微小信号

代码部分

cubemx初始化

 

各GPIO口配置好相应的标签,利于代码编写。 

使用定时器中断每隔5ms控制输出脉冲。 

Unipolar_Step_Motor.h

步进电机结构体类型

 宏定义4个相的置高置低电平函数

#define	SET_Motor_A	HAL_GPIO_WritePin(Step_Motor_A_GPIO_Port,Step_Motor_A_Pin,GPIO_PIN_SET);
#define	CLR_Motor_A	HAL_GPIO_WritePin(Step_Motor_A_GPIO_Port,Step_Motor_A_Pin,GPIO_PIN_RESET);

#define	SET_Motor_B	HAL_GPIO_WritePin(Step_Motor_B_GPIO_Port,Step_Motor_B_Pin,GPIO_PIN_SET);
#define	CLR_Motor_B	HAL_GPIO_WritePin(Step_Motor_B_GPIO_Port,Step_Motor_B_Pin,GPIO_PIN_RESET);

#define	SET_Motor_C	HAL_GPIO_WritePin(Step_Motor_C_GPIO_Port,Step_Motor_C_Pin,GPIO_PIN_SET);
#define	CLR_Motor_C	HAL_GPIO_WritePin(Step_Motor_C_GPIO_Port,Step_Motor_C_Pin,GPIO_PIN_RESET);

#define	SET_Motor_D	HAL_GPIO_WritePin(Step_Motor_D_GPIO_Port,Step_Motor_D_Pin,GPIO_PIN_SET);
#define	CLR_Motor_D	HAL_GPIO_WritePin(Step_Motor_D_GPIO_Port,Step_Motor_D_Pin,GPIO_PIN_RESET);

Unipolar_Step_Motor.c

控制电机正反转

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);
	}
}

控制电机转动速度

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; 
			}
		}
		
		//重置ARR,改变频率
		TIM7 ->ARR = Unipolar_Step_Motor.Speed;
		
		//显示速度
		Display.Disp_HEX(Disp_NUM_1,temp,Disp_DP_OFF);
	}
}

步进一个脉冲

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)
		{
			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
		{
			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)
		{
			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
		{
			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;
	}
}

定时器中断函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
	if(htim->Instance == htim7.Instance)
	{
		//判断圈数
		if(Unipolar_Step_Motor.Circle > 0)
		{
			//电机转动一个脉冲
			Unipolar_Step_Motor.Step_One_Pulse();
			
			//判断电机脉冲计数是否转动了一圈
			if(++Unipolar_Step_Motor.Pulse_Cnt == Unipolar_Step_Motor.One_Circle_Pulse)
			{
				Unipolar_Step_Motor.Pulse_Cnt = 0;
				//圈数减1
				Unipolar_Step_Motor.Circle--;
				Display.Disp_HEX(Disp_NUM_6,Unipolar_Step_Motor.Circle,Disp_DP_OFF);
			}
		}
		//关闭电机
		else
		{
			Unipolar_Step_Motor.Status = Stop_State;
			CLR_Motor_A;
			CLR_Motor_B;
			CLR_Motor_C;
			CLR_Motor_D;
			LED.LED_OFF(LED3);
		}
	}
}

通过4个Key实现功能的外部中断函数可参考此前文章STM32物联网——DC直流电机

其他类型步进电机也可在此章编写代码之上略加改变实现功能。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西红柿鸡蛋超级美味

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值