矩阵按键介绍
独立按键与单片机连接时,每一个按键都需要单片机的一个 I/O 口,若某单片机系统需较多按键,如果用独立按键便会占用过多的 I/O 口资源。单片机系统中 I/O 口资源往往比较宝贵,当用到多个按键时为了减少 I/O 口引脚,引入了矩阵按键。
无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的 I/O 口是否为低电平。独立键盘有一端固定为低电平,此种方式编程比较简单。而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平。检测方法有多种,最常用的是行列扫描和线翻转法。
- 行列扫描法:先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。
- 线翻转法: 使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键。
硬件设计
本实验用到的硬件资源如下:
- 静态数码管
- 4*4矩阵键盘
4*4矩阵键盘模块电路图如下所示:
从上图中可以看出,该电路是独立的,4*4矩阵按键引出的8根控制管脚并未直接连接到51单片机的IO上,而是连接到JP3端子上。电路中的ARRAY_H1表示矩阵键盘第1行,ARRAY_L1表示矩阵键盘第1列。
软件设计
本实验通过数码管显示矩阵按键S1-S16按下后键值0-F。
使用P1口来检测4*4矩阵按键,使用P0口控制静态数码管。单片机的P17口连接矩阵键盘的第1行,P13口连接矩阵键盘第1列。
实物接线图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| #include "reg52.h"
#define KEY_MATRIX_PORT P1
#define SMG_A_DP_PORT P0
typedef unsigned int u16; typedef unsigned char u8;
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay_10us(u16 ten_us) { while(ten_us--); }
u8 key_matrix_ranks_scan() { u8 key_value = 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; }
u8 key_matrix_flip_scan() { static 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; case 0xD0: key_value = key_value + 8;break; case 0xE0: key_value = key_value + 12;break; } while(KEY_MATRIX_PORT != 0xF0); } } else { key_value = 0; } return key_value; }
void main() { u8 key = 0; while(1) { key = key_matrix_flip_scan(); if(key != 0) SMG_A_DP_PORT = ~gsmg_code[key - 1]; } }
|
行列式扫描原理比较简单,与独立式按键操作类似,即给每一列赋值0,此时的矩阵按键就被分割成独立按键,然后再判断每一列中的按键按下情况,并返回对应的键值。如此循环4组,就可将4列4行按键按下键值全部得到。