基于51单片机的步进电机驱动,亲测无误

这篇具有很好参考价值的文章主要介绍了基于51单片机的步进电机驱动,亲测无误。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

这一次要分享的项目是最近接单做的一个小玩意儿,基于51单片机的步进电机驱动。最近积压了两个月的小项目会在后面陆续发出,好了回归正题。本次步进电机驱动的话主要实现的功能就是实现:

步进电机的加速和减速,正转反转和开启或者停止工作。用LCD1602显示当前工作转速及正反转状态,可通过按键控制电机的开启和关闭。


一、我们该如何实现电机驱动?

目前步进电机的驱动系统已经非常完善了,总结下来你只需要准备这几个信号即可:

脉冲信号:步进电机是脉冲驱动型,拿最常见的42步进电机来说,普通状态下它的步距角为1.8°。这个步距角的含义指的是,你给电机一个脉冲信号,步进电机就转动1.8°,而很明显我们转动一圈需要360°,也就是说我们给步进电机200个脉冲信号,就能够让步进电机转一圈。因此只需要单片机内部发出脉冲信号,根据你自己的需求,比如你想使步进电机转动速度变快,相应的增加脉冲的频率即可,在相同的时间内发出的脉冲数越多,你就可以转动的越快。

方向信号:顾名思义,你给高电平或者低电平,对应的步进电机转动的方向就为正方向或者反方向。你只需要设置好IO口输出状态,51单片机不用管,32单片机推挽输出即可。

脱机信号:这玩意儿我的评价是,暂时用不到,悬空就行。

其他的就是供电电源之类的准备,其实搞懂这些,就可以实现对步进电机的驱动了

二、驱动实现

1.硬件准备

  • 主要的硬件清单

1、AT89C51最小系统套件,兼容即可
2、LCD1602液晶显示屏
3、LM2596S-5.0稳压芯片
4、步进电机驱动器+42步进电机(我买的是一体式的)
5、供电电源(我用的是XH_2接口的12V电池接入

  • 接线说明

P1口的0-4号引脚均接入按键中,实现不同的功能
P3^7为正反转的控制位
P3^4为脉冲的输出位

  • 电路图
    基于51单片机的步进电机驱动,亲测无误
  • PCB
    基于51单片机的步进电机驱动,亲测无误

2.软件编写

  • 关键点

在代码中总共用到了两个定时器:

其中定时器一主要是为了刷新界面,每隔2s对界面进行刷新,注意此处是在步进电机不细分的情况下,对应的pulse_speed参量是每秒钟的脉冲总数
基于51单片机的步进电机驱动,亲测无误
定时器二主要是对脉冲输出进行控制,work_degree为步进电机的档位,根据不同的档位选择不同的定时时间,也就是脉冲的频率,档位越高,定时器的时间就越短,相对应的频率也就越高,在此处还定义了一个flag变量,定义此变量的意义在于每执行一次定时器,输出电平就会反转。相当于输出脉冲的频率是此定时器的1/2,快乐加倍。
基于51单片机的步进电机驱动,亲测无误

至于其他地方代码都是比较简洁明了的,也有相对应的注释。

  • 代码

main.c

#include<reg51.h>
#include"lcd.h"
#define uchar unsigned char
#define uint  unsigned int
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
void DelayMs(unsigned int );
/*******************************************************************************
* 函数名         : 变量定义
* 函数功能		   : 新的变量
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
unsigned char num[4];             //显示每分钟多少转
unsigned char dangwei[1];         //档位的显示
unsigned int  pulse_speed=100;    //每分钟多少转
unsigned int  pulse_speed1=0;     //每分钟多少转
unsigned char code wenzi1[16]={"now_V:     r/min"};
unsigned char code wenzi2[16]={"status:         "};
unsigned char code zheng1[5]={"zheng"};
unsigned char code fan1[5]={"fan  "};
//占空比输出
uint flag=1;                      //计时增加值
u16 duty=1;                       //占空比
u16 work_degree=1;                //步进电机工作等级
u16 work_status=0;                //工作状态,为0的时候不工作,为1的时候工作
//电机控制
sbit status=P3^7;					        //正反转控制位
sbit out=P3^4;			              //脉冲输出位
//按键控制
sbit add=P1^0;				            //加速
sbit reduce=P1^1;		              //减速
sbit zheng=P1^2;			            //正转
sbit fan=P1^3;		                //反转
sbit start=P1^4;					        //开始或者停止工作

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	while(i--);	
}
/*******************************************************************************
* 函 数 名         : keypros
* 函数功能		   : 按键处理函数,判断按键K1是否按下
*******************************************************************************/
void keypros()
{
	if(add==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(add==0)	 //再次判断按键是否按下
		{
			work_degree+=1;
			if(work_degree==8)work_degree=7;
		}
		while(!add);	 //检测按键是否松开
	}	
	if(reduce==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(reduce==0)	 //再次判断按键是否按下
		{
			work_degree-=1;
			if(work_degree==0)work_degree=1;
		}
		while(!reduce);	 //检测按键是否松开
	}
	if(zheng==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(zheng==0)	 //再次判断按键是否按下
		{
			status=1;
		}
		while(!zheng);	 //检测按键是否松开
	}
	if(fan==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(fan==0)	 //再次判断按键是否按下
		{
			status=0;
		}
		while(!fan);	 //检测按键是否松开
	}
	if(start==0)		  //检测按键K1是否按下
	{	
		delay(1000);   //消除抖动 一般大约10ms
		if(start==0)	 //再次判断按键是否按下
		{
			work_status+=1;
			if(work_status>=2)work_status=0;
		}
		while(!start);	 //检测按键是否松开
	}	
}
/*******************************************************************************
* 函 数 名         : Timer0Init
* 函数功能		   : 定时器0初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0Init()
{
	TMOD|=0X11;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

	TH0=0XD8;	//给定时器赋初值,定时1ms
	TL0=0XF1;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器			
}
/*******************************************************************************
* 函 数 名         : Timer1Init
* 函数功能		   : 定时器1初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer1Init()
{
	TMOD|=0X11;//选择为定时器1模式,工作方式1,仅用TR1打开启动。

	TH1=0X3C;	//给定时器赋初值,定时50ms
	TL1=0XB1;	
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断
	TR1=1;//打开定时器			
}
/*******************************************************************************
* 函数名         : main
* 函数功能		   : 主函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void main()
{
	unsigned char i;
	Timer0Init();                     //定时器0初始化
	Timer1Init();                     //定时器1初始化
	LcdInit();
	LcdWriteCom(0x80);
	for(i=0;i<16;i++)
	{
		LcdWriteData(wenzi1[i]);	
	}
	LcdWriteCom(0x80+0x40);
	for(i=0;i<16;i++)
	{
		LcdWriteData(wenzi2[i]);	
	}
	while(1)
	{
		//按键处理
		keypros();
		//显示转速
//		pulse_speed=;
		num[0]=pulse_speed/1000;
	    num[1]=pulse_speed%1000/100;
        num[2]=pulse_speed%100/10;
        num[3]=pulse_speed%10;
		dangwei[0]=work_degree;
		if(num[0]>9)
		{
			LcdWriteCom(0x80+0x06);			//设置显示位置
			LcdWriteData(0x37+num[0]);	//将数值转换为该显示的ASCII码
		}
		else
		{
			LcdWriteCom(0x80+0x06);
			LcdWriteData(num[0]+0x30);	//将数值转换为该显示的ASCII码
		}
		
		if(num[1]>9)
		{
			LcdWriteCom(0x80+0x07);
			LcdWriteData(num[1]+0x37);		//将数值转换为该显示的ASCII码
		}
		else
		{
			LcdWriteCom(0x80+0x07);
			LcdWriteData(num[1]+0x30);		//将数值转换为该显示的ASCII码
		}	
		
		if(num[2]>9)
		{
			LcdWriteCom(0x80+0x08);
			LcdWriteData(num[2]+0x37);		//将数值转换为该显示的ASCII码
		}
		else
		{
			LcdWriteCom(0x80+0x08);
			LcdWriteData(num[2]+0x30);		//将数值转换为该显示的ASCII码
		}	

		if(num[3]>9)
		{
			LcdWriteCom(0x80+0x09);
			LcdWriteData(num[3]+0x37);		//将数值转换为该显示的ASCII码
		}
		else
		{
			LcdWriteCom(0x80+0x09);
			LcdWriteData(num[3]+0x30);		//将数值转换为该显示的ASCII码
		}					
		
		//显示正反转
		if(status==1)
		{
		  LcdWriteCom(0x80+0x47);
	    for(i=0;i<5;i++)
	    {
		    LcdWriteData(zheng1[i]);	
	    }
		}
		else
		{
			LcdWriteCom(0x80+0x47);
	    for(i=0;i<5;i++)
	    {
		    LcdWriteData(fan1[i]);	
	    }
		}
		
		//显示当前档位
		if(dangwei[0]>9)
		{
			LcdWriteCom(0x80+0x4F);
			LcdWriteData(dangwei[0]+0x37);		//将数值转换为该显示的ASCII码
		}
		else
		{
			LcdWriteCom(0x80+0x4F);
			LcdWriteData(dangwei[0]+0x30);		//将数值转换为该显示的ASCII码
		}	
	}
}									 
/*******************************************************************************
* 函 数 名         : void Timer0() interrupt 1
* 函数功能		   : 定时器0中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0() interrupt 1
{
	static u16 i;
	TH0=0Xdc;	//给定时器赋初值,定时10ms
	TL0=0X00;
	i++;
	if(i==200)
	{
		if(work_degree==1)pulse_speed=50;
		else if(work_degree==2)pulse_speed=100;
		else if(work_degree==3)pulse_speed=200;
        else if(work_degree==4)pulse_speed=500;
		else if(work_degree==5)pulse_speed=1000;
		else if(work_degree==6)pulse_speed=2000;
		else if(work_degree==7)pulse_speed=4000;
		i=0;
	}	
}
/*******************************************************************************
* 函 数 名         : void Timer1() interrupt 3
* 函数功能		   : 定时器0中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer1() interrupt 3
{
	if(work_degree==1)TH1=0xD8,TL1=0xF1;//定时10ms
    else if(work_degree==2)TH1=0xEC,TL1=0x79;//定时5ms
    else if(work_degree==3)TH1=0xF6,TL1=0x3D;//定时2.5ms
	else if(work_degree==4)TH1=0xFC,TL1=0x19;//定时1ms
	else if(work_degree==5)TH1=0xFE,TL1=0x0D;//定时500us
	else if(work_degree==6)TH1=0xFF,TL1=0x07;//定时250us
	else if(work_degree==7)TH1=0xFF,TL1=0x84;//定时125us
	flag++;
	if(flag>1)
	{
     flag=0;
	}	
	if(work_status==1)
	{
		if(flag<duty)
		{
			out=1;
		}
		else
		{
			out=0;
		}
	}
	else
	{
		out=0;
	}
}

Lcd.c

#include"lcd.h"
/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能		   : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能		   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef 	LCD1602_4PINS	 //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
#else 
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;	 //使能清零
	LCD1602_RS = 0;	 //选择写入命令
	LCD1602_RW = 0;	 //选择写入

	LCD1602_DATAPINS = com;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

//	Lcd1602_Delay1ms(1);
	LCD1602_DATAPINS = com << 4; //发送低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能		   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/		   
#ifndef 	LCD1602_4PINS		   
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	  //使能清零
	LCD1602_RS = 1;	  //选择写入数据
	LCD1602_RW = 0;	  //选择写入

	LCD1602_DATAPINS = dat;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

	LCD1602_DATAPINS = dat << 4; //写入低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能		 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/		   
#ifndef		LCD1602_4PINS
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()						  //LCD初始化子程序
{
	LcdWriteCom(0x32);	 //将8位总线转为4位总线
	LcdWriteCom(0x28);	 //在四位线下的初始化
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#endif

lcd.h

#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include<reg51.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^5;
sbit LCD1602_RW=P2^6;
sbit LCD1602_RS=P2^7;

/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat)	;
/*LCD1602初始化子程序*/		
void LcdInit();						  

#endif

需要注意的是,虽然lcd的代码是基于普中科技的实验例程修正过来的,但是对于RS\RW\EN三个接口的引脚有所更改,建议复制粘贴我的lcd代码

3.实物

基于51单片机的步进电机驱动,亲测无误
基于51单片机的步进电机驱动,亲测无误
实物视频请移步我的个人主页视频去看


总结

冲冲冲,步进电机驱动很简单,大家可以在此基础上结合其他模块玩一些好玩的东西,稍后代码和资料会发布到我的资源中文章来源地址https://www.toymoban.com/news/detail-408419.html

到了这里,关于基于51单片机的步进电机驱动,亲测无误的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 51单片机步进电机角度控制详解(免费提供代码+仿真)

    我个人认为,步进电机的基本原理和介绍看看其他博主的介绍就好了。我比较希望讲一下我对步进电机的关于自己一种理解方式,可能与真正步进电机的原理差的有点大。下面还是给一下我推荐的一些博主对步进电机的介绍文章。 百度步进电机链接 步进电机驱动及原理—s

    2023年04月18日
    浏览(35)
  • 51单片机控制步进电机启停,正反转速度——入门

    实验器件 STC89C52RC的学习板子一个 DC 5V 4相5线步进电机 28YBJ-48 减速步进电机一个 元器件连接: 51单片机开发板  电气原理图     实验现象:下载程序后; 当按下KEY1键可调节电机旋转方向; 当按下KEY2键,电机加速; 当按下KEY3键,电机减速; 按下KEY4的时候,电机启动/停止;

    2024年02月11日
    浏览(33)
  • 51单片机的步进电机控制系统(仿真+程序+报告+原理图)

    该系统由AT89C51单片机+数码管模块+步进电机模块+按键模块构成。 可实现功能: 1、按键控制步进电机正反转、加减速、停止; 2、2个发光二极管显示正反转,1位7段LED数码管显示当前转速档位(共9个档位); 3、4个红色LED,指示电机的转速。 protues 仿真使用的是8.10版本,由于

    2024年02月11日
    浏览(29)
  • 153、仿真-基于51单片机四相步进电机正反转控制系统设计(程序+Proteus仿真+参考论文+流程图+配套资料等)

    目录 一、设计功能 二、Proteus仿真图​ 三、程序源码 资料包括: 需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一:STM32系列单片机控制,该型号单片机为LQFP44封装,内部资源足够用于本次设计。

    2024年02月16日
    浏览(44)
  • 218、仿真-基于51单片机步进电机正反转加减速度LCD1602显示Proteus仿真设计(程序+Proteus仿真+配套资料等)

    目录 一、硬件设计 二、设计功能 三、Proteus仿真图​编辑 四、程序源码 资料包括: 需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一:STM32系列单片机控制,该型号单片机为LQFP44封装,内部资源足

    2024年02月12日
    浏览(35)
  • 51单片机双轴太阳能追光追日系统ULN2003步进电机

    功能介绍:    

    2023年04月09日
    浏览(42)
  • 【51单片机Keil+Proteus8.9】控制步进电机+LCD1602显示状态

    步进电机控制 设计思路 电路设计: 选用AT89C51单片机作为电路核心部件,外加LM016L液晶显示屏作为显示,显示步进电机的Fast,Slow,Stop的三个状态 将AT89C51单片机所选引脚与LM016L控制引脚相连,再将数据通过引脚与LCD接收引脚相连。 通过AT89C51单片机P0^0和P0^2两个引脚引出两个

    2024年01月20日
    浏览(47)
  • 7-3、S曲线生成器【51单片机控制步进电机-TB6600系列】

    摘要 :本节介绍步进电机S曲线生成器的计算以及使用 一.计算原理 根据上一节内容,已经计算了一条任意S曲线的函数。在步进电机S曲线加减速的控制中,需要的S曲线如图1所示,横轴为时间,纵轴为角速度,其中w0为起始角速度,w1为终止角速度 在S曲线加减速控制中,加减

    2024年02月08日
    浏览(36)
  • 基于单片机的步进电机驱动电路设计

    基于单片机的步进电机驱动电路设计 步进电机在控制系统中具有广泛的应用。它可以把脉冲信号转换成角位移,并且可用作电磁制动轮、电磁差分器、或角位移发生器等。 有时从一些旧设备上拆下的步进电机(这种电机一般没有损坏)要改作它用,一般需自己设计驱动器。本文

    2024年01月17日
    浏览(42)
  • 基于单片机的步进电机调控系统设计(#0527)

    1、采用51/52单片机作为主控芯片; 2、采用DC-5V步进减速电机(步进角度5.625°,减速比1/64); 3、采用ULN2003作为电机驱动; 4、采用一位数码管显示当前转速(10档); 5、按键控制正转、反转、加速、减速、停止; 6、LED指示正反转状态、监看驱动信号; 采用Altium Designer作为

    2024年02月02日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包