循环流水加按键控制
实验设备
本次实验所用的设备如图:
由17个LED灯构成的一个心形灯,包括k1~k4四个按键
单片机型号:STC89C516
公司名称STC,8051内核,9指的是内部含Flash E2PROM,C指的是CMOS,16指片内ROM是64KB
最下方的灯是LED17,右侧是LED1-LED8,左侧是LED9-LED16
实验要求
按下k1,实现逆时针流水
按下k2,实现顺时针流水
按下 k3,流水暂停
按下k4,流水继续
思路分析
P2对应的是D1-D8灯,P0对应的是D9-D16灯,而P3的6口对应的是D17灯,所以要分成三部分,如何将三部分构成一个整体是重点。
解决办法:设置一个变量i,i从0一直到16,i是1的时候就是D17亮,依此类推,每个i对应一个灯亮,当亮完一圈之后,将i再置0.
按下k3,就需要设置标志位flag,如果flag等于1就是继续流水,flag=0就是在当前灯亮的位置停下,等待k4信号的来临接着流水。
注意:在流水的过程中,要时刻进行检测k3是否被按下,就需要check()函数,进行时刻调用。
最主要的就是当不满足条件时就会break,跳出相应的循环。
代码实现
#include<reg51.h>
#include<intrins.h>
void Delay(unsigned int i);//延时函数
unsigned char Key(void);//按键函数
void dispa();//控制D17逆时针流水,D8~D1,D9~D16
void dispb();//流水函数,控制D17开始顺时针流水
void check();//检测k3和k4按键是否被按下
sbit k1=P3^2;//按键以及led17的命名
sbit k2=P3^3;
sbit k3=P3^4;
sbit k4=P3^5;
sbit led=P3^6;
unsigned char flag=1;//作为区分k3还是k4按下的标志
unsigned char a;
unsigned char b;
void main()
{
unsigned char key;
key=Key();
switch(key)
{
case 1:
/*led=0;
Delay(1000);
led=1;*/
a=0xfe;
b=0x7f;
dispa();
if(k2==0)
{
a=0xfe;
b=0x7f;
dispb();
}
/*a=0x7f;
dispaa();*/
break;
case 2:
a=0xfe;
b=0x7f;
dispb();
if(k1==0)
{
a=0xfe;
b=0x7f;
dispa();
}
break;
default:
break;
}
}
//流水函数,控制D17逆时针流水,D8~D1,D9~D16
void dispa()
{
unsigned int i=0;
while(1)
{ if(i==0)
{//i=0;
P2=0xff;
P0=0xff;
led=0;
check();
if(k2==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(1000);
led=1;
}
//控制D8~D1的流水
if(i%17<=8&&i%17>0)
{
P2=a;
check();
if(k2==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(2000);
a=_crol_(a,1);
if(i==8)
{
P2=0xff;
}
}
//控制D9~D16的流水
if(i%17>8)
{
P0=b;
check();
if(k2==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(2000);
b=_cror_(b,1);
}
i++;
if(i==17)
{
i=0;
}
}
}
//流水函数,控制D17开始顺时针流水
//D17,D16~D9,D1~D8
void dispb()
{
unsigned int i=0;
while(1)
{ if(i==0)
{//i=0;
P2=0xff;
P0=0xff;
led=0;
check();
if(k1==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(2000);
led=1;
}
//控制D16~D9的流水
if(i%17<=8&&i%17>0)
{
P0=a;
check();
if(k1==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(2000);
a=_crol_(a,1);
if(i%16==8)
{
P0=0xff;
}
}
//控制D8~D1的流水
if(i%17>8)
{
P2=b;
check();
if(k1==0)
{
break;
}
if(flag==0)
{
break;
}
Delay(2000);
b=_cror_(b,1);
/*if(i%16==8)
{
P0=0xff;
}*/
}
i++;
if(i==17)
{
i=0;
}
}
}
//自定义延时函数
void Delay(unsigned int i)
{
unsigned char j;
for(;i>0;i--)
{
for(j=110;j>0;j--);
}
}
//按键扫描函数
unsigned char Key(void)
{
unsigned char key;
if(k1==0)
{
Delay(10);//延时消抖
if(k1==0)
{
key=1;
while(!k1);
}
}
if(k2==0)
{
Delay(10);//延时消抖
if(k2==0)
{
key=2;
while(!k2);
}
}
if(k3==0)
{
Delay(10);//延时消抖
if(k3==0)
{
key=3;
while(!k3);
}
}
if(k4==0)
{
Delay(10);//延时消抖
if(k4==0)
{
key=4;
while(!k4);
}
}
return key;
}
//检测k3,是否要停止流水灯
void check()
{
if(k3==0)
{
flag=0;
}
while(flag==0)
{
if(k4==0)
{
flag=1;
}
}
}
实验总结
在灯按下k1进行逆时针流水之后,如果流水的时候k2按下,那就要跳出当前循环进行顺时针流水,所以也要时刻检测k2是否为0;
灯和按键都是,当给一个低电平才会亮,才会有接通;
流水的方式采用的是循环移位,根据情况判断是左循环移还是右循环移。