单片机矩阵键盘新解

 

今天再做一个简易电子琴的时候用到了4X4矩阵键盘,突然发现矩阵键盘有新的发现。矩阵键盘连接图如下,上传图片弄了半天没搞定,以后要的时候去网上搜一下就得了。说重点。

按键是线与的关系,比如先给P1口赋值为0xf0,当有按键按下时P1口的值不在为0xf0,因为按下去的那个键使得与子相连的按键线与而为低电平,当按键松开时,线与关系不存在,端口回复到0xf0.而且当 产生线与关系后其他按键不能按下。

关于前面几天写的那些内容今天突然发现其实就是今天刚刚写过的一篇文章那就是单片机IO的读引脚和读端口的问题,给P1口寄存器赋值为0xf0的时候那就是读端口,然后改变端口的值,最后在把改变的值赋值给端口寄存器。然后我们从寄存器读回来的值就是读的引脚的值,这个引脚的值的改变显然是因为外设,这里是按键导致的。这里今天要说的是搜集到几个好的按键程序,把自己的也贴上一下吧。呵呵,给自己多点思路。

首先下面这个是我自己写的,很清楚通过给一个引脚拉低然后检测其他引脚的变化来确定按键。

P1 = 0xf0 ; if(P1 != 0xf0) { delay10ms() ; //按键延时去抖 P1 = 0xfe ; while(P1 != 0xfe ) { switch(P1) { case 0xee: key = 0 ; break ; case 0xde: key = 1 ; break ; case 0xbe: key = 2 ; break ; case 0x7e: key = 3 ; break ; } } P1 = 0xfd ; while(P1 != 0xfd ) { switch(P1) { case 0xed: key = 4 ; break ; case 0xdd: key = 5 ; break ; case 0xbd: key = 6 ; break ; case 0x7d: key = 7 ; break ; } } P1 = 0xfb ; while(P1 != 0xfb ) { switch(P1) { case 0xeb: key = 8 ; break ; case 0xdb: key = 9 ; break ; case 0xbb: key =10 ; break ; case 0x7b: key =11 ; break ; } } P1 = 0xf7 ; while(P1 != 0xf7 ) { switch(P1) { case 0xe7: key =12 ; break ; case 0xd7: key =13 ; break ; case 0xb7: key =14 ; break ; case 0x77: key =15 ; break ; } } }

下面是一个网上搜集到的,其实方法也是一样,通过给低四位循环赋值为零,然后扫描引脚的变化值,但是他这里有几个地方很是值得学习,一是他利用了一个结构体来保存按键的很多信息,这一点很好,其次运用循环检测的时候利用移位来循环。

为了精简程序程序而又不失按键扫描的正确性,利用51单片机IO的特性,当读IO口时有读引脚和读端口寄存器两种操作。程序如下:(定时扫描程序已省去) //定义按键属性(包括是否有按键更新、记录上次按键值、按键按下去的时间(通过时间可以实现同一按键的第二功能)) struct Key_attribute { uchar renew; //有更新renew=1,否则为0 uchar num; //当前按键行列值 uchar last_num; //上次按键行列值 uchar repetition; //连续扫描为同一按键的次数 } Key={0,0,0,0}; /**************************************************************************** **函数原型:uchar key_scanf_1(void) **形参: 无 **函数功能: 扫描当前按键行列值 **返回值: 当前按键的行列值 ****************************************************************************/ void key_scanf(void) { if(Key.renew==0) //只有当无按键更新时才对按键进行扫描 { uchar i=1,j; for(;i<0x10;i<<=1) { P1=~i; j=(~P1)&0xf0; if(j==0x10||j==0x20||j==0x40||j==0x80)//防止多个按键同时按下,同时也节约扫描时间 { P1=0xf0; j|=i; if(j==Key.last_num) { Key.repetition++; } else { Key.last_num=j; Key.repetition=0; } break; } } if(2<=Key.repetition) // 根据定时扫描时间确定Key.repetition的范围。注意这里可根据按键时间长短, //进行消抖动和选择同一按键的第二功能 { Key.num=Key.last_num; Key.renew=1; //有有效按键按下 //>>>>>>可根据按键时间确定按键的第二功能 如if(Key.repetition>10) Key.num=(自定义数值) } } }

其次还有一个我从书本上看过来的非常高效的按键程序。有俩个地方处理的非常好,一个是他确定按键值的地方用一个与的方式确定了按键的值,这一点用的非常好,然后就是用一个按键表来查找按键的值。这样的话我估计这个程序的效率应该很高。

keyport = 0xf0 ; //行线输出为0,列线输出全为1 keytemp = keyport ; //读出按键端口值(严格来我这里是读引脚值) if(keytemp==0xf0) { return nokey ; } keyport = keytemp | 0x0f ; //通过行线与列线值确定按键 keytemp = keyport ; //读取按键值 for(i=0; i<16; i++) { if(keytemp==keycode[i]) //根据按键值查找按键表对应的值 return i ; } return nokey ;

今天按键的新解就写到这里,插上今天的日期吧,下次又该后都看不清的,呵呵2011-03-18

你可能感兴趣的:(struct,IO,delay)