按键在未按下时,处于一种高电平状态,一般这种情况下,其对IO口的电平一致,则不会产生任何效果,只有在按下状态时,由于与接地的回路贯通,故相当于单片机的IO口直接接地。从原理图上看,之所以要接KeyIn1-KeyIn4外接至按键中,主要原因是为了获取按键的状态,因为我们只能获取单片机的IO口状态,而不能直接获取按键本身是否按下的状态,所以只能通过这个电路,通过IO口接地的情况,人为造成IO为低电平,从而判断按键被按下,如果我们不细致地把这个原因考虑清楚,而仅仅只是按这种电路图直接连接的话,势必是知其然而不知其所以然。
现在我们有16个按键,通过四个Out和四个In进行组合,但我们需要明白一个问题,Out的主要目标是为了产生低电平,从而才能够使按键按下后,对地电路导通。那么,如何进行控制Out的电平呢?如果默认情况下全部为低电平可不可以?答案是不可以的,因为假定其全部为底电平,此时比如我如果按下key1,key5,那么都会导致KeyIn1为低电平,那么我们如何判定是按了key1还是key5呢?所以不能将其全部设定为低电平,更何况如果全部是低电平,还何必要它们从单片机的IO引出来呢,直接接地就可以了。这里其实还是利用了与点阵LED与数码管一样的原理,就是扫描的方式。逐个令Keyout1-keyout4循环为低,则此时对应的那一排key值如有按下,则对应的keyin起作用,而如果不在同一排则按键不起作用。
下面是我实现的一个在最右边的那个数码管显示按键值的示例代码,其值从0到F进行显示。
#include <reg52.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
//数码管的显示数字,从0至F一共16个字符
code uint8number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
code uint8 keys[] ={0xe7,0xd7,0xb7,0x77,0xeb,0xdb,0xbb,0x7b,0xed,0xdd,0xbd,0x7d,0xee,0xde,0xbe,0x7e};
uint8 k=0;
uint8 counter=0;
sbit ENLED = P1^4;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit KeyOut1 = P2^3;
sbit KeyOut2 = P2^2;
sbit KeyOut3 = P2^1;
sbit KeyOut4 = P2^0;
//初始化计数器1
void init_timer1()
{
TMOD|= 0x10;
TMOD&= 0xdf;
TH1 = 0xFC;
TL1 = 0x67;
TR1 = 1;
}
//初始化中断响应
void init_interrupt()
{
ET1= 1;
EA = 1;
}
void refresh_KeyOut()
{
static uint8 j = 0;
switch(j)
{
case0: KeyOut1=0;KeyOut2=1;KeyOut3=1;KeyOut4=1;break;
case1: KeyOut2=0;KeyOut1=1;KeyOut3=1;KeyOut4=1;break;
case2: KeyOut3=0;KeyOut1=1;KeyOut2=1;KeyOut4=1;break;
case3: KeyOut4=0;KeyOut1=1;KeyOut2=1;KeyOut3=1;break;
default:break;
}
if(3 == j++) j = 0;
}
uint8 temp=0;
uint8 j=0;
uint8 i=0;
main()
{
ENLED= 0; ADDR3 = 1;
init_timer1();
init_interrupt();
ADDR0=0;
ADDR1=0;
ADDR2=0;
while(1)
{
temp= P2;
i=0;
for(;i<16;i++)
{
if(temp== keys[i])
{
j=i;
break;
}
}
P0=number[j];
}
}
void interrupt_timer1() interrupt 3
{
TH1 = 0xFC;
TL1 = 0x67;
if(10==counter++)
{
//切换KeyOut的输出,如果太快,则很难把握用户到底按下了
//哪个按,只能在一段延时的情况下,进行判断用户按下了哪个键
counter=0;
refresh_KeyOut();
}
}
上面代码中的keys数组所保存的是P2在不同按键时的值。其来源是通过如下方法获得的:
P2 7 6 5 4 3 2 1 0
In4 In3 In2 In1 Out1 Out2 Out3 Out4
k1 1 1 1 0 0 1 1 1 =0xe7=0
k2 1 1 0 1 0 1 1 1 =0xd7=1
k3 1 0 1 1 0 1 1 1 =0xb7=2
k4 0 1 1 1 0 1 1 1 =0x77=3
k5 1 1 1 0 1 0 1 1 =0xeb=4
k6 1 1 0 1 1 0 1 1 =0xdb=5
k7 1 0 1 1 1 0 1 1 =0xbb=6
k8 0 1 1 1 1 0 1 1 =0x7b=7
k9 1 1 1 0 1 1 0 1 =0xed=8
k10 1 1 0 1 1 1 0 1 =0xdd=9
k11 1 0 1 1 1 1 0 1 =0xbd=a
k12 0 1 1 1 1 1 0 1 =0x7d=b
k13 1 1 1 0 1 1 1 0 =0xee=c
k14 1 1 0 1 1 1 1 0 =0xde=d
k15 1 0 1 1 1 1 1 0 =0xbe=e
k16 0 1 1 1 1 1 1 0 =0x7e=f