蓝桥杯单片机之按键扫描(状态机)

         正如比赛官方所说,按键要灵敏,不要出现按键按一下跳转好几次的情况(比如常见的界面),数码管也要消隐。因为可以说这是单片机最重要的输入和输出了。而输入和输出正如人的体验一样,给人最直接而深刻的感受。

由于之前有疑问,是关于按键驱动程序是按键松开后触发还是按下就触发(都仅触发一次),蓝桥官方老师给出的是若题目只考虑到功能描述,即并未说明是按键松开后触发还是按下就触发,那就是随便~。

不过,大部分赛题都是按下就触发,而我做了这么多套题写的都是按键松开触发(不知道会不会有影响)故我总结几种按下就触发的算法(基于状态机触发的且仅触发一次的简洁算法,正所谓大道至简,道法术器!

第一种算法思路(优化前):

根据状态机有且仅有一次在按键扫描函数中从case 1变到case 2,通过定义一个临时变量保存按下的值,松开后初始化为0。

按键扫描函数(越简越好)

void key_scan(){
	
	switch(key_state){
	case 0:
		P3=0x0f;
		P42=0;
		P44=0;
		key_v=0;
		if(P3!=0x0f)	key_state=1;
			
		break;
	case 1:
			P3=0x0f;
			P42=0;
			P44=0;
			if(P3!=0x0f){
			 
			if(!P30)key_v=7;
			else if(!P31)key_v=6;
			else if(!P32)key_v=5;
			else if(!P33)key_v=4;

				
			P3=0xf0;
			P42=1;
			P44=1;
			if(!P34)key_v+=12;
			else if(!P35)key_v+=8;
			else if(!P42)key_v+=4;
			key_state=2;
		}
		else 
			key_state=0;
		break;
	case 2:
		
		P3=0x0f;
		P42=0;
		P44=0;
		if(P3==0x0f){
			key_state=0;		
		}
		break;
	default:
		break;

}
}

main函数驱动:

	if(keytime>=20){
			keytime=0;
			key_scan();
			if(key_state==2){	     //     第一次扫描,按键状态机由case0 -case1,
				if(key_v!=keys){    //	第二次扫描  按键状态机由case1 -case2
			switch(key_v){			//第三次扫描  按键状态机case2 -case 0(松开)或保持不变
				case 4:
					     //to do
					break;
				case 8:
					 	 //to do
					break;
				case  9:
					 	 //to do
					break;
				case 5:
					 	 //to do
					break;
			}
		 keys=key_v;
		}
		 
}
	else 
		keys=0;//松手后
}

第二种算法思路(进一步优化):

直接在状态机(按键的状态扫描函数)里保持按键从case1 -case2 的值,但状态机到case 2,将值初始化为0.

按键扫描(状态机):

void key_scan(){
	
	switch(key_state){
	case 0:
		P3=0x0f;
		P42=0;
		P44=0;
		key_v=0;
		if(P3!=0x0f)	key_state=1;
			
		break;
	case 1:
			P3=0x0f;
			P42=0;
			P44=0;
			if(P3!=0x0f){
			 
			if(!P30)key_v=7;
			else if(!P31)key_v=6;
			else if(!P32)key_v=5;
			else if(!P33)key_v=4;

				
			P3=0xf0;
			P42=1;
			P44=1;
			if(!P34)key_v+=12;
			else if(!P35)key_v+=8;
			else if(!P42)key_v+=4;
			key_state=2;
				rkey=key_v;//rkey 保存从case 1跳转到case 2的键值
		}
		else 
			key_state=0;
		break;
	case 2:
		rkey=0;
		P3=0x0f;
		P42=0;
		P44=0;
		if(P3==0x0f){
			key_state=0;	
			 			
		}
		break;
	default:
		break;

}
}

main函数驱动:(伪代码)

if(keytime>=20){
      keytime=0;
         switch(rkey){

            case 4://to do
                break;
            case 5://to do
                break;
            case 6://to do
                break;
            case 7://to do
                break;

}
}

若是用独立键盘扫描,则更为简单,需要注意的是在NE555频率测量的时候,由于用了P34引脚,故需在编写按键状态机函数时做诸如P3==0x0f判断时屏蔽掉P34位用P3&0x0f==0x0f替代。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值