矩阵键盘应该是一个常用设备,4X4矩阵键盘只需要8个I/o端口就可以完成16位密钥的读取。 其本质原理是矩阵扫描。 在本文中,您将详细学习矩阵键盘的原理和代码编写。
矩阵键盘的本质:矩阵键盘本质是使用8个io口来进行16个按键的控制读取,可以减小io口的使用,用4条I/O线作为行线,4条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上,设置一个按键。而这样的按键中按键的个数是4 X 4个。
这种矩阵式键盘结构可以有效地提高单片机系统中I/O端口的利用率。 节约单片机资源,其本质与独立按钮相似。 进行逐行扫描和逐列扫描,然后判断是第几行的第几列按钮,确定整体按钮是值得的。 我们使用的矩阵键盘通过接收单片机的P1端口读取P1端口的电平转换来完成矩阵键盘的数值读取。 具体原理图如下。
第1行与p17连接,第2行与p16连接,第3行与p15连接,第4行与p14连接
第1列与p13连接,第2列与p12连接,第3列与p11连接,第4列与p10连接
矩阵扫描的方式有两种。1.行列扫描,2.逐行/逐列扫描
其中行列扫描适用于8个IO口接到了单片机8个连续的IO口,则可以进行行列扫描
逐行/逐列扫描 适用于矩阵键盘接到了任意的IO口,则使用逐行,逐列扫描
接下来,我将介绍这两种方法。
矩阵扫描:原理
先从P1口的高四位(四个行)输出高电平,低四位(四个列)输出低电平,假设有按键按下,从P1口的高四位读取键盘状态。判断高四位的四行哪一行变成了低电平,就知道是第几行,再从P1口的低四位(四个列)输出高电平,高四位(四个行)输出低电平,从P1口的低四位读取键盘状态。判断低四位的四列哪一行变成了低电平,就知道是第几列,将两次读取结果组合起来就可以得到当前按键的特征编码。使用上述方法我们得到16个键的特征编码。
红色高电平,蓝色低电平
详解
根据矩阵键盘原理图,如果矩阵键盘的8个IO端口连接到每个连续的P10-P17,则当未按下键时,为将P1口的P1^0 和 P13 置高电平 P14 和 P17 置低电平 ,也就是将4个行的IO口置高,4个列的IO口置低。或http://www.sinn
此时,如果有键,则P1^0和P13中的某一个为低电平。 因此,P1的值不等于0x0f,并且按下键的行变为低电平,从而能够判断为存在键按下。
P1=0x0f(0000 1111)
http://www.Sina.com/http://www.Sina.com/http://www.Sina.com /
将对应P1口的值和0x0f(00001111)相 与 则可以得到高四位第几行变成了0
示例: http://www.Sina.com/http://www.Sina.com/http://www.Sina.com/3358 www.Sina.com /
进而向P1端口分配0X0f。按位“与”(双目运算符):仅当两个操作数都为1时,结果为1,否则为0此时的P1端口(比方说: 00=0;01=0;10=0;11=1) ) ) ) )。
即:两个同时为1,结果为1,否则为0
例如,假设按了1x1键,即第一行的第一列。 在这种情况下,按下后可以看到p1.0和p1.3都处于低电平。 Row=P10x0f; (行值)和Col=P10xf0; //列的值相加后,可知该按钮被按下了
1x1:http://www.Sina.com/http://www.Sina.com /
http://www.Sina.com/http://www.Sina.com /
ong> 1110 1110 = 0xee低电平0表示对应的行列按下
可以看到下方的p1.0和p1.4变成了低电平
2x2: (二行二列)
Row=P1&0x0f = 0000 1101
Col=P1&0xf0= 1101 0000
Row+Col= 1101 1101 = 0xdd
3x4: (三行四列)
Row=P1&0x0f = 0000 1011
Col=P1&0xf0= 0111 0000
Row+Col= 0111 1011 = 0x7b
这样就可以得到所有的16个按键的数值,具体代码如下:
unsigned char keyscan(){unsigned char key,Row,Col;P1=0x0f;if(P1!=0x0f){delay(10);//去抖if(P1!=0x0f){Row=P1&0x0f;//确保端口值正确(行的值)P1=0xf0;Col=P1&0xf0;//列值}while((P1&0xf0)!=0xf0);//判断键是否抬起}switch(Row+Col){case 0xee:key=0;break;case 0xde:key=1;break;case 0xbe:key=2;break;case 0x7e:key=3;break;case 0xed:key=4;break;case 0xdd:key=5;break;case 0xbd:key=6;break;case 0x7d:key=7;break;case 0xeb:key=8;break;case 0xdb:key=9;break;case 0xbb:key=10;break;case 0x7b:key=11;break;case 0xe7:key=12;break;case 0xd7:key=13;break;case 0xb7:key=14;break;case 0x77:key=15;break;}return key;}运行效果图:
逐行/列扫描:逐行,逐列扫描的本质和行列扫描比较类似,本质是给某一行/某一列,低电平,其余七个全部为高电平,这时候读取电平变换,有电平变低表示按键按下,即可读取按键数据。
比如逐行扫描:
置第1行为低电平,其余N-1行和N列为高电平,读取列线数据,列线有低电平表示此行有按键按下,比如按下的是1行三列(1x3),那么第三列的列线IO口就为低电平。置第2行为低电平,其余N-1行和N列为高电平,,读取列线数据,列线有低电平表示此行有按键按下。以此类推,进行逐行扫描。根据行线列线的电平不同可以识别是否有按键按下,哪一个按键按下,获取按键号。(N) 根据按键号跳转至对应的按键处理程序。用我们的P1口来进行举例:
首先,给P1赋值 P1=0xfe(1111 1110);,这时P1.0为低电平,P1.1~p1.7为高电平,如果这时候有按键按下那么四个列线,P1.4,P1.5,P1.6,P1.7就有一个列会变成低电平。因此P1的值就不等于0xfe,这是就可以判断有按键按下。
然后延时一段时间去抖动,然后给P1赋值0xfd(1111 1101),也就是P1.1为低电平,其他为高电平,这时如果有在P1.1线上的P1.4,P1.5,P1.6,P1.7有按键按下,那么就会出现低电平,从而判断哪个按键按下;如果没有那么就给P1赋值0xfb(1111 1011),也就是P1.2为低电平,其他为高电平.,相同方法判断是否有按键按下;······如此类推,一共四次检测。
比如当第1行有按键按下时P1的相应值为:
1X1(11101110=0xee)
1x2(11011110=0xde)
1X3(10111110=0xbe)
1X4(01111110=0x7e)
第2行有按键按下时P1的相应值为:
2X1(11101101=0xed)
2x2(11011101=0xdd)
2X3(10111101=0xbd)
2X4(01111101=0x7d)
将P1^2输出低电平,其他的引脚都输出高电平,即P1=0xfb,那么当第3行有按键按下时P1的相应值为:
3X1(11101011=0xeb)
3x2(11011011=0xdb)
3X3(10111011=0xbb)
3X4(01111011=0x7b)
最后可得第四行的相对应值为:
4X1(11100111=0xe7)
4x2(11010111=0xd7)
4X3(10110111=0xb7)
4X4(01110111=0x77)
那么最后我们可以得到代码:
/******************************************************************************* 函数名称:keyscan** 功能描述:按键获取函数******************************************************************************/void keyscan(void){P1=0xfe; temp=P1; temp=temp&0xf0; if(temp!=0xf0) {delay(10); if(temp!=0xf0) {temp=P1;switch(temp){case 0xee:key=0;break;case 0xde:key=1;break;case 0xbe:key=2;break;case 0x7e:key=3;break; } while(temp!=0xf0) {temp=P1;temp=temp&0xf0; }}}P1=0xfd;temp=P1;temp=temp&0xf0;if(temp!=0xf0){delay(10);if(temp!=0xf0) {temp=P1;switch(temp){case 0xed: key=4;break;case 0xdd:key=5;break;case 0xbd:key=6;break;case 0x7d:key=7;break; } while(temp!=0xf0) { temp=P1; temp=temp&0xf0; } }}P1=0xfb;temp=P1;temp=temp&0xf0;if(temp!=0xf0){delay(10); if(temp!=0xf0) {temp=P1;switch(temp){case 0xeb:key=8;break;case 0xdb:key=9;break;case 0xbb:key=10;break;case 0x7b:key=11;break; }beep=0;delay(50);beep=1;while(temp!=0xf0) {temp=P1;temp=temp&0xf0; } } }P1=0xf7; temp=P1; temp=temp&0xf0; if(temp!=0xf0) { delay(10); if(temp!=0xf0) {temp=P1;switch(temp){case 0xe7:key=12;break;case 0xd7:key=13;break;case 0xb7:key=14;break;case 0x77:key=15;break; }while(temp!=0xf0) {temp=P1;temp=temp&0xf0; } }}}运行效果图: