002_矩阵按键

独立按键与单片机连接时,每一个按键都需要单片机的一个 I/O 口,若某单片机系统需较多按键,如果用独立按键便会占用过多的 I/O 口资源。单片机系统中 I/O 口资源往往比较宝贵,当用到多个按键时为了减少 I/O 口引脚,引入了矩阵按键。

无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的 I/O 口是否为低电平。独立键盘有一端固定为低电平,此种方式编程比较简单。 而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平。检测方法有多种,最常用的是行列扫描和线翻转法。

行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。

线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键。

矩阵键盘也少不了按键消抖的环节。

在这里插入图片描述
通过数码管显示矩阵按键 S1-S16 按下后键值 0-F。

#include "reg52.h"

typedef unsigned char u8;
typedef unsigned int u16;

#define SMG_A_AP_PORT 	P0   //数码管
#define KEY_MATRIX_PORT P1   //矩阵按键

u8 gsmg_code[] = {
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				  0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void delay(u16 us)
{
    
    
	while(us--);
}

//行列式扫描
u8 key_matrix_ranks_scan(void)
{
    
    
	u8 key_value = 0;
	
	KEY_MATRIX_PORT = 0xf7;   //第一列为低电平--p13为低电平
	if(KEY_MATRIX_PORT != 0xf7)  //第一列是否有按键按下
	{
    
    
		delay(1000);//按键按下  消抖
		switch (KEY_MATRIX_PORT)
		{
    
    
		case 0x77:   key_value = 1;  break;   //S1
		case 0xb7:   key_value = 5;  break;   //S5
		case 0xd7:   key_value = 9;  break;   //S9
		case 0xe7:   key_value = 13;  break;  //S13
		}
		while(KEY_MATRIX_PORT != 0xf7); //等待按键松开
	}
	
	KEY_MATRIX_PORT = 0xfb;   //第二列为低电平--p12为低电平
	if(KEY_MATRIX_PORT != 0xfb)  //第一列是否有按键按下
	{
    
    
		delay(1000);//按键按下  消抖
		switch (KEY_MATRIX_PORT)
		{
    
    
		case 0x7b:   key_value = 2;  break;   //S2
		case 0xbb:   key_value = 6;  break;   //S6
		case 0xdb:   key_value = 10;  break;  //S10
		case 0xeb:   key_value = 14;  break;  //S114
		}
		while(KEY_MATRIX_PORT != 0xfb); //等待按键松开
	}

	KEY_MATRIX_PORT = 0xfd;   //第三列为低电平--p11为低电平
	if(KEY_MATRIX_PORT != 0xfd)  //第一列是否有按键按下
	{
    
    
		delay(1000);//按键按下  消抖
		switch (KEY_MATRIX_PORT)
		{
    
    
		case 0x7d:   key_value = 3;  break;   //S3
		case 0xbd:   key_value = 7;  break;   //S7
		case 0xdd:   key_value = 11;  break;  //S11
		case 0xed:   key_value = 15;  break;  //S15
		}
		while(KEY_MATRIX_PORT != 0xfd); //等待按键松开
	}

	KEY_MATRIX_PORT = 0xfe;   //第四列为低电平--p10为低电平
	if(KEY_MATRIX_PORT != 0xfe)  //第一列是否有按键按下
	{
    
    
		delay(1000);//按键按下  消抖
		switch (KEY_MATRIX_PORT)
		{
    
    
		case 0x7e:   key_value = 4;  break;   //S4
		case 0xbe:   key_value = 8;  break;   //S8
		case 0xde:   key_value = 12;  break;  //S12
		case 0xee:   key_value = 16;  break;  //S16
		}
		while(KEY_MATRIX_PORT != 0xfe); //等待按键松开
	}
	return key_value;
}

//线翻转法扫描
u8 key_matrix_flip_scan()
{
    
    	
	u8 key_value = 0;

	KEY_MATRIX_PORT = 0x0f;  //行全为0 判断列
	//测试列
	if(KEY_MATRIX_PORT != 0x0f)
	{
    
    
		delay(1000);
		switch (KEY_MATRIX_PORT)
		{
    
    
			case 0x07:	key_value = 1;		break;  //第1列有按键按下
			case 0x0b:	key_value = 2;		break;  //第2列有按键按下
			case 0x0d:	key_value = 3;		break;  //第3列有按键按下
			case 0x0e:	key_value = 4;		break;  //第4列有按键按下
		}
		//测试行
		KEY_MATRIX_PORT = 0xf0;
		switch (KEY_MATRIX_PORT)	
		{
    
    
			case 0x70:	key_value = key_value;			break;  	//第1行有按键按下
			case 0xb0:	key_value = key_value + 4;		break;  	//第2行有按键按下
			case 0xd0:	key_value = key_value + 8;		break;  	//第3行有按键按下
			case 0xe0:	key_value = key_value + 12;		break;  	//第4行有按键按下
		}
		while (KEY_MATRIX_PORT != 0xf0);
	}
	return key_value;
}

void main()
{
    
    
	u8 ret = 0;
	while(1)
	{
    
    
#if 0
		//行列式扫描
		ret = key_matrix_ranks_scan();
		if(ret != 0)
			SMG_A_AP_PORT = gsmg_code[ret-1];   //保证有按键按下
#endif
		//线翻转
		ret = key_matrix_flip_scan();
		if(ret != 0)
			SMG_A_AP_PORT = gsmg_code[ret-1];   //保证有按键按下
	}	
}

猜你喜欢

转载自blog.csdn.net/weixin_42581177/article/details/127820184