先附上protues仿真的原理图
首先要明白矩阵键盘的原理,由原理图可以看出矩阵键盘的值是要让端口赋值的,它不像独立键盘。独立键盘是有接地的。
那我们要怎么确认是哪一个按键按下呢?
很简单,只要确定按下的是哪一行哪一列就可以知道是哪个按键按下了,这个就是矩阵键盘最基本的原理。(形象一点的话可以画四条横线,然后在四条横线上画四条竖线,两线交叉的地方为一个点这样就是4×4十六个点)
我看的是郭天祥的书,在矩阵键盘这里,书上的方法很简单易懂,但是过于繁琐,我想把它简化一下。
首先要挖掘一下书上代码有哪些地方是有规律可以整合的,我发现主要的思路是这样的:
1.P3=0xfe(选中了第一行)
2.temp=P3&0xf0(temp取P3的列)
3.判断第一行是否有按键按下if(temp!=0xf0)(这里解释一下:因为第一行已经被选中置0了,只要我们按下第一行中的任一按键,4列就一定会有一行置0)
4.等待按键释放
5.P3=0xfd…重复上面的操作
总结一下:
定义一个行变量i,列变量j,一开始i=j=0,整体思路就是先选中第一行,判断第一行有没有按下的,有——直接送出4*i+j(此时i=0,是第一列j=0,第二列j=1,以此类推)选中是哪个数字;没有——i++,然后p3选中第二行判断第二行有没有按下,重复上面的操作。
举个栗子:
我按下了第三行第三列的按键。
首先选中第一行开始扫描,发现我的列没有变化,说明不在第一行,i++到第二行,选中第二行发现列还是没变化,说明不在第二行,i++到第三行,选中第三行判断列是否有变化,这次有变化了,因为我按的是第三行三列,当选中第三行的时候,第三行为0按下第三列按键,第三列也被置为0,检测出变化之后j锁定为2,此时4×2+2=10,选中数组表中第十个元素,输出到数码管中显示A(为什么是A呢因为我是按照最左上角的那个按键是0,往右是1、2…,所以地三行三列是10,也就是A)
下面贴上我的代码:
矩阵键盘代码:
/*****************************************
4.4
代码功能:
一个4×4的的矩阵式键盘,以P3.0~P3.3作
为行线,以P3.4~P3.7作为列线,在数码管上显示
每个按键相应的键值"0~F"
实体机接线:
P3端口(J29)接矩阵按键(JP3)
P0端口(J22)接单个数码管(J8)
********************************************/
#include
#define uchar unsigned char
#define uint unsigned int
#include //包含_crol_函数所在的头文件
uchar code table[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};//0-F数字
void matrixkeyscan()
{
uchar code table1[4][4] = {0xee, 0xde, 0xbe, 0x7e, 0xed, 0xdd, 0xbd, 0x7d,
0xeb, 0xdb, 0xbb, 0x7b, 0xe7, 0xd7, 0xb7, 0x77};//用2维数组,表示位置
uchar temp1=0xfe,temp2,i,j;
for(i = 0; i < 4; i++) //扫描低四位,即扫描行
{
P3=temp1; //输出一行0
temp2=P3; //马上就读入按下的状态
if((temp2 & 0xf0) != 0xf0) //判断按键是否按下
{
for(j=0;j<4;j++) //扫描高四位
if(temp2==table1[i][j]) //查表,找到是哪个位置
P0=table[(4*i+j)]; //查到了就返回按键的数值
}
else temp1 = _crol_(temp1, 1); //用循环左移来改变选中哪一行
}
}
void main()
{
P0=0xff; //数码管消影
while(1)
{
matrixkeyscan();
}
}
还另外看到几种方法,分享学习一下
行反转法的基本概念是:
行列线的交叉位置布置按键。所有行和列加上拉电阻。
所有行作输出先送低电平,然后读入列值。 如果有任意键按下,那么一定对应列值有0出现,也就知道了按下的键所在列。
反过来驱动这一列为0,其他列为1。把行作输入。就可以判断按下的键所在行。
uchar keyscan()
{
uchar i=0,j=0,key;
P3=0xf0; // 高位拉高,低位拉低
if(((~P3)&0xf0)!=0)
{
delay(10);
if(((~P3)&0xf0)!=0)
{
P3=0xfe;
while(((~P3)&0x0f)!=0) // 此语句保证只扫描四行
{
if(((~P3)&0xf0)!=0)
{
switch((~P3)&0xf0)
{
case 0x10:
j=0;break;
case 0x20:
j=1;break;
case 0x40:
j=2;break;
case 0x80:
j=3;break;
}
return(4*i+j);
}
else
{
P3=P3<<1; //循环4次
i++;
}
}
}
}
return (key) ;
}
/**************************************************************
* 名称:KeyRvs()
* 功能:P1外接4×4按键, 按照反转法读出键值
* 输出:按键值0~15/如无键按下, 返回16
*按键的键值分布图:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
***************************************************************/
uchar keyscan(void)
{
uchar temH, temL;
uchar key_value;
P3 = 0xf0;
if(P3 != 0xf0)
{
delay(5); //消抖
if(P3 != 0xf0) //的确是有按键被按下
{
P3 = 0xf0; temH = P3; //低四位先输出0;读入,高四位含有按键信息
P3 = 0x0f; temL = P3; //然后反转输出0;读入,低四位含有按键信息
switch(temH) {
case 0xe0: key_value = 0; break;
case 0xd0: key_value = 1; break;
case 0xb0: key_value = 2; break;
case 0x70: key_value = 3; break;
default: return 16;//按下的不是上述按键,就当是没有按键
}
switch(temL)
{
case 0x0e: return key_value;
case 0x0d: return key_value + 4;
case 0x0b: return key_value + 8;
case 0x07: return key_value + 12;
default: return 16;//按下的不是上述按键,就当是没有按键
}
}
}
}//本程序虽然稍多几行,但是没有循环,还可以提前返回,所以执行的速度最快