按键扫描之精妙一谈(原创)

#define KEY0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
#define KEY1  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
#define KEY2  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)//读取按键2 
#define KEY3  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP) 
 
 
#define KEY_UP 4
#define KEY_LEFT3
#define KEY_DOWN2
#define KEY_RIGHT1
 
void KEY_Init(void);//IO初始化
u8 KEY_Scan(u8);  //按键扫描函数
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下 
//4,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
u8 KEY_Scan(u8 mode)
static u8 key_up=1;//按键按松开标志
if(mode)key_up=1;  //支持连按  
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))
{
delay_ms(10);//去抖动 
key_up=0;
if(KEY0==0)return 1;
else if(KEY1==0)return 2;
else if(KEY2==0)return 3;
else if(KEY3==1)return 4;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==0)key_up=1;     
 return 0;// 无按键按下
}
函数解读:
一、mode=0时,按键不支持连按,程序运行过程,主函数中,按键扫描,首先默认为key_up=1,因为从开机,到函数运行速度是极快的,因此会扫描到无按键按下。当然,有一种特殊的情况是,在起机时,就按下按键,此时key_up=0,估计少有人去做这么蛋疼的事吧!
一切准备就绪,程序开始运行,如有按键按下,执行到if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))
此时,key_up=0,函数返回一个u8型数(0||1||2||3||4),如按键不松开,key_up=0,if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))语句永远不会执行,只有按键松开,执行else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==0)key_up=1,因此实现了按键不连按的效果!当然,此时,或许会有人想,如果,我按一下键,赶紧再按一下,不就永远不会执行if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))里的语句了么,我想说的是,你多虑了,我现在所用的是芯片是72MHZ的,代码执行的间距仅仅几毫秒,人的反应速度还没那么快呢,(注:一般条件下,反应时间约为0.1~0.5 s。对于复杂的选择性反应时间达1~3 s,要进行复杂判断和认识的反应时间平均达3~5 s,具体的带有判别的反应时间t可用下式求得: t = k log2 (n+1)   式中,k为常数;n为等概率出现的选择对象数;(n+1)是考虑判明是否出现刺激。)即是低一点的芯片也是没问题的。
二、mode=1时,初始化和mode=0是一样,上面提到,在这里就不再说了,直接看代码,函数在主函数中循环,若有按键按下,运行if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1)),此时key_up=0;不丢开按键,主函数循环到按键扫面函数,执行if(mode)key_up=1;之后,若有按键按下,当然可以运行if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))里的语句了。至此,实现了连续按键。
三、这个函数的封装性极强,换句话说,即是不懂这个函数里的意思,也可以直接拿来运用,当然函数应当这样描述:
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下 
//4,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
u8 t;
t=KEY_Scan(0);
switch(t)
{
   case 1:
   case 2:
   case 3:
   case 4:
}
函数的整体设计确实很吸引人,如果将函数的扫描放在中断里,将大大节省内存,从而可以提高程序运行速率!
    在这儿不得不再次提到一些高级语言,比如C#,VB,Java等等,个人觉得这些高级语言也许正和上面的这个函数有点相像,封装性太强,尤其C#,感觉一种很飘渺的感觉,说实在的起初还可以,时间久了便腻了!我觉得编程人员不是为编程而编程,而是从编程中去寻找乐趣,寻求一种自由!
    所以,正如这个函数,如果只是调用,太简单了,但是如果你了解了这个的设计过程,那么你就是成功地!当然,若想获得更好,懂得底层驱动,甚至,芯片的驱动原理,呵呵,便最好不过了!
    《易经》:“易有太极,是生两仪两仪四象,四象生八卦。”孔颖达疏:“太极谓天地未分之前,元气混而为一,即是太初、太一也。”
     由于时间仓促及水平有限,难免有些差错和不足,希望读者多多指教!
     高手勿喷,在此谢过代码的设计者!
原文地址:https://www.cnblogs.com/skl374199080/p/3108238.html