实验三矩阵键盘独立键盘与单片机连接时,每一个按键都需要单片机的一个I/O口若某单片机系统需较多按键,如果用独立按键便会占用过多的I/O口资源。单片机系统中I/O口资源往往比较宝贵,当用到多个按键时为了节省I/O口口线,我们引入矩阵键盘。我们以4X4矩阵键盘为例讲解其工作原理和检测方法。将16个按键排成4行4列,第一行将每个按键的一端连接在一起构成行线,第一列将每个按键的另一端连接在一起构成列线,这样便一共有4行4列共8根线,我们将这8根线连接到单片机的8个I/O口上,通过程序扫描键盘就可检测16个键。用这种方法我们也可实现3行3列9个键、5行5列25个键、6行6列36个键等。无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的I/O口是否为低电平。独立键盘有一端固定为低电平,单片机写程序检测时比较方便。而矩阵键盘两端都与单片机I/O口相连,因此在检测时需人为通过单片机I/O口送出低电平。检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。这就是矩阵键盘检测的原理和方法。首先看一下电路图上图是一个4X4的矩阵键盘,一共是16个按键。我们照习惯称横为“行”,“竖”为列。那么5、6、7、8我们称之为“行线”,则1、2、3、4称为“列线”。要正确记住各个行列线各自对应的I/O。注意看,每一个按键的两端,都分别接在某一个列线和行线上,即:“行线和列线是通过某个按键的按下和抬起实现联通和断开的”。现在详细讲述一下矩阵键盘扫描的原理和步骤:扫描矩阵键盘,即是把某一条(只有一条)行线置为低电平,而列线全部置为输入方向,然后检测列线,如果检测到某一条列线是低电平,那么就表示位于这条列线与输出低电平的行线的交点处的按键被按下了。要扫描16个按键,就依次以这样的方法扫描16次,之后就可以确定哪一个按键被按下了。当然这里也少不了延时消除按键抖动的环节。下面看一下程序/*******************************************************************************实验名:矩阵键盘实验*使用的IO:数码管使用P0,键盘使用P1*实验效果:按矩阵键盘分别显示在数码管上面显示十六进制的0到F。*注意:******************************************************************************/#includereg51.h#defineGPIO_DIGP0#defineGPIO_KEYP1sbitLSA=P2^2;56781234sbitLSB=P2^3;sbitLSC=P2^4;unsignedcharcodeDIG_CODE[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码unsignedcharKeyValue;//用来存放读取到的键值voidDelay10ms();//延时10ms函数voidKeyDown();//检测按键函数/******************************************************************************函数名:main*函数功能:主函数*输入:无*输出:无******************************************************************************/voidmain(void){LSA=0;//给一个数码管提供位选LSB=0;LSC=0;while(1){KeyDown();GPIO_DIG=DIG_CODE[KeyValue];}}/*******************************************************************************函数名:KeyDown*函数功能:检测有按键按下并读取键值*输入:无*输出:无******************************************************************************/voidKeyDown(void){chara;GPIO_KEY=0x0f;if(GPIO_KEY!=0x0f){Delay10ms();if(GPIO_KEY!=0x0f){//测试列GPIO_KEY=0X0F;switch(GPIO_KEY){case(0X07):KeyValue=0;break;case(0X0b):KeyValue=1;break;case(0X0d):KeyValue=2;break;case(0X0e):KeyValue=3;break;}//测试行GPIO_KEY=0XF0;switch(GPIO_KEY){case(0X70):KeyValue=KeyValue;break;case(0Xb0):KeyValue=KeyValue+4;break;case(0Xd0):KeyValue=KeyValue+8;break;case(0Xe0):KeyValue=KeyValue+12;break;}while((a50)&&(GPIO_KEY!=0xf0))//检测按键松手检测{Delay10ms();a++;}a=0;}}}/*******************************************************************************函数名:Delay10ms*函数功能:延时函数,延时10ms*输入:无*输出:无******************************************************************************/voidDelay10ms(void)//误差0us{unsignedchara,b,c;for(c=1;c0;c--)for(b=38;b0;b--)for(a=130;a0;a--);}下载HEX文件,观察实验效果,实验的效果是:按矩阵键盘分别显示在数码管上面显示十六进制的0到F。ORG00HLJMPINITORG30HDB03FH,006H,05BH,04FH,066H,06DH,07DH,007HDB07FH,06FH,077H,07CH,039H,05EH,079H,071H;0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F;*************;;主程序;;*************;INIT:CLRP2.2CLRP2.3CLRP2.4MOVR1,#00HSTART:MOVA,R1MOVDPTR,#30HMOVCA,@A+DPTRMAIN:MOVP0,A;**********************;;矩阵键盘扫描程序;;**********************;KEY_SCAN:MOVP1,#00FHNOPMOVR2,P1CJNER2,#00FH,KEY_DOWN;没有按键按下就返回主函数SJMPMAINKEY_DOWN:ACALLDELAY10MS;消抖MOVR2,P1CJNER2,#00FH,NEXT0SJMPMAIN;没有按键按下就返回主函数NEXT0:CJNER2,#007H,NEXT1;如果不等于007H就跳去检测下一个键值MOVR1,#00H;如果是的话SJMPNEXT_SCANNEXT1:CJNER2,#00BH,NEXT2MOVR1,#01HSJMPNEXT_SCANNEXT2:CJNER2,#00DH,NEXT3MOVR1,#02HSJMPNEXT_SCANNEXT3:CJNER2,#00EH,MAINMOVR1,#03HNEXT_SCAN:MOVP1,#0F0HMOVR2,P1CJNER2,#070H,NEXT4MOVA,#00HADDA,R1MOVR1,ALJMPSTARTNEXT4:CJNER2,#0B0H,NEXT5MOVA,#04HADDA,R1MOVR1,ALJMPSTARTNEXT5:CJNER2,#0D0H,NEXT6MOVA,#08HADDA,R1MOVR1,ALJMPSTARTNEXT6:CJNER2,#0E0H,MAINMOVA,#0CHADDA,R1MOVR1,AMOVR3,#030HKEY_UP:ACALLDELAY10MSDJNZR3,KEY_UPLJMPSTART;*************;;延时程序;;*************;DELAY10MS:MOVR6,#015HDE1:MOVR7,#0F8HDE2:DJNZR7,DE2DJNZR6,DE1RETEND