28BYJ-48步进电机驱动程序

28BYJ-48步进电机驱动程序

这两天开始学调 28BYJ-48步进电机,但是淘宝卖家给的资料和网上搜到的都是51的程序,用的驱动板都是ULN2003。

以下是我自己写的STM32的程序。我用的板子是F103ZET6,驱动板是L298N。

电机驱动原理简述:电机内有四组线圈,每给一个电机供电,转子就会转动一个角度,按顺序轮流循环转动给四个线圈供电,就能让转子一直转起来。跟详细的说明网上有很多,这里就不重复了。

接线:红线接5V电源,其余四根按顺序接驱动板上,其余四根的颜色是橙黄蓝粉,不同厂家做的顺序可能不一样,但都是按顺序排的,比如我的顺序就是橙黄蓝粉,或者说粉蓝黄橙也对,反正就是按这个颜色的先后顺序接就对了。

时序说明:电机内部四个线圈的一端都接到5V上,所以我们需要先给线圈的另一端供5V的电,然后按一定的顺序拉低电压,使线圈通电,电机就能动了。我们是通过驱动板控制的,也就是说,IO口默认输出高电平,然后按时序给低电平。

                                                       ↓↓↓四相八拍时序图↓↓↓

在这里插入图片描述

                                                      ↓↓↓四相单四拍时序图↓↓↓

在这里插入图片描述

                                                     ↓↓↓四相双四拍时序图↓↓↓↓

在这里插入图片描述
以下是源码:

首先是IO口的初始化,这里我设PD1为1号,PD4为2号,PD6为3号,PG9为4号。

#include "motor.h"
#include "sys.h"
#include "delay.h"
void my_motor_init(void)
{
	GPIO_InitTypeDef GPIO_Init_config_d1;
	GPIO_InitTypeDef GPIO_Init_config_d4;	
	GPIO_InitTypeDef GPIO_Init_config_d6;	
	GPIO_InitTypeDef GPIO_Init_config_g9;	

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOG,ENABLE);

	GPIO_Init_config_d1.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init_config_d1.GPIO_Pin=GPIO_Pin_1;
	GPIO_Init_config_d1.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOD,&GPIO_Init_config_d1);

	GPIO_Init_config_d4.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init_config_d4.GPIO_Pin=GPIO_Pin_4;
	GPIO_Init_config_d4.GPIO_Speed=GPIO_Speed_50MHz;

	GPIO_Init_config_d6.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init_config_d6.GPIO_Pin=GPIO_Pin_6;
	GPIO_Init_config_d6.GPIO_Speed=GPIO_Speed_50MHz;	
	GPIO_Init(GPIOD,&GPIO_Init_config_d6);

	GPIO_Init_config_g9.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init_config_g9.GPIO_Pin=GPIO_Pin_9;
	GPIO_Init_config_g9.GPIO_Speed=GPIO_Speed_50MHz;		
	GPIO_Init(GPIOG,&GPIO_Init_config_g9);	

	PD1=1;
	PD4=1;
	PD6=1;
	PG9=1;
}

然后是头文件
这里用了正点原子的 sys.h头文件进行了一些宏定义
里面声明了四个函数,第一个是上面的初始化,后面三个是三种不同的驱动写法

#include "sys.h"

#define PD1 PDout(1)
#define PD4 PDout(4)
#define PD6 PDout(6)
#define PG9 PGout(9)

#define IN1 PDout(1)
#define IN2 PDout(4)
#define IN3 PDout(6)
#define IN4 PGout(9)

#ifndef my_motor_H
#define my_motor_H

void my_motor_init(void);
void my_motor_working_0(int time_us);//low B写法
void my_motor_working_1(u16 arr[],int M_us);
void my_motor_working_2(u16 arr[],int M_us);

#endif

第一种
这是最直观的控制方法,直接一步一种情况的控制,每一步中间要有一个延迟,控制我们输出的低电平宽度,这里我用微秒us控制。据电机说明书,脉冲频率不能太高,我这里试了下,似乎至少要大于一点多个毫米ms,就是1000多微妙us,因此我在主函数里设脉冲频率为1100us。这段是四相八拍的程序,这样写的话不够灵活,换成其他方式就很麻烦。

void my_motor_working_0(int time_us)//low B写法
{
	delay_init();
	PD1=0;
	PD4=1;
	PD6=1;
	PG9=1;
	delay_us(time_us);//1

	PD1=0;
	PD4=0;
	PD6=1;
	PG9=1;
	delay_us(time_us);//2

	PD1=1;
	PD4=0;
	PD6=1;
	PG9=1;
	delay_us(time_us);//3

	PD1=1;
	PD4=0;
	PD6=0;
	PG9=1;
	delay_us(time_us);//4

	PD1=1;
	PD4=1;
	PD6=0;
	PG9=1;
	delay_us(time_us);//5

	PD1=1;
	PD4=1;
	PD6=0;
	PG9=0;
	delay_us(time_us);//6

	PD1=1;
	PD4=1;
	PD6=1;
	PG9=0;
	delay_us(time_us);//7

	PD1=0;
	PD4=1;
	PD6=1;
	PG9=0;
	delay_us(time_us);//8		
}

第二种
将每一步的io口状态都变成一个二进制数某一位,如上面的第一步,按PD1,PD4,PD6,PG9的顺序,就可以得到一个二进制数0111,第二步就是0011,不知道是不是MD5的原因还是什么原因,程序无法识别二进制前缀0b,所以我这里写成16进制,并按顺序写到一个数组中,那么我们就可以得到一个这样的数组(我在主函数里定义)

	time_48_0[]={0x7,0x3,0xb,0x9,0xd,0xc,0xe,0x6};

在这段函数里,for进行0~7的循环,四个if分别判断数组元素的一二三四位,符合条件就进行相应的操作。要注意的是,符合条件和不符合条件的操作都要有,保持四根信号线默认是高电平的状态,或者说for每次运算完,四个io口的结果都是要符合上面我给出的时序表。拿这段程序举例,如果我不写else,io口就是上一步的状态,显然这样是有问题的。

void my_motor_working_1(u16 arr[],int M_us)
{ 
	u8 i;
	u16 c=0;
	for(i=0;i<8;i++)
	{
		if(arr[i]&0x8) IN1=1; else IN1=0;
		if(arr[i]&0x4) IN2=1; else IN2=0;
		if(arr[i]&0x2) IN3=1; else IN3=0;
		if(arr[i]&0x1) IN4=1; else IN4=0;
		delay_us(M_us);
	}
}

第三种
用数组里的数进行位运算。要注意的是,通过宏定义对io状态进行控制的数值,似乎只能是0和1,如5、7、8之类的数输入,虽然也有电,电机也会转,但转起来很奇怪,这里我统一只用0和1控制。
这段函数拿IN2距离,与0x4(即0100)进行与运算,这样就得到了第二位的结果(位3,位2,位1,位0),不管是0还是1,都右移最低位(位0),这样得出的结果就是前面三位都是0 ,只有最低位的数是有效数据,然后赋给宏定义符。

void my_motor_working_2(u16 arr[],int M_us)
{ 
	u8 i;
	u16 c=0;
	for(i=0;i<8;i++)
	{
		IN1=(c=(arr[i]&0x8)>>3);
		IN2=(c=(arr[i]&0x4)>>2);
		IN3=(c=(arr[i]&0x2)>>1);
		IN4=(c=(arr[i]&0x1)>>0);
		
		delay_us(M_us);
	}
}

然后就没了。最后再贴出我主函数。

#include "sys.h"
#include "motor.h"
#include "delay.h"
int main(void)
{
	u16 time_48_0[]={0x7,0x3,0xb,0x9,0xd,0xc,0xe,0x6}; //四相八拍 顺转
	u16 time_48_1[]={0x6,0xe,0xc,0xd,0x9,0xb,0x3,0x7}; //四相八拍 逆转
	u16 time_414_0[]={0x7,0xb,0xd,0xe}; //四相单四拍 顺转
	u16 time_414_1[]={0xe,0xd,0xb,0x7}; //四相单四拍 逆转
	u16 time_424_0[]={0x6,0x3,0x9,0xc}; //四相双拍 顺转
	u16 time_424_1[]={0xc,0x9,0x3,0x6}; //四相双拍 逆转
		
	int us=0;
	my_motor_init();
	delay_init();
	us=1200;
	while(1)
	{
		my_motor_working_1(time_424_0,us);
//		my_motor_working_2(time_48_0,us);
//    my_motor_working_0(1200);	
	}
}

这里的顺转和逆转,跟线序有关,等你开始调的时候你就懂了。

  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值