学习矩阵键盘的使用
本文条件限制:4x4矩阵键盘;使用逐行扫描方法,区分按下和抬起,不区分连击、长按和单击;线路逻辑如下图。
策略:设置定时器,每过8~10毫秒,取决于软件消抖动通常采取的延时,就扫描一次矩阵键盘。将按键状态记录下来,将其与上一次按键状态进行对比,从而计算出按键动作。随后将按键动作加入循环队列,供其它程序使用。队列满时可以丢弃新的动作,也可以丢弃之前的动作,这取决于你的需要。
扫描:逐次将各条行线置低,四条列线拉高。随后读入4位列信号,根据列信号中出现低电平(零)的位置来判断该行中四个按键的状态。
动作:要确定每个按键的动作,至少需要为每一个按键保存一个状态。使其根据按键的状态,也就是用户的按键输入,在各个状态之间迁移。这是一般化方法。
状态:对于一次完整的击键动作,对应的列线电平状态可以简单描述为下图。红色折线代表列线电平变化,灰色区域为按键抖动,黑色竖线为时间点。
时间点1:稳定释放,2:按键被按下,3:稳定按下,4:按键被释放
C语言代码:
#define NO_KEY 0 #define KEY1_DOWN 1 #define KEY2_DOWN 2 #define KEY3_DOWN 3 #define KEY4_DOWN 4 #define KEY5_DOWN 5 #define KEY6_DOWN 6 #define KEY7_DOWN 7 #define KEY8_DOWN 8 #define KEY9_DOWN 9 #define KEY10_DOWN 10 #define KEY11_DOWN 11 #define KEY12_DOWN 12 #define KEY13_DOWN 13 #define KEY14_DOWN 14 #define KEY15_DOWN 15 #define KEY16_DOWN 16 #define KEY1_UP -1 #define KEY2_UP -2 #define KEY3_UP -3 #define KEY4_UP -4 #define KEY5_UP -5 #define KEY6_UP -6 #define KEY7_UP -7 #define KEY8_UP -8 #define KEY9_UP -9 #define KEY10_UP -10 #define KEY11_UP -11 #define KEY12_UP -12 #define KEY13_UP -13 #define KEY14_UP -14 #define KEY15_UP -15 #define KEY16_UP -16 #define key_port P1 #define queue_max 8 static char queue[queue_max]; static unsigned char front, rear; static char states[key_n]; static void push(char msg) { if ((rear+1) & 7 == front) return; queue[rear] = msg; rear = (rear+1) & 7; } static char pop() { char e; if (rear == front) return NO_KEY; e = queue[front]; front = (front+1) & 7; return e; } void init_key() { char i; front=0, rear=0; for(i=0; i0; } } void key_scan() { unsigned char tmp; unsigned int mask=0x8000, curr=0xffff; char i; key_port=0xfe; tmp = key_port>>4; curr = (curr<<4) + tmp; key_port=0xfd; tmp = key_port>>4; curr = (curr<<4) + tmp; key_port=0xfb; tmp = key_port>>4; curr = (curr<<4) + tmp; key_port=0xf7; tmp = key_port>>4; curr = (curr<<4) + tmp; for (i=0; i >= 1, ++i){ switch(states[i]){ case 0: if(!(curr&mask)) {states[i]=1;} break; case 1: if(!(curr&mask)) {push(i+1); states[i]=2;} else {states[i]=0;} break; case 2: if(curr&mask) {states[i]=3;} break; case 3: if(curr&mask) {push(-i-1);} states[i]=0; break; }//switch }//for } char get_key(){ return pop(); }
定时器中断处理程序要保证每隔8~10毫秒扫描一次矩阵键盘。
若要阻塞式地等待某按键动作发生,可以将get_key放入循环结构内以重复判断按键动作。这样做会抛弃指定按键动作发生之前的所有其它按键动作。