1.电路结构
行线Row0~3接到P0.0~P0.3端口,通过4个1K上拉电阻接+5V,置“1”,作为输入状态;列线Col0~3接到P2.0~P2.3端口,作为输出状态。按键设在行、列交点上。
2.原理:扫描法---逐一送低电平
在某一时刻只让一条列线处于低电平,均其余列线处于高电平。则当这一列有按键按下时,该键所在的行电平将会有高电平变为低电平,可判定该列相应的行有键按下。
/*流程:当第0列处于低电平时,逐行查找是否有行线变低,若有,则第0列与该行的交叉点按键按下;若无,则表示第0列无键按下,再让下一列处于低电平,依次循环。
键值 =行号*4+列号 //KeyNum =Row*4+Col
/*第0列送低电平:若第0列无按键按下,则P0=0xff,temp=0x00。//temp=P0;temp=~temp%0x0f
若第0列第0行按键按下P0不全高,temp=0x01,Row=0,Col=0,KeyNum=Row*4+Col =0----可知按键0按下。
若第1列第0行按键按下P0不全高,temp=0x01,Row=0,Col=1,KeyNum=Row*4+Col =1----可知按键1按下。
若第2列第0行按键按下P0不全高,temp=0x01,Row=0,Col=2,KeyNum=Row*4+Col =2----可知按键2按下。
若第3列第0行按键按下P0不全高,temp=0x01,Row=0,Col=3,KeyNum=Row*4+Col =3----可知按键3按下。
若第0列第1行按键按下P0不全高,temp=0x02,Row=1,Col=0,KeyNum=Row*4+Col =4----可知按键4按下。
若第0列第2行按键按下P0不全高,temp=0x04,Row=2,Col=0,KeyNum=Row*4+Col =8----可知按键8按下。
........
3.程序源码
//功能:矩阵键盘扫面程序
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar code Table[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//LED码表
void KeyScam();//键盘扫描函数
void main()
{
uchar KeyNum; //按键值变量
while(1)
{
KeyNum =KeyScam(); //调用扫描函数
P3 =Table[KeyNum]; //显示按键值,显示数码管接到P3口
}
}
//扫描子程序
//返回值:KeyNum
void KeyScam()
{
uint Row,Col,KeyNum,j,temp; //定义行、列、返回值、temp-临时变量存储P0状态
P0 =0xff; //P0初始状态
for(j =0;j<4;j++) //分4次(列)扫描
{
P2 =0xfe<<j; //扫描列扫描码P2口(低4位),每次扫描一次
temp =P0; //读回行值
temp =~temp&0x0f; //读回行值取反,并去掉高4位
if(temp !=0x00) //如果读回行值为0则没有按键按下
{
Delay(5); //消抖延时
temp =P0; //读回行值
temp =~temp&0x0f; //读回行值取反,并去掉高4位(P0.4~0.7没有用到,故去掉)
if(temp !=0x00) //如果读回行值为0则没有按键按下
{
Col =j; //保存列值
switch(temp) //确定被按下的键所在第几行
{
case 0x01:Row =0;break; //读取值是0x01,说明按下的键在第0行,Row=0
case 0x02:Row =1;break; //读取值是0x02,说明按下的键在第1行,Row=1
case 0x04:Row =2;break; //读取值是0x04,说明按下的键在第2行,Row=2
case 0x08:Row =3;break; //读取值是0x08,说明按下的键在第3行,Row=3
default:break; //读取值是其他参数不处理
}
break; //已经确定行列值,提前结束扫描
}
}
}
KeyNum =Row*4+Col; //确定键值,公式计算
return KeyNum; //键值返回主函数
}