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