当前位置: 首页 > news >正文

stm32驱动ULN2003控制28BYJ48步进电机原理及代码(通俗易懂)

1.28BYJ48步进电机介绍

步进电机是一种将电脉冲信号转换为精确角度位移的数字执行元件。其核心特点是:脉冲个数决定旋转角度,脉冲频率决定旋转速度。通过控制定子绕组电流大小改变磁场大小吸引转子转动电机。

28BYJ48步进电机是四相(A,B,C,D)五线(四相加公共正极)式步进电机,减速比是1:64,电机转子本身的步进角是 5.625°,经过齿轮减速比后输出轴单步步距角: 5.625° / 64 = 约 0.0879°,故输出轴每转一圈所需步数: 360° / 0.0879° ≈ 4096 步/转,但这是理论值,实际可能会有一点偏差。

2.控制原理

常见的驱动序列是 8拍序列(半步驱动模式:A, AB, B, BC, C, CD, D, DA)或 4拍序列(全步驱动模式:A, B, C, D 或 AB, BC, CD, DA),反应在代码里其实就是逐个拉高各个io口的电平,如下图所示。

在上面我们已经知道输出轴每转一圈是4096 步/转(八拍驱动),但我们经常听说的四拍驱动是2048步/转又是怎么来的?给大家看个图就明白了,四拍时一步转过的角度是八拍的两倍,故转一圈用的步数也是八拍的一半,这俩个参数在后面转换脉冲转换角度时会用到。

【STM32控制ULN2003驱动板-驱动28BYJ48步进电机-哔哩哔哩】 ​编辑 网页链接想要了解步进电机具体原理的可以看看这个视频,我为了方便大家理解,只说一些代码里会用的参数,讲解的可能不是特别专业,大家见谅。

3.控制代码

 ULN2003驱动板接线如图所示,IN1-IN4接单片机四相IO口分别控制A,B,C,D四相,然后就是电机接口(直接对着插进去)和电源接口(一个正极一个负极)就不多说了。(注意1-4分别对应代码里的ABCD别接叉了,不然电机可能有些功能无法实现

代码的话就给大家看八拍驱动的了,如果八拍能看懂的话,四拍很容易复制粘贴修改一下就出来了,使用的是定时器产生脉冲,比其它给的延时代码慢慢调要精准很多,不用调节就能转动,注释也写的很详细了。

Stepper.c

#include "stm32f10x.h"                 
#include "Stepper.h"
#include "Delay.h"
static uint32_t Beats;
static uint8_t Dir;
static uint8_t StepNum = 0;
uint8_t Stepper_flage;/*** @brief  定时器初始化函数* @param  无* @retval 无*/
void Timer2_Init(void)
{NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			RCC_APB2PeriphClockCmd(Stepper_Servo_CLK, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	// 推挽输出GPIO_InitStruct.GPIO_Pin = Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_C | Stepper_Servo_D;//四相步进电机io口初始化GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(Stepper_Servo_GPIO, &GPIO_InitStruct);GPIO_ResetBits(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_C | Stepper_Servo_D);//io口初始拉低/*配置时钟源*/TIM_InternalClockConfig(TIM2);		/*时基单元初始化*/		//2ms,越快电机速度越快			TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	TIM_TimeBaseInitStructure.TIM_Period = 2000 - 1;				TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;				TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				/*中断输出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update);						TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				/*NVIC配置*/							NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			NVIC_Init(&NVIC_InitStructure);								}/*** @brief  电机停转函数* @param  无* @retval 无*/
void Sepper_Servo_Stop(void)
{GPIO_ResetBits(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_C | Stepper_Servo_D);
}/*** @brief  步进电机按整数角度旋转* @param  Sepper_Servo_Dir	旋转方向,Forward(正传)Reversal(反转)* @param  angle			    电机转轴旋转角度* @retval */void Stepper_Servo_Angle(Sepper_Servo_Dir direction , uint32_t angle)
{Dir = direction;TIM_Cmd(TIM2, DISABLE);//关定时器Beats = (angle * 4096)/360 ; //转的角度不准可微调4096,四拍驱动就换成2048TIM_Cmd(TIM2, ENABLE);//开定时器Stepper_flage = 0;
}/*** @brief  定时器2中断刷新节拍* @param  无* @retval 无*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){if(Beats != 0){if(Dir == Forward)//正转{if(StepNum == 9){StepNum = 1;}switch(StepNum){case 1:		// AGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;case 2:		// ABGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;			case 3:		// BGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;	case 4:		// BCGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_D, Bit_RESET);break;	case 5:		// CGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_D, Bit_RESET);break;case 6:		// CDGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C | Stepper_Servo_D, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B, Bit_RESET);break;		case 7:		// DGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_D, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_C, Bit_RESET);break;case 8:		// DAGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_D | Stepper_Servo_A, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C, Bit_RESET);break;		default: break;}StepNum++;}else if(Dir == Reversal)//反转{if(StepNum == 0){StepNum = 8;}switch(StepNum){case 1:		// AGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;case 2:		// ABGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;			case 3:		// BGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_C | Stepper_Servo_D, Bit_RESET);break;	case 4:		// BCGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_D, Bit_RESET);break;	case 5:		// CGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_D, Bit_RESET);break;case 6:		// CDGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_C | Stepper_Servo_D, Bit_SET);	GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B, Bit_RESET);break;		case 7:		// DGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_D, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_A | Stepper_Servo_B | Stepper_Servo_C, Bit_RESET);break;case 8:		// DAGPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_D | Stepper_Servo_A, Bit_SET);GPIO_WriteBit(Stepper_Servo_GPIO, Stepper_Servo_B | Stepper_Servo_C, Bit_RESET);break;		default: break;}StepNum--;				}	Beats--;}else{Sepper_Servo_Stop();TIM_Cmd(TIM2, DISABLE);//关定时器中断}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);	}
}

Stepper.h

#ifndef __STEPPER_SERVO_H
#define __STEPPER_SERVO_Htypedef enum
{Forward  = 0,Reversal   = 1
}Sepper_Servo_Dir;#define		Stepper_Servo_CLK			RCC_APB2Periph_GPIOB
#define		Stepper_Servo_GPIO	    	GPIOB
#define 	Stepper_Servo_A				GPIO_Pin_6
#define 	Stepper_Servo_B				GPIO_Pin_7
#define 	Stepper_Servo_C				GPIO_Pin_8
#define 	Stepper_Servo_D				GPIO_Pin_9void Timer2_Init(void);
void Sepper_Servo_Stop(void);
void Stepper_Servo_Angle(Sepper_Servo_Dir direction , uint32_t angle);
#endif

 main.c

uint8_t KeyNum;int main(void)
{delay_init();	    	 		//延时函数初始化	  Timer2_Init();                  //步进电机KEY_Init();	                    //按键初始化EXTIX_Init();					//外部中断初始化	while (1){	KeyNum = Key_GetNum();if(KeyNum == 1){Stepper_Servo_Angle(Forward , 90);	//正转90°		}else if(KeyNum == 2){Stepper_Servo_Angle(Reversal , 90); //反转90°}				}
}

如果还有不懂的,可以评论区交流,也可以一件三联后私信我获取完整源码! 

相关文章:

  • 10:00开始面试,10:06就出来了,问的问题有点变态。。。
  • 将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
  • 【HarmonyOS 5.0】开发实战:从UI到Native全解析
  • Ynoi数据结构题单练习1
  • 利用最小二乘法找圆心和半径
  • CTFSHOW pwn143 WP
  • React19源码系列之合成事件机制
  • 数据库学习笔记(十五)--变量与定义条件与处理程序
  • 核方法、核技巧、核函数、核矩阵
  • Java 语言特性(面试系列2)
  • 关于Android camera2预览变形的坑
  • [创业之路-415]:经济学 - 价值、使用价值、交换价值的全面解析
  • MS9292+MS9332 HD/DVI转VGA转换器+HD环出带音频
  • HarmonyOS开发:设备管理使用详解
  • GISBox如何导入Revit格式的BIM数据?
  • Kotlin基础语法二
  • AI驱动下的商品详情API:2025年电商平台的智能化数据交互新趋势
  • <component :is=““>
  • 【C++】回调函数,是什么,怎么用?
  • iview组件库:关于分页组件的使用与注意点
  • 葫芦岛建设工程信息网站/网站优化方法
  • 企业网站设计开发服务/南京网站设计公司大全
  • 做音乐分享的网站/aso优化师
  • .com免费网站怎么做/手机金融界网站
  • 河南建设工程信息网 就上平台中项网/seo基础篇
  • 兼职做一篇微信的网站/网站关键词优化代理