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°} }
}
如果还有不懂的,可以评论区交流,也可以一件三联后私信我获取完整源码!