ULN2003驱动28BYJ-48步进电机详解(附:51 32代码讲解)
ULN2003使用方法
ULN2003 是一款 16 引脚芯片,由 7 个达林顿对(每对受抑制二极管保护)组成,因此能够处理最多 7 个负载。每个达林顿对可以处理最大 500mA 的负载,而峰值为 600mA。
其应用电路如下,在其每个输出端需要上拉500欧电阻,增加其驱动能力,亲测去过不加上拉电阻的话会导致输出高电平达不到VCC;如果IO口的驱动能力过低,需要在其输入端增加10K上拉电阻,提高IO口的驱动能力,保证输出高电平的时候能够实现。(51系列除了P0口其他口需要上拉,32全部需要上拉)
在电源和地之间需要连接104电容(100000pf=0.1uf)对输入电源进行滤波。
注意:由其内部结构可知,其输出与输入是相反的,即:输入低电平信号,输出的是高电平,输入高电平信号输出的是低电平。
28YJ-48步进电机工作原理
首先介绍名称定义
28:步进电机的有效最大外径是28毫米
B:表示是步进电机
Y:表示是永磁式
J:表示是减速型(减速比1:64)
48:表示四相八拍(驱动方式比较重要)
什么是四相八拍?首先介绍定义
1、相数:是指产生不同对极N、S磁场的激磁线圈对数。如上图所示28YJ-48有四对线圈 A、B、C、D,所以其为四相。
2、拍数:完成一个磁场周期性变化所需脉冲数。
以四相电机为例,如下图所示,有两种四拍、一种八拍三种驱动方式
有此步进电机的名字可知,其为四相驱动方式为八拍。相对于另外两种驱动方式此驱动方式,步进电机运行更流畅。
其运行参数入上图所示,通过参数可知其空载牵入频率>=500;其空载牵出频率>=800。也就是说其启动时,每步之间的时间间隔至少为2ms,在启动后可以减少每部之间的时间。
步进角为5.625/64 :因为减速比为1/64.所以步进角需要除以64。也就是说实际实际一步转动角度为:0.087890625。实测在刚启动的时候时是小于这个值的,因为启动的时候阻力大会导致慢一些。到速度稳定后,会满足这个值。
驱动代码详解
51驱动代码
sbit IN1_A=P1^4; //引脚定义,根据实际情况修改
sbit IN1_B=P1^3;
sbit IN1_C=P1^2;
sbit IN1_D=P1^1;
/******
step:为拍数 0-7对应1-8拍
dir:方向 0为正方向 1为反方向
*******/
void step_28byj48_control(uchar step,uchar dir)//步进电机驱动函数
{
uchar temp=step;
if(dir==0) temp=7-step;
switch(temp) //4相8拍驱动方式
{
case 0: IN1_A=1;IN1_B=1;IN1_C=1;IN1_D=0;break;
case 1: IN1_A=1;IN1_B=1;IN1_C=0;IN1_D=0;break;
case 2: IN1_A=1;IN1_B=1;IN1_C=0;IN1_D=1;break;
case 3: IN1_A=1;IN1_B=0;IN1_C=0;IN1_D=1;break;
case 4: IN1_A=1;IN1_B=0;IN1_C=1;IN1_D=1;break;
case 5: IN1_A=0;IN1_B=0;IN1_C=1;IN1_D=1;break;
case 6: IN1_A=0;IN1_B=1;IN1_C=1;IN1_D=1;break;
case 7: IN1_A=0;IN1_B=1;IN1_C=1;IN1_D=0;break;
}
}
这里开启了1个1ms的定时器终端,来控制步进电机
void Timer0Init() //定时器0初始化
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。 定时模式
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X66;
ET0=1;//打开定时器0中断允许 GATE=0所以软件打开就可以了
TR0=1;//打开定时器
}
//定时器0中断服务函数
void Timer0() interrupt 1 //0 1 2 3 外0 定0 外1 定1
{
static uchar i;
i++;
if(i%2==0) //2ms
step_28byj48_control(i/2,0) ;
if(i==16) i=0;
}
在主函数中初始化定时器后就可以实现步进电机的运动了。
32代码
void MX_GPIO_Init(void) //引脚初始化、配置为推挽输出
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//输出状态宏定义
#define IN1_A(a) GPIOB->ODR=GPIOB->ODR & 0XFFFFFFFFE | (a<<0) //PB0
#define IN1_B(a) GPIOB->ODR=GPIOB->ODR & 0XFFFFFFFFD | (a<<1) //PB1
#define IN1_C(a) GPIOB->ODR=GPIOB->ODR & 0XFFFFFFFFB | (a<<2) //PB2
#define IN1_D(a) GPIOB->ODR=GPIOB->ODR & 0XFFFFFFFF7 | (a<<3) //PB3
void step_28byj48_control(uchar step,uchar dir)//步进电机驱动函数
{
uchar temp=step;
if(dir==0) temp=7-step;
switch(temp) //4相8拍驱动方式
{
case 0: IN1_A(1);IN1_B(1);IN1_C(1);IN1_D(0);break;
case 1: IN1_A(1);IN1_B(1);IN1_C(0);IN1_D(0);break;
case 2: IN1_A(1);IN1_B(1);IN1_C(0);IN1_D(1);break;
case 3: IN1_A(1);IN1_B(0);IN1_C(0);IN1_D(1);break;
case 4: IN1_A(1);IN1_B(0);IN1_C(1);IN1_D(1);break;
case 5: IN1_A(0);IN1_B(0);IN1_C(1);IN1_D(1);break;
case 6: IN1_A(0);IN1_B(1);IN1_C(1);IN1_D(1);break;
case 7: IN1_A(0);IN1_B(1);IN1_C(1);IN1_D(0);break;
}
}
最后开一个定时器调用此函数就可以了。