矩阵按键
原理图如下:
行列扫描
行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确 定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电 平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列 的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平, 这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。 当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检 测。
线翻转法
线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果 有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值, 由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部 按键。
#include "reg52.h"typedef unsigned int u16;
typedef unsigned char u8;#define SMG_A_DP_PORT P0 //共阴极接法-高电平有效
#define KEY_MATRIX_PORT P1 u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};/** 延时函数**/
void delay_10us(u16 num){while(num--);
}/** 行列扫描法*/
u8 key_matrix_ranks_scan(void){u8 key_value = 0;//返回值,0表示没有按键按下KEY_MATRIX_PORT=0xf7;//先将第一列设为低电平if(KEY_MATRIX_PORT!=0xf7){delay_10us(1000);//消抖switch(KEY_MATRIX_PORT){//保存第一列的键值case 0x77: key_value=1;break;case 0xb7: key_value=5;break;case 0xd7: key_value=9;break;case 0xe7: key_value=13;break;}}while(KEY_MATRIX_PORT!=0xf7);//等待按键松开KEY_MATRIX_PORT=0xfb;//先将第二列设为低电平if(KEY_MATRIX_PORT!=0xfb){delay_10us(1000);//消抖switch(KEY_MATRIX_PORT){//保存第二列的键值case 0x7b: key_value=2;break;case 0xbb: key_value=6;break;case 0xdb: key_value=10;break;case 0xeb: key_value=14;break;}}while(KEY_MATRIX_PORT!=0xfb);//等待按键松开KEY_MATRIX_PORT=0xfd;//先将第三列设为低电平if(KEY_MATRIX_PORT!=0xfd){delay_10us(1000);//消抖switch(KEY_MATRIX_PORT){//保存第三列的键值case 0x7d: key_value=3;break;case 0xbd: key_value=7;break;case 0xdd: key_value=11;break;case 0xed: key_value=15;break;}}while(KEY_MATRIX_PORT!=0xfd);//等待按键松开KEY_MATRIX_PORT=0xfe;//先将第四列设为低电平if(KEY_MATRIX_PORT!=0xfe){delay_10us(1000);//消抖switch(KEY_MATRIX_PORT){//保存第四列的键值case 0x7e: key_value=4;break;case 0xbe: key_value=8;break;case 0xde: key_value=12;break;case 0xee: key_value=16;break;}}while(KEY_MATRIX_PORT!=0xfe);//等待按键松开return key_value;
}/**
* 函 数 名 : key_matrix_flip_scan
* 函数功能 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输 入 : 无
* 输 出 : key_value:1-16,对应 S1-S16 键,
*0:按键未按下
*/u8 key_matrix_flip_scan(void){u8 key_value = 0;KEY_MATRIX_PORT = 0x0f;//先给所有行设为低电平if(KEY_MATRIX_PORT!=0x0f){//判断按键是否按下delay_10us(1000);//消抖if(KEY_MATRIX_PORT!=0x0f){//消抖之后再次判断按键是否按下//测试列KEY_MATRIX_PORT=0x0f;switch(KEY_MATRIX_PORT){case 0x07: key_value = 1;break;case 0x0b: key_value = 2;break;case 0x0d: key_value = 3;break;case 0x0e: key_value = 4;break;}//测试行KEY_MATRIX_PORT = 0xf0;switch(KEY_MATRIX_PORT){case 0x70: key_value = key_value;break;//如果是第一行,那么列值就是所在的键位case 0xb0: key_value = key_value+4;break;//如果是第二行,那么列数+4就是所在的键位case 0x0d: key_value = key_value+8;break;//如果是第三行,那么列数+8就是所在的键位case 0x0e: key_value = key_value+12;break;如果是第四行,那么列数+12就是所在的键位}while(KEY_MATRIX_PORT!=0xf0);//等待按键松开}}else{//如果没有按下则返回0key_value=0;}return key_value;}/*
* 主函数
*/
void main(){u8 key = 0;while(1){key = key_matrix_ranks_scan();if(key!=0){P0 = gsmg_code[key-1];//得到的按键值减 1 换算成数组下标对应 0-F 段码}}}
本实验核心代码为 key_matrix_ranks_scan 函数和 key_matrix_flip_scan 函数,前者是使用行列式扫描方式实现,而后者是使用线翻转式扫描方式实现, 实现功能一致,二者可选其一。对于初学者,可能行列式扫描方式更易于理解, 因为比较接近独立按键的编程方式。 行列式扫描原理比较简单,与独立式按键操作类似,即给每一列赋值 0,此 时的矩阵按键就被分割成独立按键,然后再判断每一列中的按键按下情况,并返 回对应的键值。如此循环 4 组,就可将 4 列 4 行按键按下键值全部得到。 而线翻转式扫描相对较难理解,不过静下心,在纸上画画,列举几个数据也是比较容易理解的!!!
结束!!!