一、独立按键的处理
(1)轮询方式
这种方式需要CPU不断地去检测用户的按键是否按下,CPU对于按键什么时候按下是未知的,因此就需要不断地去检测,而且检测的周期需要的时间不能太长,不然会错过用户的按键。也不能太短不然CPU的资源都会浪费在这个地方。
(2)中断方式
如果我们需要同时运行的函数比较少的话,使用轮询是可以的,但是如果我们运行的函数过多,就会导致按键的反应会很不灵敏,或者根本就检测不到按键的按下。因此就需要使用一种新的方式来进行,那就是中断。想要在中断里面处理需要注意:代码不能太多,不然会影响其他任务的执行。中断这种方式需要外部进行触发,如果没有触发是不会去运行中断处理程序的,一般会有低电平触发和下降沿触发。如果没有发生中断CPU一直会去处理主程序。
二、轮询方式编程
首先我们通过看原理图发现,所有的独立按键都是一端接地,另一端接在一个端口上。首先我们这里将这个端口接到P1端口上。如果有按键按下,则对应的端口的值会变成0,否则这个按键没有被按下。不同的返回值对应着不同的按键被按下。这种方法是将检测按键和处理按键分开处理,这样当我们想使用按键的时候只需要进行按键的处理函数的编写即可。
//使用轮询的方式进行独立按键的检测
u8 jiance_lunxun(void)
{
if (key1 == 0) //如果按下的是按键1,则返回1
{
return 1;
}
else if (key2 == 0) //其他的按键返回值同理即可
{
return 2;
}
}
但是我们这样处理按键会有两个问题,首先当我们按下按键时,由于硬件电路的问题,会产生很多杂散的波形。也就是我们虽然按下去了,但是由于硬件的原因他并不会直接就变成低电平,而是会经历一个波动才会变成低电平。这样我们的然间就会误判,导致多次的相应。这个问题的解决方法就是当CPU以为有一个按键响应来时,我们先延时一段时间,将那一段波动给放过去,然后在进行判断就可以了。还有一个问题就是当我们一直按下按键的时候,就会一直进行响应,当我们只想按一次相应一次时,我们就需要按的特别快,但是我们怎么可能有电脑快呢。因此我们就需要添加一个标志位,用来判断按键的状态,这样当一次按键只有按下而没有抬起时,就不会进行多次相应。而只会相应一次。下面是代码:注意我只处理了前3个按键,其他的都类似。
u8 flag[8] = 0; //按键标志位 1表示按键被按下 0表示没有按下
//数组不同的位分别表示不同的按键状态
void delay20ms(void) //误差 0us
{
unsigned char a,b;
for(b=215;b>0;b--)
for(a=45;a>0;a--);
}
//使用轮询的方式进行独立按键的检测
u8 jiance_lunxun(void)
{
/****************************************************/
if (key1 == 0) //如果按下的是按键1,则返回1
{
delay20ms();
if (key1 == 0 && flag[0] == 0)
{
flag[0] = 1;
return 1;
}
}
else
{
flag[0] = 0;
}
/****************************************************/
if (key2 == 0) //如果按下的是按键1,则返回1
{
delay20ms();
if (key2 == 0 && flag[1] == 0)
{
flag[1] = 1;
return 2;
}
}
else
{
flag[1] = 0;
}
/****************************************************/
if (key3 == 0) //如果按下的是按键1,则返回1
{
delay20ms();
if (key3 == 0 && flag[2] == 0)
{
flag[2] = 1;
return 3;
}
}
else
{
flag[2] = 0;
}
/****************************************************/
if (key4 == 0) //其他的按键返回值同理即可
{
return 4;
}
/****************************************************/
if (key5 == 0) //其他的按键返回值同理即可
{
return 5;
}
/****************************************************/
if (key6 == 0) //其他的按键返回值同理即可
{
return 6;
}
/****************************************************/
if (key7 == 0) //其他的按键返回值同理即可
{
return 7;
}
/****************************************************/
if (key8 == 0) //其他的按键返回值同理即可
{
return 8;
}
三、中断方式编程
#include <shumaguan.h>
#include "anjian.h"
sbit LED = P2^3;
u8 flag1 = 0; //LED亮灭标志位1亮 0灭
void main(void)
{
u8 temp = 0, i = 0;
EA = 1; //打开总中断
IT0 = 1; //配置外部中断0为,下降沿触发
EX0 = 1; //打开外部中断0的开关
while(1)
{
ShuMaGuanShow(2, temp);
ShuMaGuanShow(1, temp+1);
if (i == 200)
{
temp++;
i = 0;
}
if (temp > 14)
{
temp = 0;
}
i++;
}
}
void key_int0(void) interrupt 0
{
if (flag1 == 0)
{
LED = 0;
flag1 = 1;
}
else if (flag1 == 1)
{
LED = 1;
flag1 = 0;
}
}
首先我们需要打开一些中断开关和一些触发的方式。然后我们再写中断处理函数就完成了,这个程序的主任务是动态的更新数码管的显示,然后接受到外部中断后,LED进行亮灭。数码管的显示函数前面提到过,就不再赘述了。这里我们主要考虑的是如何使用中断。
四、矩阵键盘的处理
首先我们先看矩阵键盘的原理图,我们可以看到这个矩阵键盘是由一个端口就可以进行控制的,那么我们该如何对他进行编程呢?首先我们呢如果给这4个H高电平,4个L低电平,那么当按键S1,S2,S3,S4其中任何一个被按下都会导致,H1变成低电平。这时候我们是不能准确的去进行判断的。我们只能通过H1变成低电平知道是哪一行,的那具体是哪一个还不能知道。因此如果我们再来一次给4个H低电平,4个L高电平。通过上面的原理我们能知道,这样做可以锁定是那一列 被按下了,这样将他们两个同时使用就可以锁定是哪个按键被按下了。比如我们用S2被按下举个例子,我们第一次判断的时候H1从高电平变成了低点评,第二次判断的时候L2从高电平变成了低电平。下面我们使用这个方法进行编程。
//#include <reg51.h>
#include <intrins.h>
#include "shumaguan.h"
//#include "dainzhen.h"
#include "anjian.h"
void main(void)
{
u8 temp = 0;
while(1)
{
JUZHEN = 0xf0;
switch (JUZHEN){
case 0x70:temp = 4;break;
case 0xb0:temp = 3;break;
case 0xd0:temp = 2;break;
case 0xe0:temp = 1;break;
}
JUZHEN = 0x0f;
switch (JUZHEN){
case 0x07:temp += 12;break;
case 0x0b:temp += 8;break;
case 0x0d:temp += 4;break;
case 0x0e:temp += 0;break;
}
ShuMaGuanShow(0, temp-1);
}
}
我们这里使用了一个变量temp来给每个按键对应一个编号,不同的按键按下,temp的值是不同的,最后将结果显示在数码管上面。JUZHEN这个变量表示的是一个端口我使用是宏定义。