两种方式实现矩阵键盘扫描(含程序)
1 矩阵键盘的结构下图是一个4*3的矩阵键盘示意图,三条列线连接P1.4-P1.6引脚。四条行线连接P1.0-P1.3引脚2 逐行逐列扫描法首先使三条列线所连接的I/O引脚P14-P16输出低电平,四条行线所连接的I/O引脚P10-P13输出高电平。当没有按键按下时,四条行线所连接的I/O引脚读取到的将全部是高电平;而当有按键按下时,由于该按键所在的行线与列线接通,行线将被下拉到低电平。此时读取行
1 矩阵键盘的结构
下图是一个4*3的矩阵键盘示意图,三条列线连接P1.4-P1.6引脚。四条行线连接P1.0-P1.3引脚
2 逐行逐列扫描法
首先使三条列线所连接的I/O引脚P14-P16输出低电平,四条行线所连接的I/O引脚P10-P13输出高电平。当没有按键按下时,四条行线所连接的I/O引脚读取到的将全部是高电平;而当有按键按下时,由于该按键所在的行线与列线接通,行线将被下拉到低电平。此时读取行线所连接的引脚P10-P13,将不再全是高电平,由此可以判断出有按键按下。判断有按键按下后,还要用逐行逐列扫描法来获取按键的键值。
逐行逐列扫描法的原理是:逐列将列线依次置低电平,读取行线,如果某一条行线为低电平,则说明该行线与当前置为低电平的列线交叉点处的按键被按下,从而可以获取按键的键值。
#define keyboard P1 //四条行线三条列线所连接的IO口
unsigned char Check_Keyboard()
{
unsigned char row_scan_code=0x01; //行扫描码
unsigned char col_scan_code=0xEF;//列扫描码
unsigned char keycode; //按键键值
unsigned char i,x,j;
//可以做一个消抖处理
for(i=0;i<3;i++)//逐列扫描,将列线逐列拉低
{
keycode=i+1;
keyboard=col_scan_code;
x=keyboard; //读取行线状态
for(j=0;j<4;j++)//逐行扫描
{
if(!(x&row_scan_code))//说明对应行的按键按下,使行线被拉低
{
keycode+=3*j;
//如果按键还未释放,则仍有行线被拉至低电平
while((keyboard&0x0f)!=0x0f);//等待按键释放
P1=0x0F; //恢复原状态,为下次按键做准备
return keycode; //已检测到按键键码,返回
}
else
row_scan_code=_crol_(row_scan_code,1);
}
col_scan_code=_crol_(col_scan_code,1);//左移一位,将下一列线拉低
row_scan_code=0x01;//重置行扫描码,为下一行扫描作准备
}
keycode=0;//没有按键按下,键值记为0
return keycode;
}
3 线反法
上面逐行逐列扫描法较为繁琐,在实际的单片机系统中更常用的是线反法。
线反法的原理为:首先使P1口的高四位输出高电平,P1口低四位输出低电平,这时键盘的行线被拉高,列线被拉低。如果有按键按下,则某一条行线将被拉低,此时读取P1口高四位,读取到的将不再全为高电平,说明有按键按下。(在判断是否有按键按下这一点上,线反法与逐行逐列扫描法是一致的)根据读取到0值的I/O口所连接的行线,就可以判断出按下的按键位于哪一行。接下来使P1口的高四位输出低电平,P1口低四位输出高电平(即与上次输出的电平相反,因此称为线反法)。如果有按键按下,此时读取P1口低四位,读取到的将不再全为高电平,根据读取到0值的I/O口所连接的列线,就可以判断出按下的按键位于哪一列。综合按键所在的行线与列线,即可唯一确定按键所在位置,进而获取按键的键值。
//@brief:判断4*4矩阵键盘是否有键可靠按下,高4位口接行线,低四位口接列线
//@retval:当有键可靠按下时返回1-16的键值,否则返回0
#define keyboard P1
unsigned char Check_Keydown()
{
unsigned char KeyValue=0;
keyboard=0x0f;
if(keyboard!=0x0f)//如果按键按下
{
delay_ms(10);//延时10ms消抖
if(keyboard!=0x0f)//按键确实按下
{
//判断按键所在列,以所在列的第一行的按键键值赋给KeyValue
keyboard=0X0F;
switch(keyboard)
{
case(0X07): KeyValue=1;break; //第一列按下
case(0X0b): KeyValue=2;break; //第二列按下
case(0X0d): KeyValue=3;break; //第三列按下
case(0X0e): KeyValue=4;break; //第四列按下
}
//判断按键所在行
keyboard=0XF0;
switch(keyboard)
{
case(0X70): KeyValue=KeyValue;break; //第一行按下
case(0Xb0): KeyValue=KeyValue+4;break; //第二行按下
case(0Xd0): KeyValue=KeyValue+8;break; //第三行按下
case(0Xe0): KeyValue=KeyValue+12;break; //第四行按下
}
while(keyboard!=0xf0); //按键松手后退出
return KeyValue;
}
else //否则认为是信号干扰导致
{
return 0; //认为没有按键按下
}
}
return 0; //如果没有按键按下返回零
}
更多推荐
所有评论(0)