一.原理图
二.原理图分析
如上图,用跳线帽连接J5的1和2,此时为矩阵键盘模式。即P3.7口与左侧4个按键的左端相连,此时可发现P3.0-3确定行,P3.4-7确定列。以S6为例,当S6按下时,P3.1与P3.7相连,此时通过行列便可确定按键。具体实现看代码。
三.代码
状态机:
#define KEY P3
#define key_state_0 0 //判断按键是否按下
#define key_state_1 1 //判断按键是否是抖动
#define key_state_2 2 //判断按键是否弹起
char Key_Read(void)
{
static char key_state = 0;
unsigned char key_return=0, key_press;
unsigned char key1,key2;
KEY=0xf0;
key1=KEY&0xf0;
KEY=0x0f;
key2=KEY&0x0f;
key_press =key1|key2;
//使用stc15转接板时,需要把上述代码换成下面的,因为P3.6,P3.7此时被换成了P4.2和P4.4
// P30=0;P31=0;P32=0;P33=0;P34=1;P35=1;P42=1;P44=1;
// if(P44==0) key1=0x70;
// if(P42==0) key1=0xb0;
// if(P35==0) key1=0xd0;
// if(P34==0) key1=0xe0;
// if((P34==1)&&(P35==1)&&(P42==1)&&(P44==1)) key1=0xf0;
// P30=1;P31=1;P32=1;P33=1;P34=0;P35=0;P42=0;P44=0;
// if(P30==0) key2=0x0e;
// if(P31==0) key2=0x0d;
// if(P32==0) key2=0x0b;
// if(P33==0) key2=0x07;
// if((P30==1)&&(P31==1)&&(P32==1)&&(P33==1)) key2=0x0f;
// key_press=key1|key2;
switch(key_state)
{
case key_state_0:
if(key_press!=0xff) key_state=key_state_1;
break;
case key_state_1:
if(key_press!=0xff)
{
if(key_press==0xde) key_return=15; //S15
if(key_press==0xdd) key_return=14; //S14
key_state=key_state_2;
}
else
key_state=key_state_0;
break;
case key_state_2:
if(key_press==0xff) key_state=key_state_0;
break;
}
return key_return;
}
对其中较难理解的一段进行解释:
KEY=0xf0;
key1=KEY&0xf0;
//先设置P3.0~3为低电平,P3.4~7为高电平
//此时若某个按键被按下,与其相连的两个I/O口,
//便会因为其中一个为低电平,另外一个也被强制拉低
//例如:当S6被按下,由于P3.1为低电平,P3.7便被拉低,
//则KEY变成0x70,key1即为0x70,此时便确定了按键所在的列
KEY=0x0f;
key2=KEY&0x0f;
//先设置P3.4~7为低电平,P3.0~3为高电平
//此时若某个按键被按下,与其相连的两个I/O口,
//便会因为其中一个为低电平,另外一个也被强制拉低
//例如:当S6被按下,由于P3.7为低电平,P3.1便被拉低,
//则KEY变成0x0d,key2即为0x0d,此时便确定了按键所在的行
key_press =key1|key2;
//key_press通过key1或key2,将行列的信息合并,每个按键便只有唯一值与其对应
通过定时器实现消抖,与独立按键相同:
unsigned char key_return; //按键返回值
unsigned char key_flag; //消抖标记
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void main()
{
Timer0Init(); // 1ms定时器
EA=1; //打开总中断
ET0=1; //打开定时器0中断
while(1)
{
if(key_flag==1)
{
key_flag=0;
key_return=Key_Read();
switch(key_return)
{
case 4:
case 5:
case 6:
case 7:
}
}
}
}
void Time0_Interrupt(void) interrupt 1
{
static unsigned char count=0;
count++;
if(count==10) //10ms
{
count=0;
key_flag=1;
}
}