今天来介绍另一个外设——按键与LED的配合工作,与开关不同,按键需要注意消除抖动带来的影响,代码逻辑也会更复杂一写,下面先为大家介绍独立式键盘的相关知识。
单片机的独立式键盘指的是一种不依赖于计算机或其他外部设备的键盘输入方式,由若干按键按照一定的规则组成,每一个按键实质就是一个按钮开关。而独立式键盘的各键相互独立,每个按键各接一条I/O口线,通过检测I/O输入线的电平状态,很容易地判断哪个按键被按下。
当无键按下时,通过上拉电阻,P0的 8 个I/O口引脚被上拉为高电平“ 1 ”;如果有键按下,将使对
应该键接的I/O口引脚,通过该键接地,信息为“0 ” 。
与开关不同,机械式按键在按下或释放时,由于机械弹性作用的影响
通
常伴随一定时间的触点机械抖
动,
然后才能稳定下来。
若有抖动,按键按下会被错误地认为是多次操作。
所以我们要在代码中执行消抖程序。
消抖程序的原理是
在检测到有按键按下时执行一个10ms左右的延时程序;再确认该键电平是否仍保持闭合状态电平,若仍保持闭合状态电平,则确认该键处于闭合状态,从而消除抖动的影响。我现在以8位独立式键盘控制LED灯点亮作为案例,代码如下:
#include <reg52.h>
void delay10ms(void) //延时消抖程序,第三种delay,数量级为5~10k
{
unsigned char i,j;
for(i=40;i>0;i--)
for(j=250;j>0;j--);
}
void main()
{
unsigned char x;
P1=0xff; //led全灭
x=0;
while(1)
{
while(x==0) //无键被按下执行死循环,有键被按下才往下走
{x=P0; //第一次进入循环给x赋值,没有异常再取反恢复原值
x=~x;}
delay10ms(); //消抖
x=P0; //再次读键盘状态
x=~x;
if(x==0) continue;//如果无键按下则认为是按键抖动,重新扫描键盘
switch(x) //根据键值点亮对应的发光二极管
{
case 0x01: P1=0xfe; break; //点亮第一个发光二极管
case 0x02: P1=0xfd; break; //点亮第二个发光二极管
case 0x04: P1=0xfb; break; //点亮第三个发光二极管
case 0x08: P1=0xf7; break; //点亮第四个发光二极管
case 0x10: P1=0xef; break; //点亮第五个发光二极管
case 0x20: P1=0xdf; break; //点亮第六个发光二极管
case 0x40: P1=0xbf; break; //点亮第七个发光二极管
case 0x80: P1=0x7f; break; //点亮第八个发光二极管
default: break;
}
}
}
#include<reg52.h>
sbit S1=P1^0; //将S1位定义为P1.0引脚
sbit S2=P1^1; //将S2位定义为P1.1引脚
sbit S3=P1^2; //将S3位定义为P1.2引脚
sbit S4=P1^3; //将S4位定义为P1.3引脚
unsigned char keyval; //定义键值储存变量单元
void led_delay(void);//第一种延时函数,流水灯延时
void delay10ms(void);//按键消抖
void key_scan(void) ;//键盘扫描
void ledstate(); //switch封装,也可以写在主函数中
//void key(void);
//灯的四种变化
void forward(void); //从上至下
void backward(void);//从下至上
void Alter(void); //高四位与低四位互闪
void blink (void); //全闪
void main(void)
{
keyval=0; //键值初始化为0
while(1)
{ //key();
key_scan(); //调用键盘扫描函数
ledstate(); //调用灯光执行程序
}
}
void key_scan(void) //函数功能:键盘扫描
{
P1=0xff;
if((P1&0x0f)!=0x0f) //检测到有键按下
{
delay10ms(); //延时10ms再去检测
if(S1==0) keyval=1; //按键k1被按下
if(S2==0) keyval=2; //按键k2被按下
if(S3==0) keyval=3; //按键k3被按下
if(S4==0) keyval=4; //按键k4被按下
}
}
void forward(void) //函数功能:正向流水点亮LED
{
P3=0xfe; led_delay(); //LED0亮
P3=0xfd; led_delay(); //LED1亮
P3=0xfb; led_delay(); //LED2亮
P3=0xf7; led_delay(); //LED3亮
P3=0xef; led_delay(); //LED4亮
P3=0xdf; led_delay(); //LED5亮
P3=0xbf; led_delay(); //LED6亮
P3=0x7f; led_delay(); //LED7亮
}
void backward(void) //函数:反向流水点亮LED
{
P3=0x7f; led_delay(); //LED7亮
P3=0xbf; led_delay(); //LED6亮
P3=0xdf; led_delay(); //LED5亮
P3=0xef; led_delay(); //LED4亮
P3=0xf7; led_delay(); //LED3亮
P3=0xfb; led_delay(); //LED2亮
P3=0xfd; led_delay(); //LED1亮
P3=0xfe; led_delay(); //LED0亮
}
void Alter(void) //函数:交替点亮高4位与低4位LED
{
P3=0x0f;
led_delay();
P3=0xf0;
led_delay();
}
void blink (void) //函数:闪烁点亮LED
{
P3=0xff;
led_delay();
P3=0x00;
led_delay();
}
void led_delay(void) //函数:延时
{
unsigned char i,j;
for(i=0;i<220;i++)
for(j=0;j<220;j++)
;
}
void delay10ms(void) //函数:软件消抖延时10ms
{
unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<100;j++);
}
void ledstate()
{
switch(keyval)
{
case 1:forward(); //键值为1,调用正向流水点亮函数
break;
case 2:backward(); //键值为2,调用反向流水点亮函数
break;
case 3:Alter(); //键值为3,调用高、低4位交替点亮函数
break;
case 4:blink (); //键值为4,调用闪烁点亮函数
break;
}
}
//键盘扫描和灯光操作可以合并为一个函数,还能省下sbit命名
/*void key(void)
{
P1=0xff;
if((P1&0x0f)!=0x0f)
{delay10ms();
switch(~(P1&0x0f))
{case 0xf1:forward(); //键值为1,调用正向流水点亮函数
break;
case 0xf2:backward(); //键值为2,调用反向流水点亮函数
break;
case 0xf4:Alter(); //键值为3,调用高、低4位交替点亮函数
break;
case 0xf8:blink (); //键值为4,调用闪烁点亮函数
break; }
}
} */
这里给大家展示了两个程序,第一个实例就是先检测按键的状态,然后用switch语句判断哪个键被按下,之后执行相应的点亮程序。第二个实例是把之前学过的LED点亮状态都封装成函数,然后在主程序里根据键盘的值执行相应的操作。
有两点需要注意
- delay10ms是到目前为止我们学习的第三个延时函数,作用是消抖,数量级为5~10k。
- 为了节省空间,按键个数一般少于8个,需要用按位与“&”屏蔽不需要的引脚来防止异常电位
按键控制LED点亮
下面是多功能按键控制LED的案例,与前文不同,该案例是通过记录按键按下的次数来改变LED状态的。,在这种情况下,就需要考虑按住按键不松手的情况,以免一直进行灯光切换。
#include <reg52.h>
sbit key=P3^0;
unsigned char ID;
void delay10ms(void)
{
unsigned char i,j;
for(i=20;i>0;i--)
for(j=248;j>0;j--);
}
void keyonoff()
{
if(key==0) //检测按键被按下
{
delay10ms(); //去抖
if(key==0)
{
ID++;
while(key==0); //防止按住不松手,等待按键释放
if(ID==4)
{
ID=0;
}
}
}
}
void displayled()
{
switch(ID)
{
case 0: P1=0x0e;break; //点亮D1,熄灭其它LED
case 1: P1=0x0d;break; //点亮D2,熄灭其它LED
case 2: P1=0x0b;break; //点亮D3,熄灭其它LED
case 3: P1=0x07;break; //点亮D4,熄灭其它LED
} //end switch
}
void main(void)
{ P1=0x0f;
while(1)
{
//按键识别程序
keyonoff();
//根据按键结果,输出程序
displayled();
}
}
这个模式在没有按键被按下的情况下点亮第一个LED作为标志,大家也可以自行更改case的值设置双击或全灭等操作,或者把前文封装的函数放在switch里执行更多的功能。
多功能按键控制LED点亮
以上就是按键控制LED灯点亮的过程,之后会介绍按键控制数码管显示的案例。谢谢大家。