项目文件
文件
关于项目的内容知识点可以见专栏单片机原理及应用 的第四章 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-键控流水灯