STC89C52RC电梯模拟

题目:在STC89C52RC上完成一个八层楼的电梯模拟项目,使用键盘阵列模拟电梯按键,按键的排列如下图所示:

5

6

7

8

1

2

3

4

确定

开发板8个LED灯自下向上排列,分别对应8个楼层如下图所示:

D1

8

D2

7

D3

6

D4

5

D5

4

D6

3

D7

2

D8

1

使用8x8LED点阵屏显示1-8八个数字,蜂鸣器发出“哔”声,提示电梯到达。

现要求电梯运行流程如下:

  1. 初始电梯停在1楼,对应的LED灯点亮,点阵屏显示数字1;
  2. 按下按键上的数字键,表示电梯运行的目标楼层,对应LED灯点亮,如:按下3,对应3层的LED灯点亮;允许多次按键,如楼层已经按过,再按不起作用;
  3. 按下确定键,电梯开始以0.5秒一层的速度自下向上运行,同时对应的LED灯和点阵屏随同改变,如:运行到2层,1层LED熄灭,2层LED亮起,点阵屏显示数字2;
  4. 电梯一直运行到目标楼层,蜂鸣器响起,提示到达目标;如有多个目标楼层,每一个目标楼层停顿三秒后电梯继续运行直到最后一个目标,此时仅有该楼层LED点亮,电梯一次运行结束;
  5. 不论电梯停在何层,重复步骤2-4,电梯继续运行,注意:当目标楼层中出现小于当前楼层的,电梯都以“先上后下”原则处理,即先运行到最高目标楼层后再往下运行到最低的目标楼层方停止,完成一次运行;如仅有低于当前楼层的目标楼层,则电梯直接向下运行;
  6. 电梯运行过程中按键不起作用。

以下代码是我个人使用C51语言写的代码,以上功能能够基本实现,不能够实现的部分是电梯运行时LED灯只能显示一个灯从当前楼层到目的楼层运行的过程,不能同时显示当前楼层与目的楼层的楼层数与当前LED灯运行状态。这是博主肝了好几天晚上写的,虽然还有很多不足,但我觉得以及是我能做到的最高水平了,希望大家多多包涵,如有问题,可在评论区评论或者私信我,我看到一定会回的。

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define M 8

unsigned char LED;		//LED当前状态
unsigned char begin;   //LED灯初始状态
unsigned char tmp; //当前楼层只有其亮时的亮灯状态
unsigned char flag;	//当前输入的目的楼层
unsigned char first;   //初始楼层数
unsigned char b[M];	 //b数组内存储从大到小的目标楼层数
unsigned char a[M];	 //a数组用来小于当前楼层的楼层
unsigned char c[M];	 //c数组存放大于first的楼层


sbit Max7219_pinCS = P2^5;
sbit Max7219_pinDIN = P2^6;
sbit Max7219_pinCLK = P2^7;
sbit beep=P2^3;
																			   

uchar code disp[8][8]={
{0x18,0x8,0x8,0x8,0x8,0x8,0x8,0x3E},//1
{0x7C,0x44,0x44,0x8,0x10,0x20,0x40,0x7C},//2
{0x7C,0x4,0x4,0x7C,0x4,0x4,0x4,0x7C},//3
{0x22,0x22,0x22,0x22,0x3E,0x2,0x2,0x2},//4
{0x20,0x3E,0x20,0x20,0x3E,0x2,0x2,0x3E},//5
{0x3E,0x22,0x20,0x20,0x3E,0x22,0x22,0x3E},//6
{0x7E,0x4,0x8,0x10,0x20,0x20,0x20,0x20},//7
{0x7C,0x44,0x44,0x44,0x7C,0x44,0x44,0x7C},//8
};

void delay1ms(uint n)	   //延时n毫秒
{
	uint i,j;
	for(i=n;i>0;i--)
		for(j=112;j>0;j--);
}

void delay(uint i){
	 while(i--){
	 }
}

void Write_Max7219_byte(uchar DATA)    //向MAX7219写入字节     
{
    	uchar i;    
		Max7219_pinCS=0;		
	    for(i=8;i>=1;i--)
        {		  
            Max7219_pinCLK=0;
            Max7219_pinDIN=DATA&0x80;
            DATA=DATA<<1;
            Max7219_pinCLK=1;
        }                                 
}

void Write_Max7219(uchar address,uchar dat)	  //向MAX7219写入数据
{ 
     Max7219_pinCS=0;
	 Write_Max7219_byte(address);           //写入地址,即数码管编号
     Write_Max7219_byte(dat);               //写入数据,即数码管显示数字 
	 Max7219_pinCS=1;                        
}

//初始化MAX7219
void Init_MAX7219(void)
{
	Write_Max7219(0x09, 0x00);       //译码方式:BCD码:0x07;不译码,直接存字形码:0x00
	Write_Max7219(0x0a, 0x03);       //亮度 
	Write_Max7219(0x0b, 0x07);       //扫描界限;8个数码管显示
	Write_Max7219(0x0c, 0x01);       //掉电模式:0,普通模式:1
	Write_Max7219(0x0f, 0x00);       //显示测试:1;正常显示:0
}

int check()   //检查当前8个LED中灯亮起的数量及位置
{
	
	uchar i,j=0,count=0;
	for(i=1;i<9;i++)	   //i表示位数
	{
		if((0x01&LED>>(i-1))==0)
		{
			count++;
			b[count]=9-i;  //9-i表示楼层数
			

		}
	}
	return count;
}


					 	
	
void display(uchar n,uchar m)   //当前输入楼层的灯亮情况n以及其所对应的楼层数m		  
{
	uchar i;
	flag=m;			 //flag所输入的目的楼层
	tmp=n;			//当前楼层只有其亮时的亮灯状态		  				 
	for(i=1;i<9;i++)
	{
   	 	Write_Max7219(i,disp[flag-1][i-1]); 
	}	
	P1=~(P1^tmp);   //此时LED亮起,表示输入楼层的对应灯亮以及当前所在楼层亮的情况
	LED=P1;			
}
	
void run()	//电梯运行
{
	uchar i,j,x,y,q,p,z,m,n,k=0,f,g=0;
	uint t=0;
	uchar count,smaller=0,s,bigger=0;
	count=check();
	if(count==1) return;
	if(count==2)
	{
		if(first<flag)
		{	
			P1=begin;  //p1 1101 1111
			for(i=0;i<8;i++)
			{		
				delay1ms(500);
				P1=P1>>1;
				P1=P1|0x80;
				if(P1==tmp) break;	  //表示已到达目的层			
			}
			beep=0;
			delay1ms(100);
			beep=1;
			for(j=1;j<9;j++)
			{
   		 		Write_Max7219(j,disp[flag-1][j-1]); 
			}			
			begin=P1;//begin 1101 1111
			first=flag;
	
		}
		else if(first>flag)
		{
			P1=begin;  //p1 1101 1111
			for(x=0;x<8;x++)
			{		
				delay1ms(500);
				P1=P1<<1;
				P1=P1|0x01;
				if(P1==tmp) break;	  //表示已到达目的层			
			}
			beep=0;
			delay1ms(100);
			beep=1;
			for(y=1;y<9;y++)
			{
   		 		Write_Max7219(y,disp[flag-1][y-1]); 
			}
			begin=P1;//begin 1101 1111
			first=flag;
			
		}
	}
	if(count>2)
	{
		 for(p=count;p>0;p--)
		 {
		 	if(b[p]<first)	  
			{
				smaller++;//smaller表示小于当前目标楼层的个数
				a[k]=b[p];
				k++;
			}
			else if(b[p]>first)
			{
				bigger++;
				c[g]=b[p];	
				g++;
			}
		 }
		 if(bigger==0)
		 {
		 	 for(f=smaller-1;f>=0;f--)
			 {
				P1=begin;
			 	for(z=0;z<8;z++)
				{
					
					delay1ms(500);
					first--;
					P1=P1<<1;
					P1=P1|0x01;
					
					if(a[f]==first) break;		
				} 
				beep=0;
				delay1ms(100);
				beep=1;
				for(n=1;n<9;n++)
				{
   		 			Write_Max7219(n,disp[first-1][n-1]); 
				}
				delay1ms(3000);
				begin=P1;
				first=a[f];
				if(f==0) break;
			} 	
		 }
		 if(smaller==0)
		 {
		 	for(s=0;s<bigger;s++)
			{
				P1=begin;			
				for(q=0;q<8;q++)
				{	 
					
					delay1ms(500);
					first++;
					P1=P1>>1;
					P1=P1|0x80;
					if(first==c[s]) break;
				}
				beep=0;
				delay1ms(100);
				beep=1;
				for(m=1;m<9;m++)
				{
   		 			Write_Max7219(m,disp[first-1][m-1]); 
				}				
				delay1ms(3000);
				begin=P1;
				first=c[s];
				if(s==bigger-1) break;
			}
		 }
		 if(smaller!=0&&bigger!=0)
		 {
		 	 for(s=0;s<bigger;s++)
			 {
				P1=begin;			
				for(q=0;q<8;q++)
				{	 
					
					delay1ms(500);
					first++;
					P1=P1>>1;
					P1=P1|0x80;
					if(first==c[s]) break;
				}
				beep=0;
		 		delay1ms(100);
				beep=1;
				for(m=1;m<9;m++)
				{
   		 			Write_Max7219(m,disp[first-1][m-1]); 
				}				
				delay1ms(3000);
				begin=P1;
				first=c[s];
				if(s==bigger-1) break;
			}
			for(f=smaller-1;f>=0;f--)
			{
				P1=begin;
			 	for(z=0;z<8;z++)
				{
					
					delay1ms(500);
					first--;
					P1=P1<<1;
					P1=P1|0x01;
					if(a[f]==first) break;		
				}
				beep=0;
				delay1ms(100);
				beep=1;
				for(n=1;n<9;n++)
				{
   		 			Write_Max7219(n,disp[first-1][n-1]); 
				}
				delay1ms(3000);
				begin=P1;
				first=a[f];
				if(f==0) break;
			}	
		 }
	}
}			 
 



void keyscan4x4()
{
    uchar temp,key,index;
	///第一行扫描///
	P3=0xfe;//1111 1110 让P3.0口输出低
	temp=P3;
	temp=temp&0xf0;//1111 0000	位与操作 屏蔽后四位
	if(temp!=0xf0)
	{
	    delay1ms(10);
		temp=P3;
		temp=temp&0xf0;
		if(temp!=0xf0)
		{
		    temp=P3;
			switch(temp)
			{
			  case 0xee:	   //1110 1110 S1被按下
			       key=0xf7;
				   index=5;
				   break;
			  case 0xde:		  //1101 1110  S2被按下
				   key=0xfb;
				   index=6;
				   break;
			  case 0xbe:		  //1011 1110  S3被按下
				   key=0xfd;
				   index=7;
				   break;
			  case 0x7e:		  //0111 1110  S4被按下
				   key=0xfe;
				   index=8;
				   break;
			}
			while(temp!=0xf0)
			{
			    temp=P3;
				temp=temp&0xf0;
			}
			display(key,index);
		}
	}
			///第二行扫描///
	P3=0xfd;//1111 1101 让P3.1口输出低
	temp=P3;
	temp=temp&0xf0;//1111 0000	位与操作 屏蔽后四位
	if(temp!=0xf0)
	{
	    delay1ms(10);
		temp=P3;
		temp=temp&0xf0;
		if(temp!=0xf0)
		{
		    temp=P3;
			switch(temp)
			{
			  case 0xed:	   //1110 1101 S5被按下
			       key=0x7f;
				   index=1;
				   break;
			  case 0xdd:		  //1101 1101  S6被按下
				   key=0xbf;
				   index=2;
				   break;
			  case 0xbd:		  //1011 1101  S7被按下
				   key=0xdf;
				   index=3;
				   break;
			  case 0x7d:		  //0111 1101  S8被按下
				   key=0xef;
				   index=4;
				   break;
			}
			while(temp!=0xf0)
			{
			    temp=P3;
				temp=temp&0xf0;
			}
			display(key,index);
		}
	 }
			///第三行扫描///
	P3=0xfb;//1111 1011 让P3.2口输出低
	temp=P3;
	temp=temp&0xf0;//1111 0000	位与操作 屏蔽后四位
	if(temp!=0xf0)
	{
	    delay1ms(10);
		temp=P3;
		temp=temp&0xf0;
		if(temp!=0xf0)
		{
		    temp=P3;
			switch(temp)
			{
			  case 0xeb:	   //1110 1011 S9被按下
				   break;
			  case 0xdb:		  //1101 1011  S10被按下
				   break;
			  case 0xbb:		  //1011 1011  S11被按下
				   break;
			  case 0x7b:		  //0111 1011  S12被按下
				   break;
			}
			while(temp!=0xf0)
			{
			    temp=P3;
				temp=temp&0xf0;
			}
		  }
	}

			///第四行扫描///
	P3=0xf7;//1111 0111 让P3.0口输出低
	temp=P3;
	temp=temp&0xf0;//1111 0000	位与操作 屏蔽后四位
	if(temp!=0xf0)
	{
	    delay1ms(10);
		temp=P3;
		temp=temp&0xf0;
		if(temp!=0xf0)
		{
		    temp=P3;
			switch(temp)
			{
			  case 0xe7:	   //1110 0111 S13被按下
			       run();
				   break;
			  case 0xd7:		  //1101 0111  S14被按下
				   break;
			  case 0xb7:		  //1011 0111  S15被按下
				   break;
			  case 0x77:		  //0111 0111  S16被按下
				   break;
			}
			while(temp!=0xf0)
			{
			    temp=P3;
				temp=temp&0xf0;
			}

		 }
	 }

}

void main()
{
	uchar i;
	P1=0x7f; //0111 1111
	first=1; //first表示当前楼层数
	begin=P1; //初始电梯状态
	delay1ms(50);
	Init_MAX7219();
	for(i=1;i<9;i++)
	{
   	 	Write_Max7219(i,disp[0][i-1]); 
	}
	delay1ms(1000);
	while(1)
	{
		keyscan4x4();
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值