蓝桥杯(4)——矩阵按键

版权声明:让结局不留遗憾,让过程更加完美。 https://blog.csdn.net/Xiaomo_haa/article/details/86649021

矩阵按键

在我的印象中,从我学单片机开始,就很少写矩阵按键的程序,但是原理差不多都清楚,不过在这里不仅要考虑程序的执行,而且需考虑程序的完整与完善。

一针见血,看原理图

将开发板上面的J5跳线帽接到KBD端,也就是J5的1和2相接。

这里注意:在开发板上,根据转接板原理图,WR端接到单片机的P42管脚,RD端接到单片机的P44管脚。

我们知道,按键按下通常会保持100ms以上,如果在按键扫描中断中,每次让矩阵按键的一个KeyOut输出低电平其他三个输出高电平,判断当前所有Keyln的状态,下次中断时再让下一个KeyOut输出低电平,其他三个输出高电平.再次判断所有KeyIn,通过快速的中断不停地循环进行判断,就可以最终确定哪个按键按下了。

这个原理是不是跟数码管动态扫描有点类似?数码管在动态赋值,而按键在动态读取状态。至于扫描间隔时间和消抖时间,因为现在有4个KeyOut输出,要中断4次才能完成一次全部按键的扫描,显然2ms中断时间较长,这里我们使用1ms。

//main.c

#define u16 unsigned int
#define u8 unsigned char

u8 Led_flag = 0;
u8 Led_dat;				//led显示状态
u8 KeySta[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};			//当前按键状态
u8 Key_backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};	//按键状态备份,保存前一次的按键值

void main(void)
{
	u8 i,j;
	All_Init();
	Time0_Init();
	Led_dat = 0xfe;
	while(1)
	{
		for(i = 0;i < 4;i ++)					//循环检测4×4的矩阵按键
		{	
			for(j = 0;j < 4;j ++)
			{
				if(Key_backup[i][j] != KeySta[i][j])	    //检测按键当前动作
				{
					if(Key_backup[i][j] != 0)    	    //按键按下时执行动作
					
					Key_backup[i][j] = KeySta[i][j];    //更新前一次的备份值
				}
			}
		}
	}
}
//key.c

//按键扫描
void Key_Scan(void)
{
	u8 i;
	static u8 keyout = 0;		//矩阵按键扫描输出索引
	static u8 keybuff[4][4] = {{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}};	//矩阵按键扫描缓存区
	
	keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1;		//将每一行的4个按键值移入缓存区
	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;		//连续4次扫描值都是0,即4×4s内都是按下状态,认为按键已平稳按下
		else if((keybuff[keyout][i] & 0x0f) == 0x0f)
			KeySta[keyout][i] = 1;		//连续4次扫描值都是1,即4×4s内都是松开状态,认为按键已稳定弹起
	}
	
	//执行下一次的扫描输出
	keyout ++;
	keyout = keyout & 0x03;		//索引加到4就归零
	switch(keyout)						//根据索引,释放当前输出引脚,拉低下次的输出引脚
	{
		case 0:KEY_OUT_4 = 1;KEY_OUT_1 = 0;break;
		case 1:KEY_OUT_1 = 1;KEY_OUT_2 = 0;break;
		case 2:KEY_OUT_2 = 1;KEY_OUT_3 = 0;break;
		case 3:KEY_OUT_3 = 1;KEY_OUT_4 = 0;break;
		default:break;
	}
}

猜你喜欢

转载自blog.csdn.net/Xiaomo_haa/article/details/86649021