基于51单片机的直流电机转速显示+加速减速启停

文章目录

  • 前言
  • 一、前期准备
  • 1、功能实现思路
  • 2、软件实现思路
  • 二、硬件电路
  • 1.总电路
  • 三、软件解读
  • 1.代码解读
  • 2.代码
  • 总结

  • 前言

    做了一个实战项目,这个实战项目主要是实现对直流电机转速的控制,可以实现电机加速,减速,报警、启停以及显示转速。在本电路的基础上也可以进行一些拓展改变电机正反转的状态,只需要外加一个按键和修改部分程序即可,在文章的最后会对拓展进行一个说明。基础代码来源于普中科技的基础例程,代码经过我的验证并且实践到了实际项目中,如果想要进行实战测试的话,请仔细对照着我这篇文章进行调试学习,实际电路要对应好。


    一、前期准备

    1、功能实现思路

    首先先分析需求:

    51单片机有很多种,鉴于本人只有AT系列单片机的下载器,因此选用的芯片型号为AT89S52/AT89C52,都兼容,任意选择一种都可以。

    直流电机驱动电路。这个比较通用的就几个,常见的有L298N驱动电路,由于是直接设计到电路板上,所以在网上copy了开源的直流电机驱动电路,就不用L298N驱动芯片了。直接通过三极管和二极管配合对马达进行驱动控制。

    需要显示转速,用LCD1602进行显示,两行可以显示N多数据

    需要进行测速,通用的就是霍尔传感器+磁铁,那么根据个人的需求,你可以选择低电平触发也可以选择高电平触发的霍尔传感器。其出发原理就是磁铁的一极靠近霍尔传感器的时候,霍尔传感器一引脚会产生触发电平,通过检查触发电平即可知道磁铁经过的次数。通常的软件检测方法是利用外部中断检测上升沿或者下降沿

    按键模块,普通的按键按下检测就可以

    特此提醒一下,我用的霍尔传感器是低电平有效,因此在我的程序里面外部中断被设置为下降沿触发。只要是低电平有效的霍尔传感器都可以,只需要注意触发速率,因为电机转速很快,所以需要高速率的检测。

    2、软件实现思路

    话不多说,直接上图。整体流程就是先将该初始化的初始化,比如外部中断,定时器一和定时器二中断。霍尔传感器的存在主要是为了检测转速,由于直流电机每转动一圈霍尔传感器就会产生一个下降沿,故可以通过判断下降沿的多少从而转换成某段时间内电机的转速。定时器一的功能是进行2s的计时,因为要统计一段时间内的下降沿个数,故通过定时器一进行赋值和复位。定时器二的作用是与设置的占空比进行比较,比如定义的占空比最大100%的时候对应一个参数量为200,那么可以设置一个定量duty为100,可以调节duty的大小,100的时候就代表50%的占空比,当计数小于100时输出为高电平,大于100时输出为低电平,这样就实现了PWM的输出。

    二、硬件电路

    1.总电路

    下图是硬件连接图
    ## 2.硬件电路解读
    除单片机最小系统以外,需要注意的地方有:

    霍尔传感器的连接方式:在VCC和数据输出口也就是定义的P33引脚口需要接一个上拉电阻,在没有触发信号的时候,数据口能够一直以高电平的状态存在,这样不会存在误触发的情况。

    直流电机驱动电路:尤其要注意三极管的型号和所处的位置,不要焊接错误了,焊接对了就能正常运行。想要让电机正常运行的话,只需要P34和P37之间存在着电平差,即P34高电平,P37低电平就可以运行,反之即可。

    LCD背光显示:此处采用电阻直接分压,并没有用到滑动变阻器分压,背光固定,可通过改变电阻自由选择。

    三、软件解读

    1.代码解读

    在参数定义部分,主要是定义多个数组。数组的作用是为了将数据存放并显示,由于LCD1602写入数据是通过地址写入的,在这里博主采用的是单字符逐步写入,所以将数据拆分开放到定义的数组里面,这样就能够单独进行显示。

    unsigned char Limit[5];   //报警阈值存放位置
    unsigned int  max=10000;  //设置报警阈值
    unsigned char duty1[3];   //报警阈值存放位置
    unsigned char zhuansu[5]; //转速存放位置
    unsigned int  zhuansu1=0; //显示转速大小
    unsigned int  zhuansu2=0; //显示转速大小
    unsigned char code wenzi1[14]={"now_V:     m/h"};
    unsigned char code wenzi2[16]={"Limit:     m    "};
    uint flag=0;
    u16 duty=100;              //占空比
    u16 duty2=0;
    u16 work_status=0;        //工作状态,为0的时候不工作,为1的时候工作
    

    IO口的定义分别为。P1.0-P1.4是按键控制口,分别代表电机加速,减速,报警阈值增加,报警阈值减少以及电机的启停。P1.5-P1.6分别代表LED灯控制端口和蜂鸣器控制端口,控制方式也就是给高低电平就能控制蜂鸣器鸣叫或者LED亮。P3.4和P3.7是控制直流电机两端的IO口,通过控制其中某个口为高电平,某个口为低电平就能实现直流电机的正转或者反转。此外,虽然没有定义,但是在外部中断里面对应的IO口为P3.3口,所以要通过杜邦线去连接霍尔传感器的数据输出端。

    sbit beep=P1^6;
    sbit led=P1^5;
    sbit out=P3^4;					  //PWM输出用于正传
    sbit out1=P3^7;			      //PWM输出用于反转
    sbit duty_add=P1^0;				//占空比加1
    sbit duty_reduce=P1^1;		//占空比减一
    sbit limit_add=P1^2;			//阈值加1
    sbit limit_reduce=P1^3;		//阈值减1
    sbit start=P1^4;					//开始或者停止工作
    

    延时函数和按键处理函数。在按键处理函数里面,对五个按键进行扫描判断,当检测到按键按下以后执行相对应的程序。其中duty是我们定义的占空比数值,占空比为100%的时候duty为200,初始值duty设置为100,对应占空比为50%。通过判断第一个或者第二个按键按下从而实现对占空比的加减。同理第三个第四个也是对阈值进行判断,第五个按键有所不同的地方在于里面有work_status的切换,当然直接用!语句也行,我这里是用习惯了这种方式。在每个按键处理函数后面加一个while循环是为了防止连续按下导致疯狂加减。

    /*******************************************************************************
    * 函 数 名         : delay
    * 函数功能		   : 延时函数,i=1时,大约延时10us
    *******************************************************************************/
    void delay(u16 i)
    {
    	while(i--);	
    }
    /*******************************************************************************
    * 函 数 名         : keypros
    * 函数功能		   : 按键处理函数,判断按键K1是否按下
    *******************************************************************************/
    void keypros()
    {
    	if(duty_add==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(duty_add==0)	 //再次判断按键是否按下
    		{
    			duty+=1;
    		}
    		while(!duty_add);	 //检测按键是否松开
    	}	
    	if(duty_reduce==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(duty_reduce==0)	 //再次判断按键是否按下
    		{
    			duty-=1;
    		}
    		while(!duty_reduce);	 //检测按键是否松开
    	}
    	if(limit_add==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(limit_add==0)	 //再次判断按键是否按下
    		{
    			max+=100;
    		}
    		while(!limit_add);	 //检测按键是否松开
    	}
    	if(limit_reduce==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(limit_reduce==0)	 //再次判断按键是否按下
    		{
    			max-=100;
    		}
    		while(!limit_reduce);	 //检测按键是否松开
    	}
    	if(start==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(start==0)	 //再次判断按键是否按下
    		{
    			work_status+=1;
    			if(work_status>=2)work_status=0;
    		}
    		while(!start);	 //检测按键是否松开
    	}	
    }
    

    三个函数的初始化。在初始化函数里面对每一个都进行了配置,每条语句有其对应的解释,具体操作是通过寄存器层面去操作的,在reg52.h里面类似于IT1这种符号都有被定义。需要注意的是,定时器的工作模式为方式1。由于每一次单片机一个周期是1us,所以若想实现10ms的定时,就需要计10000个周期,那么定时器的TH和TL就可设置为65535-计数周期+1。其中TH代表高八位,TL代表低八位。比如定时10ms就为55536,用十六进制表示为D8F0。

    /*******************************************************************************
    * 函数名         : Int1Init()
    * 函数功能		   : 霍尔传感器接收信号
    * 输入           : 无
    * 输出         	 : 无
    *******************************************************************************/
    void Int1Init()
    {
    	IT1=1;//下降沿触发
    	EX1=1;//打开中断0允许
    	EA=1;	//打开总中断
    }
    /*******************************************************************************
    * 函 数 名         : Timer0Init
    * 函数功能		   : 定时器0初始化
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer0Init()
    {
    	TMOD|=0X11;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
    
    	TH0=0XD8;	//给定时器赋初值,定时10ms
    	TL0=0XF0;	
    	ET0=1;//打开定时器0中断允许
    	EA=1;//打开总中断
    	TR0=1;//打开定时器			
    }
    /*******************************************************************************
    * 函 数 名         : Timer1Init
    * 函数功能		   : 定时器1初始化
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer1Init()
    {
    	TMOD|=0X11;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
    
    	TH1=0XFF;	//给定时器赋初值,定时100us
    	TL1=0X9C;	
    	ET1=1;//打开定时器1中断允许
    	EA=1;//打开总中断
    	TR1=1;//打开定时器			
    }
    

    主函数其实就是对所有的函数进行初始化以后,再对数据进行显示,所有控制方式生效都是在后续的定时器中断或者外部中断里面去执行。

    *******************************************************************************
    * 函数名         : main
    * 函数功能		   : 主函数
    * 输入           : 无
    * 输出         	 : 无
    *******************************************************************************/
    void main()
    {
    	unsigned char i;
    	beep=1;                           //蜂鸣器不叫
    	led=0;
    	Int1Init(); 	                    //初始化霍尔传感器外部中断1
    	Timer0Init();                     //定时器0初始化
    	Timer1Init();                     //定时器1初始化
    	LcdInit();
    	LcdWriteCom(0x80);
    	for(i=0;i<14;i++)
    	{
    		LcdWriteData(wenzi1[i]);	
    	}
    	LcdWriteCom(0x80+0x40);
    	for(i=0;i<16;i++)
    	{
    		LcdWriteData(wenzi2[i]);	
    	}
    	while(1)
    	{
    		duty2=duty/2;
    		if(zhuansu1>=max)beep=0,led=1;
    		else beep=1,led=0;
    		//按键处理
    		keypros();
    		//显示转速
    	  zhuansu[0]=zhuansu1/10000;
        zhuansu[1]=zhuansu1%10000/1000;
        zhuansu[2]=zhuansu1%10000%1000/100;
        zhuansu[3]=zhuansu1%10000%1000%100/10;
        zhuansu[4]=zhuansu1%10;
    		if(zhuansu[0]>9)
    		{
    			LcdWriteCom(0x80+0x06);			//设置显示位置
    			LcdWriteData(0x37+zhuansu[0]);	//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x06);
    			LcdWriteData(zhuansu[0]+0x30);	//将数值转换为该显示的ASCII码
    		}
    		
    		if(zhuansu[1]>9)
    		{
    			LcdWriteCom(0x80+0x07);
    			LcdWriteData(zhuansu[1]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x07);
    			LcdWriteData(zhuansu[1]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		
    		if(zhuansu[2]>9)
    		{
    			LcdWriteCom(0x80+0x08);
    			LcdWriteData(zhuansu[2]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x08);
    			LcdWriteData(zhuansu[2]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(zhuansu[3]>9)
    		{
    			LcdWriteCom(0x80+0x09);
    			LcdWriteData(zhuansu[3]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x09);
    			LcdWriteData(zhuansu[3]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(zhuansu[4]>9)
    		{
    			LcdWriteCom(0x80+0x0a);
    			LcdWriteData(zhuansu[4]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x0a);
    			LcdWriteData(zhuansu[4]+0x30);		//将数值转换为该显示的ASCII码
    		}	
        //显示阈值
        Limit[0]=max/10000;
        Limit[1]=max%10000/1000;
        Limit[2]=max%10000%1000/100;
        Limit[3]=max%10000%1000%100/10;
        Limit[4]=max%10;		
    		if(Limit[0]>9)
    		{
    			LcdWriteCom(0xc0+0x06);			//设置显示位置
    			LcdWriteData(0x37+Limit[0]);	//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x06);
    			LcdWriteData(Limit[0]+0x30);	//将数值转换为该显示的ASCII码
    		}
    		
    		if(Limit[1]>9)
    		{
    			LcdWriteCom(0xc0+0x07);
    			LcdWriteData(Limit[1]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x07);
    			LcdWriteData(Limit[1]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		
    		if(Limit[2]>9)
    		{
    			LcdWriteCom(0xc0+0x08);
    			LcdWriteData(Limit[2]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x08);
    			LcdWriteData(Limit[2]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(Limit[3]>9)
    		{
    			LcdWriteCom(0xc0+0x09);
    			LcdWriteData(Limit[3]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x09);
    			LcdWriteData(Limit[3]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(Limit[4]>9)
    		{
    			LcdWriteCom(0xc0+0x0a);
    			LcdWriteData(Limit[4]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x0a);
    			LcdWriteData(Limit[4]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		duty1[0]=duty2/100;
        duty1[1]=duty2/10;
        duty1[2]=duty2%10;
    		LcdWriteCom(0xc0+0x0d);
    		LcdWriteData(duty1[0]+0x30);		//将数值转换为该显示的ASCII码
    		LcdWriteCom(0xc0+0x0e);
    		LcdWriteData(duty1[1]+0x30);		//将数值转换为该显示的ASCII码
    		LcdWriteCom(0xc0+0x0f);
    		LcdWriteData(duty1[2]+0x30);		//将数值转换为该显示的ASCII码
    	}
    }									 
    

    在三个中断里面,首先先说明外部中断。外部中断里面这个zhuansu2的意思就是在每触发一次下降沿就加1,清零则在timer0里面进行实现。在timer0里面,定义了一个暂态变量i,i累加到200以后执行一次if语句。由于我们单次定时的时间是10ms,所以执行200次以后就是2s钟。2s一到我们就将zhuansu2的值经过处理后赋值给zhuansu1,当然由于这个转速我们无法真正测量,所以就随便在后面乘以了一个2.82,显得有零有整也更加真实一点。同时清零zhuansu2和i,这样再下一个循环zhuansu2这个参量又可以通过外部中断累加。在定时器1里面呢则是输出PWM信号。由于定时器1的速度很快,为100us一次。所以最快可以100us改变一次IO口的输出电平。在里面设置了flag变量,flag变量的作用就是从0累加到200,当我们定义的duty,也就是占空比对应的数值大于flag的时候,就停止运行。当小于flag的时候,out就给高电平,out1就给低电平,这样保证电机处于正转的工作状态。那么想要电机反转也很简单,就是令out给低电平,out1给高电平,本质上就是通过左边电压高于右边或者左边电压低于右边电压来决定的。当我们定义的work_status参数为0时,我们默认不工作,故两个IO口都直接拉高。

    /*******************************************************************************
    * 函 数 名         : Int1()	interrupt 2
    * 函数功能		   : 外部中断1的中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Int1()	interrupt 2		//外部中断1的中断函数
    {
      zhuansu2++;
    }
    /*******************************************************************************
    * 函 数 名         : void Timer0() interrupt 1
    * 函数功能		   : 定时器0中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer0() interrupt 1
    {
    	static u16 i;
    	TH0=0XD8;	//给定时器赋初值,定时10ms
    	TL0=0XF0;
    	i++;
    	if(i==200)
    	{
    		 zhuansu1=zhuansu2*30*2.82;
    		 zhuansu2=0;
    		 i=0;
    	}	
    }
    /*******************************************************************************
    * 函 数 名         : void Timer1() interrupt 3
    * 函数功能		   : 定时器0中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer1() interrupt 3
    {
      TH1=0xFF;
      TL1=0x9C;//定时100us
    	flag++;
    	if(flag>199)
    	{
         flag=1;
    	}	
    	if(work_status==1)
    	{
    		if(flag<=duty)
    		{
    			out=1;
    			out1=0;
    		}
    		else
    		{
    			out=1;
    			out1=1;
    		}
    	}
    	if(work_status==0)
    	{
    		out=1;
    		out1=1;
    	}
    }
    

    2.代码

    总代码main.c,像LCD的代码和52的代码都是普中科技通用的,copy粘贴一下就行,请注意LCD三个数据口的连接方式,根据板子不同记得更改数据口的顺序。

    #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 Limit[5];   //报警阈值存放位置
    unsigned int  max=10000;  //设置报警阈值
    unsigned char duty1[3];   //报警阈值存放位置
    unsigned char zhuansu[5]; //转速存放位置
    unsigned int  zhuansu1=0; //显示转速大小
    unsigned int  zhuansu2=0; //显示转速大小
    unsigned char code wenzi1[14]={"now_V:     m/h"};
    unsigned char code wenzi2[16]={"Limit:     m    "};
    uint flag=0;
    u16 duty=100;              //占空比
    u16 duty2=0;
    u16 work_status=0;        //工作状态,为0的时候不工作,为1的时候工作
    sbit beep=P1^6;
    sbit led=P1^5;
    sbit out=P3^4;					  //PWM输出用于正传
    sbit out1=P3^7;			      //PWM输出用于反转
    sbit duty_add=P1^0;				//占空比加1
    sbit duty_reduce=P1^1;		//占空比减一
    sbit limit_add=P1^2;			//阈值加1
    sbit limit_reduce=P1^3;		//阈值减1
    sbit start=P1^4;					//开始或者停止工作
    /*******************************************************************************
    * 函 数 名         : delay
    * 函数功能		   : 延时函数,i=1时,大约延时10us
    *******************************************************************************/
    void delay(u16 i)
    {
    	while(i--);	
    }
    /*******************************************************************************
    * 函 数 名         : keypros
    * 函数功能		   : 按键处理函数,判断按键K1是否按下
    *******************************************************************************/
    void keypros()
    {
    	if(duty_add==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(duty_add==0)	 //再次判断按键是否按下
    		{
    			duty+=1;
    		}
    		while(!duty_add);	 //检测按键是否松开
    	}	
    	if(duty_reduce==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(duty_reduce==0)	 //再次判断按键是否按下
    		{
    			duty-=1;
    		}
    		while(!duty_reduce);	 //检测按键是否松开
    	}
    	if(limit_add==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(limit_add==0)	 //再次判断按键是否按下
    		{
    			max+=100;
    		}
    		while(!limit_add);	 //检测按键是否松开
    	}
    	if(limit_reduce==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(limit_reduce==0)	 //再次判断按键是否按下
    		{
    			max-=100;
    		}
    		while(!limit_reduce);	 //检测按键是否松开
    	}
    	if(start==0)		  //检测按键K1是否按下
    	{	
    		delay(1000);   //消除抖动 一般大约10ms
    		if(start==0)	 //再次判断按键是否按下
    		{
    			work_status+=1;
    			if(work_status>=2)work_status=0;
    		}
    		while(!start);	 //检测按键是否松开
    	}	
    }
    /*******************************************************************************
    * 函数名         : Int1Init()
    * 函数功能		   : 霍尔传感器接收信号
    * 输入           : 无
    * 输出         	 : 无
    *******************************************************************************/
    void Int1Init()
    {
    	IT1=1;//下降沿触发
    	EX1=1;//打开中断0允许
    	EA=1;	//打开总中断
    }
    /*******************************************************************************
    * 函 数 名         : Timer0Init
    * 函数功能		   : 定时器0初始化
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer0Init()
    {
    	TMOD|=0X11;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
    
    	TH0=0XD8;	//给定时器赋初值,定时10ms
    	TL0=0XF0;	
    	ET0=1;//打开定时器0中断允许
    	EA=1;//打开总中断
    	TR0=1;//打开定时器			
    }
    /*******************************************************************************
    * 函 数 名         : Timer1Init
    * 函数功能		   : 定时器1初始化
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer1Init()
    {
    	TMOD|=0X11;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
    
    	TH1=0XFF;	//给定时器赋初值,定时100us
    	TL1=0X9C;	
    	ET1=1;//打开定时器1中断允许
    	EA=1;//打开总中断
    	TR1=1;//打开定时器			
    }
    /*******************************************************************************
    * 函数名         : main
    * 函数功能		   : 主函数
    * 输入           : 无
    * 输出         	 : 无
    *******************************************************************************/
    void main()
    {
    	unsigned char i;
    	beep=1;                           //蜂鸣器不叫
    	led=0;
    	Int1Init(); 	                    //初始化霍尔传感器外部中断1
    	Timer0Init();                     //定时器0初始化
    	Timer1Init();                     //定时器1初始化
    	LcdInit();
    	LcdWriteCom(0x80);
    	for(i=0;i<14;i++)
    	{
    		LcdWriteData(wenzi1[i]);	
    	}
    	LcdWriteCom(0x80+0x40);
    	for(i=0;i<16;i++)
    	{
    		LcdWriteData(wenzi2[i]);	
    	}
    	while(1)
    	{
    		duty2=duty/2;
    		if(zhuansu1>=max)beep=0,led=1;
    		else beep=1,led=0;
    		//按键处理
    		keypros();
    		//显示转速
    	  zhuansu[0]=zhuansu1/10000;
        zhuansu[1]=zhuansu1%10000/1000;
        zhuansu[2]=zhuansu1%10000%1000/100;
        zhuansu[3]=zhuansu1%10000%1000%100/10;
        zhuansu[4]=zhuansu1%10;
    		if(zhuansu[0]>9)
    		{
    			LcdWriteCom(0x80+0x06);			//设置显示位置
    			LcdWriteData(0x37+zhuansu[0]);	//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x06);
    			LcdWriteData(zhuansu[0]+0x30);	//将数值转换为该显示的ASCII码
    		}
    		
    		if(zhuansu[1]>9)
    		{
    			LcdWriteCom(0x80+0x07);
    			LcdWriteData(zhuansu[1]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x07);
    			LcdWriteData(zhuansu[1]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		
    		if(zhuansu[2]>9)
    		{
    			LcdWriteCom(0x80+0x08);
    			LcdWriteData(zhuansu[2]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x08);
    			LcdWriteData(zhuansu[2]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(zhuansu[3]>9)
    		{
    			LcdWriteCom(0x80+0x09);
    			LcdWriteData(zhuansu[3]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x09);
    			LcdWriteData(zhuansu[3]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(zhuansu[4]>9)
    		{
    			LcdWriteCom(0x80+0x0a);
    			LcdWriteData(zhuansu[4]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0x80+0x0a);
    			LcdWriteData(zhuansu[4]+0x30);		//将数值转换为该显示的ASCII码
    		}	
        //显示阈值
        Limit[0]=max/10000;
        Limit[1]=max%10000/1000;
        Limit[2]=max%10000%1000/100;
        Limit[3]=max%10000%1000%100/10;
        Limit[4]=max%10;		
    		if(Limit[0]>9)
    		{
    			LcdWriteCom(0xc0+0x06);			//设置显示位置
    			LcdWriteData(0x37+Limit[0]);	//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x06);
    			LcdWriteData(Limit[0]+0x30);	//将数值转换为该显示的ASCII码
    		}
    		
    		if(Limit[1]>9)
    		{
    			LcdWriteCom(0xc0+0x07);
    			LcdWriteData(Limit[1]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x07);
    			LcdWriteData(Limit[1]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		
    		if(Limit[2]>9)
    		{
    			LcdWriteCom(0xc0+0x08);
    			LcdWriteData(Limit[2]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x08);
    			LcdWriteData(Limit[2]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(Limit[3]>9)
    		{
    			LcdWriteCom(0xc0+0x09);
    			LcdWriteData(Limit[3]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x09);
    			LcdWriteData(Limit[3]+0x30);		//将数值转换为该显示的ASCII码
    		}			
    		
    		if(Limit[4]>9)
    		{
    			LcdWriteCom(0xc0+0x0a);
    			LcdWriteData(Limit[4]+0x37);		//将数值转换为该显示的ASCII码
    		}
    		else
    		{
    			LcdWriteCom(0xc0+0x0a);
    			LcdWriteData(Limit[4]+0x30);		//将数值转换为该显示的ASCII码
    		}	
    		duty1[0]=duty2/100;
        duty1[1]=duty2/10;
        duty1[2]=duty2%10;
    		LcdWriteCom(0xc0+0x0d);
    		LcdWriteData(duty1[0]+0x30);		//将数值转换为该显示的ASCII码
    		LcdWriteCom(0xc0+0x0e);
    		LcdWriteData(duty1[1]+0x30);		//将数值转换为该显示的ASCII码
    		LcdWriteCom(0xc0+0x0f);
    		LcdWriteData(duty1[2]+0x30);		//将数值转换为该显示的ASCII码
    	}
    }									 
    /*******************************************************************************
    * 函 数 名         : Int1()	interrupt 2
    * 函数功能		   : 外部中断1的中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Int1()	interrupt 2		//外部中断1的中断函数
    {
      zhuansu2++;
    }
    /*******************************************************************************
    * 函 数 名         : void Timer0() interrupt 1
    * 函数功能		   : 定时器0中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer0() interrupt 1
    {
    	static u16 i;
    	TH0=0XD8;	//给定时器赋初值,定时10ms
    	TL0=0XF0;
    	i++;
    	if(i==200)
    	{
    		 zhuansu1=zhuansu2*30*2.82;
    		 zhuansu2=0;
    		 i=0;
    	}	
    }
    /*******************************************************************************
    * 函 数 名         : void Timer1() interrupt 3
    * 函数功能		   : 定时器0中断函数
    * 输    入         : 无
    * 输    出         : 无
    *******************************************************************************/
    void Timer1() interrupt 3
    {
      TH1=0xFF;
      TL1=0x9C;//定时100us
    	flag++;
    	if(flag>199)
    	{
         flag=1;
    	}	
    	if(work_status==1)
    	{
    		if(flag<=duty)
    		{
    			out=1;
    			out1=0;
    		}
    		else
    		{
    			out=1;
    			out1=1;
    		}
    	}
    	if(work_status==0)
    	{
    		out=1;
    		out1=1;
    	}
    }
    

    总结

    实测效果还不错,可以用来实战演练一番。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于51单片机的直流电机转速显示+加速减速启停

    发表评论