蓝桥杯之单片机设计与开发(4)——矩阵按键

矩阵按键

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

一针见血,看原理图

将开发板上面的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;
	}
}

 

 

 

 

 

 

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值