目录
- 1.实现功能
- 2.矩阵按键介绍
- 3.矩阵按键两种方法实现原理
-
- 3.1行列式扫描原理理解
- [3.2 线翻转法](#3.2 线翻转法)
- 4.行列式扫描代码
- 5.线翻转代码
- 6.原理图
1.实现功能
一共有16个按键,分别控制数码管0-15,在数码管显示0-F,每一个按键都会单独控制显示数码管一个数字,数码管采用共阴极
2.矩阵按键介绍

P17,P16,,P15,P14 连接的是行
P13,P12,P11,P10 连接的是列
3.矩阵按键两种方法实现原理
实现矩阵扫描有两种方法,行列式扫描,线翻转法
3.1行列式扫描原理理解
P17,P16,,P15,P14连接的是行
P13,P12,P11,P10连接的是列
当P13是0(第一列为0) 那么P1接口 1111 0111,当第一列中的某一个按钮按下得到
0111 0111 -------->0X77 第一行第一列 key1
1011 0111 -------->0XB7 第二行第一列 key5
1101 0111 --------->0XD7 第三行第一列 key9
1110 0111---------->0XE7 第四行第一列 key13
当P12是0(第二列为0) 那么P1接口 1111 1011,当第二列中的某一个按钮按下得到
0111 1011 -------->0X7B 第一行第二列 key2
1011 1011 -------->0XBB 第二行第二列 key6
1101 1011 --------->0XDB 第三行第二列 key10
1110 1011---------->0XEB 第四行第二列 key14
当P11是0(第三列为0) 那么P1接口 1111 1101,当第三列中的某一个按钮按下得到
0111 1101 -------->0X7D 第一行第三列 key3
1011 1101 -------->0XBD 第二行第三列 key7
1101 1101 --------->0XDD 第三行第三列 key11
1110 1101---------->0XED 第四行第三列 key15
当P10是0(第四列为0) 那么P1接口 1111 1110,当第四列中的某一个按钮按下得到
0111 1110 -------->0X7E 第一行第四列 key4
1011 1110 -------->0XBE 第二行第四列 key8
1101 1110 --------->0XDE 第三行第四列 key12
1110 1110---------->0XEE 第四行第四列 key16
最后可以定义一个保存键值的变量key_value保存第key值,通过定义的数码管数组,用key充当数组的下标得到要输出的数字,赋值给数码管段选。
这种行列式需要重复四次的操作
3.2 线翻转法
P17,P16,,P15,P14连接的是行
P13,P12,P11,P10连接的是列
当P17,P16,,P15,P14都是0,行为0,那么P1接口 0000 1111,当四列中某一列的按钮按下得到
0000 0111 -------->0X07 第一列
0000 1011 -------->0X0B 第二列
0000 1101 -------->0X0D 第三列
0000 1110 -------->0X0E 第四列
用一个变量保存第几列,key_value
当P13,P12,P11,P10都是0,列为0,那么P1接口 1111 0000,当四行中某一行的按钮按下得到
0111 0000 -------->0X70 第一行 key = key_value
1011 0000 -------->0XB0 第二行 key = key_value + 4
1101 0000 -------->0XD0 第三行 key = key_value + 8
1110 0000 -------->0XE0 第四行 key = key_value + 12
最后返回的key值,充当数码管数组下标,输出显示出来对应的数码管的值。
4.行列式扫描代码
c
#include <reg51.h>
typedef unsigned int u16;
typedef unsigned char u8;
#define KEY_MATRIX_POST P1
#define SMG_A_DP_POST P0
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共阴数码管0-F
void delay_50ms(u16 us) {
while(us--);
}
u8 key_matrix_ranks_scan(void) { //行列式扫描
u8 key_value = 0;
KEY_MATRIX_POST = 0XF7; //第一列为低电平 1111 0111
if (KEY_MATRIX_POST != 0XF7) {
delay_50ms(1000);
switch(KEY_MATRIX_POST) {
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_POST != 0XF7);//等待按键松开
}
KEY_MATRIX_POST = 0XFB; //第二列为低电平
if (KEY_MATRIX_POST != 0XFB) {
delay_50ms(1000);
switch(KEY_MATRIX_POST) {
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_POST != 0XFB);//等待按键松开
}
KEY_MATRIX_POST = 0XFD; //第三列为低电平
if (KEY_MATRIX_POST != 0XFD) {
delay_50ms(1000);
switch(KEY_MATRIX_POST) {
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_POST != 0XFD);//等待按键松开
}
KEY_MATRIX_POST = 0XFE; //第四列为低电平
if (KEY_MATRIX_POST != 0XFE) {
delay_50ms(1000);
switch(KEY_MATRIX_POST) {
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_POST != 0XFE);//等待按键松开
}
return key_value;
}
void main() {
u8 key = 0;
while(1) {
key = key_matrix_ranks_scan();
if (key !=0)
SMG_A_DP_POST = gsmg_code[key - 1];
}
}
main函数里面的 if 作用,当没有这个if限制条件,由于在while循环里面执行的,当16个按键什么都不操作,无限返回0,一直输出数码管数组下标是-1,所以数码管最终显示不出来数字。当按下其中一个按键,返回一个键值,在数码管输出该键值的数字,由于程序一直在while执行的,程序会不停的执行,不停的返回键值,每次返回0,输出数组下标-1的值,由于用户按了按键,会输出键值,但是很短暂,因为没有在数码管输出数字后进行暂停,最终会在数码管输出按键键值会一闪而过。
当有了if限制条件,当用户按下按键后,得到一个键值输出在数码管后,当之后什么都不操作,会一直返回0,那么就不会对数码管显示的数字赋予新的值
5.线翻转代码
c
#include <reg51.h>
typedef unsigned int u16;
typedef unsigned char u8;
#define KEY_MATRIX_POST P1
#define SMG_A_DP_POST P0
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共阴数码管0-F
void delay_50ms(u16 us) {
while(us--);
}
u8 key_matrix_flip_scan(void) { //线翻转
u8 key_value = 0;
KEY_MATRIX_POST = 0X0F;
if (KEY_MATRIX_POST != 0X0F) {
delay_50ms(1000);
if (KEY_MATRIX_POST != 0X0F) {
switch(KEY_MATRIX_POST) { //找列
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_POST = 0XF0;
switch(KEY_MATRIX_POST) { //找行
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_POST != 0XF0); //松手检测
}
}
return key_value;
}
void main() {
u8 key = 0;
while(1) {
//key = key_matrix_ranks_scan();
key = key_matrix_flip_scan();
if (key !=0)
SMG_A_DP_POST = gsmg_code[key - 1];
}
}
6.原理图
