【蓝桥杯】按键原理及其常用写法分析

绝对不能放弃的事!要从“今天”开始!!

【刚刚调字体颜色的时候才发现,原来调颜色和字体大小也有语句在前面,突然发现了什么不得了的事情……】

矩阵按键

为啥我在这只说矩阵按键?
因为独立按键、矩阵按键其实本质上控制原理都一样,都是通过检测高低电平来判断按键是否按下。
先看原理图:
【蓝桥杯】按键原理及其常用写法分析_第1张图片
独立按键是最左侧的S4-S7四个按键,矩阵按键则为这个4x4的16个按键。
左侧J5,若用跳帽将2、3短接,则为独立按键模式,若用跳帽将1、2短接,则为矩阵按键模式。

矩阵按键的使用,就是检测某个按键对应的行列是否同时置0,若是,则按下,若不是,则没按。

首先,将第一列置0,P3=0x7f。
【注意】:
P36 - >P42, P37 - >P44;
并且若使用的头文件为 ,则应自己定义P4口,sfr P4 = 0xc0;

第一列置低电平后,可检测第一列的按键哪个按下,若为S7按下,则P30为低电平,则 P3 = 0x7e;
另外,判断完了之后,还要确定按键是否释放,要有一个while语句。

其他按键同理。

对常见写法的分析

在我学习矩阵按键的过程中最初见到的写法:

一、延时消抖法

由于按键需要不停的扫描,达到成功检测的目的,则需要进行消抖测试。
【蓝桥杯】按键原理及其常用写法分析_第2张图片
若不对抖动进行检测和处理,就会造成误判。

#include 

sfr P4 = 0xc0;

sbit P42 = P3^6;
sbit P44 = P3^7;

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

uchar keyscan()
{
	uchar key,temp;

	P3 = 0x7f; 		//令第一列为低电平
	P42 = 1;P44 = 0;
	temp &= 0x0f; 	//P3与0x0f相与,若结果不为0x0f,说明代表行的P30-P33中有置低电平的部分,说明有键按下
	if(temp != 0x0f)
	{
		delay10ms();		//延时消抖
		temp = P3;
		temp &= 0X0f;			//再次确认是否按下
		if(temp != 0x0f)		//确实有键按下
		{
			temp = P3;
			swith(temp)
			{
				case 0x7e:key = 7;break;
				case 0x7d:key = 6;break;
				case 0x7b:key = 5;break;
				case 0x77:key = 4;break;
				default:break;
			}
			while(temp != 0x0f)		//判断是否释放按键
			{
				temp = P3;
				temp &= 0x0f;
			}
		}
	}
……	
}

就仅举S4-S7来写,其他列同理,只不过若是第二列,则先将P3 = 0xbf,再去判断其他行是否置低电平。

上面的写法是我之前比较喜欢用的,但是使用延时函数会对整个使用造成比较大的影响。 我之前用的时候就经常会误判,延时函数占用了一部分时间。 在此,给大家推荐另一种方法,也是我逐渐适应的一种写法

二、中断扫描按键

此时按键的扫描不再放在主函数中,而是在中断中扫描,通过判断按键状态的持续时间来确定按键是否按下或者弹起。
隔一段时间扫描一次按键的状态,如果与上一次按键的状态不同,再隔一段时间扫描一次按键状态,如果又改变了,则说明按键完成了一次按下又弹起的动作。

sbit Key_Out_1 = P3^0;		//行扫描
sbit Key_Out_2 = P3^1;
sbit Key_Out_3 = P3^2;
sbit Key_Out_4 = P3^3;

sbit Key_In_4 = P3^4;		//列扫描
sbit Key_In_3 = P3^5;
sbit Key_In_2 = P4^2;
sbit Key_In_1 = P4^4;

uchar KeySta[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};			//储存按键当前值
uchar code KeyMap[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; 		//规定16个键分别代表的值

void KeyDriver()
{
	uchar i,j;
	static uchar KeyBack[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};	//矩阵按键初始化

	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			if(KeySta[i][j] != KeyBack[i][j])	//按键状态改变
			{
				if(KeySta[i][j] != 0)		//按键松开
				{
				 	KeyAction();//按下之后,写入相应语句执行按键操作
				}
				KeyBack[i][j] = KeySta[i][j];		//将变化后的按键值储存
			}
		}
	}	
}

uchar KeyScan()
{
	uchar i=0;
	static uchar KeyOut = 0;
	static uchar KeyBuff[4][4] = {{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}};

	switch(KeyOut)
	{
		case 0:Key_Out_1=0; Key_Out_4=1; break;
		case 1:Key_Out_2=0; Key_Out_1=1; break;
		case 2:Key_Out_3=0; Key_Out_2=1; break;
		case 3:Key_Out_4=0; Key_Out_3=1; break;
	}
	
	KeyBuff[KeyOut][0] = KeyBuff[KeyOut][0]<<1 | Key_In_1;
	KeyBuff[KeyOut][1] = KeyBuff[KeyOut][1]<<1 | Key_In_2;
	KeyBuff[KeyOut][2] = KeyBuff[KeyOut][2]<<1 | Key_In_3;
	KeyBuff[KeyOut][3] = KeyBuff[KeyOut][3]<<1 | Key_In_4;

	for(i=0;i<4;i++)		//消抖
	{
		if((KeyBuff[KeyOut][i]&0x0f) == 0x00)
		{
			KeySta[KeyOut][i] = 0;
		}	
		else if((KeyBuff[KeyOut][i]&0x0f) == 0x0f)
		{
			KeySta[KeyOut][i] = 1;
		}
	}
	KeyOut ++;  		//检测下一行
	KeyOut &= 0X03;		//若超过3,则与0x03相与又变回0x00了
}

函数的使用应该在中断函数中进行每1ms一次,4ms消抖

void Timer0() interrupt 1
{
	KeyScan();
}

void main()
{
	while(1)
	{
		KeyDrive();
	}
}

通过阅读别人的博客,学习到:
①KeyScan() 放在中断中作扫描作用,运用移位操作、静态变量、循环,判断按下的键值;
②KeyDriver() 放在主函数里,判断按键的按下、松开、按住。

其实一开始从别处看到上面第二种写法,理解了很久才懂。
以前用过的另一种方法似乎比这个好理解,但是我忘记写法了【没办法,每次学到一半都放弃了】

有问题欢迎大家提出,共同交流学习!

你可能感兴趣的:(【蓝桥杯】按键原理及其常用写法分析)