项目文件
文件
关于项目的内容知识点可以见专栏单片机原理及应用 的第四章 IO口编写
在电路图的基础上,编写可键控的流水灯程序。要求实现的功能为,K1是总开关,当K1首次按下时,流水灯由下往上流动;当K2按下时停止流动,且全部灯灭;当K3 按下时使灯由上往下流动,K4则使灯由下往上流动。

 思路分析:
当K1~ K4分别按下时,经(P0 & 0xf)运算得到的应键值分别为0x0e、0x0d、0x0b、0x07,而无键按下时的键值为0x0f。
显然,按键状态可以依据(PO&0x0f)是否等于 0xof 来进行判断。为此,可采用根据键值修改标志位,再根据标志位控制 LED灯状态的编程思路,即设置两个标志位:启停标志 run (=1 表示启动,=0 表示停止),方向标志 dir(=1表示自上而下循环,=0表示自下而上循环)。

获取按键状态:

 根据按键状态值来修改标志位:
- run=1:开始(自下而上)
- run=0:结束
- dir=0:自下而上
- dir=1:自上而下
	switch (P0 & 0x0f){			 	//读取键值
			case 0x0e:run=1;break;		//K1动作,设run=1
			case 0x0d:run=0,dir=0;break;//K2动作,设run=dir=0
			case 0x0b:dir=1;break;		//K3动作,设dir=1
			case 0x07:dir=0;break;	    //K4动作,设dir=0
LED的工作状态可由存放在一个数组中的数据控制。本例电路中LED为低电平驱动,故花样数据中输出0电平对应着灯亮,输出1电平对应着灯灭,即:
unsigned char led[]={0xfe,0xfd,0xfb,0xf7};//LED灯的亮灯数据
自上而下和自下而上时的彩灯循环可以采用如下for 循环语句实现,即:
	if (run) 						//若run=dir=1, 自上而下流动
			if(dir)
				for(i=0;i<=3;i++){
					P2=led[i];
					delay(200);
				}
		    else						//若run=1,dir=0, 自下而上流动
				for(i=3;i>=0;i--){
					P2=led[i]; 
					delay(200);
				}
				 else P2=0xff; 					//若run=0,灯全灭
	}
所以完整的代码如下:
#include "reg51.h"
unsigned char led[]={0xfe,0xfd,0xfb,0xf7};//LED灯的亮灯数据
void delay(unsigned char time){ 	     //延时函数
	unsigned int j=15000;
	for(;time>0;time--)
		for(;j>0;j--);
} 
void main(){ 
	bit dir=0,run=0;				    //标志位定义及初始化
	char i;
	while(1){ 
		switch (P0 & 0x0f){			 	//读取键值
			case 0x0e:run=1;break;		//K1动作,设run=1
			case 0x0d:run=0,dir=0;break;//K2动作,设run=dir=0
			case 0x0b:dir=1;break;		//K3动作,设dir=1
			case 0x07:dir=0;break;	    //K4动作,设dir=0
		}
		if (run) 						//若run=dir=1, 自上而下流动
			if(dir)
				for(i=0;i<=3;i++){
					P2=led[i];
					delay(200);
				}
		    else						//若run=1,dir=0, 自下而上流动
				for(i=3;i>=0;i--){
					P2=led[i]; 
					delay(200);
				}
	    else P2=0xff; 					//若run=0,灯全灭
	}
}
结果:

运行视频:
单片机C51-键控流水灯


















