矩阵键盘扫描一般采取行列扫描法。比如先拉低所有列线,拉高行线,之后读取行线状态,如果行线有一行为低,则假设有按键按下,此时再延时20毫秒左右后判断 行线的某一行是否仍然为低,若为低则确认有键按下。这时可以进行按键键值判断,即判别在哪一行哪一列有按键按下。判断的方法是通过拉高列线,依次置行线的 某一行为低,读取列线值。如果列线有一列为低,则表示按键发生在该行,进而可以通过读取到的列线值确定在哪一列,从而确定按键发生在具体的行和列。为了防 止按键按下后一直有按键被读取,需要在程序中设定在按键被释放后才能读取具体的键值来避免这一问题。
代码如下:
#include<reg52.h>
#include<stdio.h>
#define KEY_PORT P2 //矩阵键盘端口,其中P2.0-P2.3为列线,P2.4-P2.7为行线
typedef unsigned char uchar;
typedef unsigned int uint;
void serial_init(void) //串口初始化函数
{
TMOD = 0x20; //T1工作方式1,用于设定波特率
TH1 = 0xF3; //波特率4800Bps,12MHz晶振
TL1 = 0xF3;
PCON |= 0x80; //SMOD = 1,波特率加倍
SCON = 0x50; //允许发送接收
ES = 0; //禁止串口中断
TI = 1;
TR1 = 1;
}
uchar key_scan(void) //键盘扫描函数,有键按下则返回1,否则返回0
{
uchar keyPressed = 0;
KEY_PORT = 0xF0; //置低列线,以读取行线判断是不是有键按下
keyPressed = KEY_PORT & 0xF0; //读取行线值
if(keyPressed == 0xF0) //无键按下
return 0;
else
return 1; //有键按下
}
uchar key_assert(void) //键值判断函数,第半字节存列号,高半字节存行号
{
uchar keyvalue; //按键键值存储变量,高四位代表行线位置,低四位代表列线位置
KEY_PORT = 0xEF;//拉低第一行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第一行的键被按下,确认在哪一列
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return keyvalue | 0xE0;
}
KEY_PORT = 0xDF; //拉低第二行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第二行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0xD0);
}
KEY_PORT = 0xBF; //拉低第三行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第三行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0xB0);
}
KEY_PORT = 0x7F; //拉低第四行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第四行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0x70);
}
}
void Hardware_Delay_1ms(void) //硬件定时器延时1ms函数
{
TMOD &=0xF0;
TMOD |=0x01; //T0——16位定时器器模
TH0 = 0xFC;
TL0 =0x18; //64536
TF0=0; //清除定时器溢出标志
TR0=1; //启动定时器
while(TF0==0);//等待计数完成
TR0=0; //停止定时器
}
void Delay_Nms(uint N) //延时N毫秒函数
{
uint j;
for(j=N;j>0;j--)
Hardware_Delay_1ms();
}
void main(void)
{
uchar key_value = 0; //键值
serial_init();
while(1)
{
if(key_scan())
{
Delay_Nms(20); //延时20ms,去抖
if(key_scan()) //确实有键按下,读取键值
key_value = key_assert(); //读取P2值做判断
P1 = key_value; //通过LED显示键值
switch(key_value)//通过串口打印哪个按键被按下信息
{
case 0xEE:
printf("Key 1 pressed!/n");
break;
case 0xED:
printf("Key 2 pressed!/n");
break;
case 0xEB:
printf("Key 3 pressed!/n");
break;
case 0xE7:
printf("Key 4 pressed!/n");
break;
case 0xDE:
printf("Key 5 pressed!/n");
break;
case 0xDD:
printf("Key 6 pressed!/n");
break;
case 0xDB:
printf("Key 7 pressed!/n");
break;
case 0xD7:
printf("Key 8 pressed!/n");
break;
case 0xBE:
printf("Key 9 pressed!/n");
break;
case 0xBD:
printf("Key 10 pressed!/n");
break;
case 0xBB:
printf("Key 11 pressed!/n");
break;
case 0xB7:
printf("Key 12 pressed!/n");
break;
case 0x7E:
printf("Key 13 pressed!/n");
break;
case 0x7D:
printf("Key 14 pressed!/n");
break;
case 0x7B:
printf("Key 15 pressed!/n");
break;
case 0x77:
printf("Key 16 pressed!/n");
break;
}
}
}
}
代码如下:
#include<reg52.h>
#include<stdio.h>
#define KEY_PORT P2 //矩阵键盘端口,其中P2.0-P2.3为列线,P2.4-P2.7为行线
typedef unsigned char uchar;
typedef unsigned int uint;
void serial_init(void) //串口初始化函数
{
TMOD = 0x20; //T1工作方式1,用于设定波特率
TH1 = 0xF3; //波特率4800Bps,12MHz晶振
TL1 = 0xF3;
PCON |= 0x80; //SMOD = 1,波特率加倍
SCON = 0x50; //允许发送接收
ES = 0; //禁止串口中断
TI = 1;
TR1 = 1;
}
uchar key_scan(void) //键盘扫描函数,有键按下则返回1,否则返回0
{
uchar keyPressed = 0;
KEY_PORT = 0xF0; //置低列线,以读取行线判断是不是有键按下
keyPressed = KEY_PORT & 0xF0; //读取行线值
if(keyPressed == 0xF0) //无键按下
return 0;
else
return 1; //有键按下
}
uchar key_assert(void) //键值判断函数,第半字节存列号,高半字节存行号
{
uchar keyvalue; //按键键值存储变量,高四位代表行线位置,低四位代表列线位置
KEY_PORT = 0xEF;//拉低第一行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第一行的键被按下,确认在哪一列
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return keyvalue | 0xE0;
}
KEY_PORT = 0xDF; //拉低第二行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第二行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0xD0);
}
KEY_PORT = 0xBF; //拉低第三行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第三行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0xB0);
}
KEY_PORT = 0x7F; //拉低第四行
if((keyvalue = KEY_PORT & 0x0F) != 0x0F) //第四行的键被按下
{
while((KEY_PORT & 0x0F) != 0x0F); //等待按键释放
return (keyvalue | 0x70);
}
}
void Hardware_Delay_1ms(void) //硬件定时器延时1ms函数
{
TMOD &=0xF0;
TMOD |=0x01; //T0——16位定时器器模
TH0 = 0xFC;
TL0 =0x18; //64536
TF0=0; //清除定时器溢出标志
TR0=1; //启动定时器
while(TF0==0);//等待计数完成
TR0=0; //停止定时器
}
void Delay_Nms(uint N) //延时N毫秒函数
{
uint j;
for(j=N;j>0;j--)
Hardware_Delay_1ms();
}
void main(void)
{
uchar key_value = 0; //键值
serial_init();
while(1)
{
if(key_scan())
{
Delay_Nms(20); //延时20ms,去抖
if(key_scan()) //确实有键按下,读取键值
key_value = key_assert(); //读取P2值做判断
P1 = key_value; //通过LED显示键值
switch(key_value)//通过串口打印哪个按键被按下信息
{
case 0xEE:
printf("Key 1 pressed!/n");
break;
case 0xED:
printf("Key 2 pressed!/n");
break;
case 0xEB:
printf("Key 3 pressed!/n");
break;
case 0xE7:
printf("Key 4 pressed!/n");
break;
case 0xDE:
printf("Key 5 pressed!/n");
break;
case 0xDD:
printf("Key 6 pressed!/n");
break;
case 0xDB:
printf("Key 7 pressed!/n");
break;
case 0xD7:
printf("Key 8 pressed!/n");
break;
case 0xBE:
printf("Key 9 pressed!/n");
break;
case 0xBD:
printf("Key 10 pressed!/n");
break;
case 0xBB:
printf("Key 11 pressed!/n");
break;
case 0xB7:
printf("Key 12 pressed!/n");
break;
case 0x7E:
printf("Key 13 pressed!/n");
break;
case 0x7D:
printf("Key 14 pressed!/n");
break;
case 0x7B:
printf("Key 15 pressed!/n");
break;
case 0x77:
printf("Key 16 pressed!/n");
break;
}
}
}
}