思路决定出路--键盘扫描详解_自强不息,厚德载物_百度空间

按键扫描是每个搞单片机的都会遇到的问题,也是一个开发人员必须具备的基本功。先从最基本的说起。在此声明,没有代码,也不要向我要代码,也不想穿裤子,如果你看了帖子还写不出代码,那么我只能说你太笨了。。。。。。。。还是那句话,搞开发重要的是思想,而不是代码,代码只是工具
通常的按键扫描程序是这样做的
键盘按下?YES---延时去抖----键盘按下?YES-----确实按下了,按键有效---退出
    NO                            NO
   退出                          退出
很多教材上都是这样写,但这个程序却是误人子第的
问题来了,这个程序不太好用,有时按一下,或按久一点,程序会认为你按了很多次!!为什么???
因为没有判断按键释放,当我们按下键盘时,程序可能已经跑了N个来回了。

好了,我们来个改进版的按键扫描程序
键盘按下?YES---延时去抖----键盘按下?YES-----确实按下了,按键有效---A按键释放?YES--退出
    NO                            NO                                        NO
   退出                          退出                                     返回A
这是大多数人的按键扫描程序,在一般的场合也能用。这个程序比{dy}个要好点,但也好不到哪里去。为什么?判断按键释放的方法太笨了,如果我们一直按下这个键盘会怎么样?程序在此死等,可能你说我还有中断,但中断处理完了你还得回来傻等!而且其他按键也将被屏蔽。

那么,让我们好好想想该怎么做。。。。。。。(未完待续,欢迎大家跟贴,谈一下自己的解决方法;看有没有同道中人)

继上:

==============================================================================
言归正传,其实楼下很多人都给出了较好的按键扫描程序,但没有人解释一下为什么要那么做。
现在我来谈谈自己的看法 。先假设按键平时是高电平,按下后是低电平。也就是按键低电平有效
那么一个完整的按键过程会发生什么?按键输入脚电平变化顺序是   高----》低----》高
                                                           未按键   按下键    键释放
真正的高手看到这里就恍然大悟,后面的基本不用看了。
好的按键扫描程序不是判断按键是否被按下,而是判断按键电平变化的变化顺序是否符合   高----》低

----》高 ,其他的按键电平变化顺序都是非法的 。这是按键扫描的基本原理。那么该怎么来判断呢?
进入按键扫描后,我们可能会扫到高电平,那么就需要判断到底是未按键导致的高电平还是按下后键释

放导致的高电平,这里用一个位变量(取名为键前状态,1=曾经按下,0=未按下)做为标志就可以了;

也可能会扫到低电平,那么需要判断这个低电平是由未按键到按下键得到的,还是扫描之前本来就是低

电平,这里也用一个位变量(取名为键有效1=有效,0=无效)做为标志。好了,下面给一个简单的流程
主程序初始化操作,键前状态=0,键有效=0
                                        按键扫描流程
     
键盘===高电平----》键有效=1--》A1键盘曾经按下后变成高电平,键盘已释放,复位键前状态=0---》退出
   !            !
   !            --》键有效=0--》未按下---》退出
   !     
   !     
   !     
   !===低电平----》键前状态=1--》键盘曾经按下,现在仍然是低电平--》退出
                !
                --》键前状态=0--》未按下---》A2键盘由高电平变成低电平,置键有效=1,键前状态=1;---》退出

为了突出重点,这个流程没有加去抖处理,想要稳定的效果,必须加延时去抖处理。按这个流程处理按键,响应速度快,
也不会误判。你就是按{yt}也,不会傻等。按键有效之后,每次只进来看一下就走。{zd0}的好处就是可以实现真正的模块化
按键处理xx由这个程序控制,不必在其他地方判断按键释放没有。
另外再简单谈一下长按,短按的判断。要判断长按,在按键有效之后(A2处)启动定时器,然后在按键释放(A1处)后判断时
间的长短,大于一定时间算长按。至于组合键盘的处理,在上面的流程上稍加改动就可以实现,等有时间再详谈。

转自:ouravr

QUOTE:

起先我也是按楼主说的{dy}种方法,按下后,判断,延时,处理程序,等待按键释放。但是发现这样真的很浪费单片机的时间, 所以现在换成了用定时器来扫描按键,如果定时时间到才判断按键是否释放 。不知道这 ... shenwen11 发表于 2009-5-21 16:01
在中断里处理按键自然响应更快,不过你的这个方法有漏洞。如果在定时时间未到的时候按键松开一下又按下,那么在你定时时间到的时候认为是一直按下的。特别是判断长按的时候。可以这么做:开个定时器,定时间隔可以定为1毫秒。在定时器ISR里检测按键,采用一个全局变量对按下时长做计数。这样可以准确得出按键按下的时长,作为区分长短按的依据。

#pragma interrupt_handler miao:9
void miao()
{
   TCNT1L=0XF7;
TCNT1H=0XC2;
if(key_press==255)//按键按下
key_press=0
key_press++;
}
void key_p(unsigned char m)
{
if(PINC&0Xff!=0Xff)&&(t==0))//按键按下,并等待m次中断后
   {
    t=1;//不再满足此条件,t为全局变量
    key_press=0;//定时器标志清零
   }
if((key_press>=m)&&(PINC&0Xff!=0Xff))//定时时间到
   {
    switch(PINC)
    {
     case 0:PORTD=0X01;break;
     case 1:PORTD=0X02;break;
     case 3:PORTD=0x03;break;
     default PINC=0;break;
    }
   }
if(PINC!=0xff)
   t=0;//允许按键再次按下
}
/*
方法2
___________________________________________________________________
*/
#pragma interrupt_handler miao:9
void miao()
{
   TCNT1L=0XF7;
   TCNT1H=0XC2;
if(PINC!=0XFF)
   key_press++;
else
   key_press=0;
}
void key_p(unsigned char m)//如果定时时间长,这里可以换成unsigned int
{
if(PINC!=0Xff)&&(m>=key_press))//按键按下,并等待m次中断后
   {
    PORTD=0X00;//执行语句;
   }
if(key_press>=250)
   key_press=250;//
}

_______________A

以上程序未验证,

我是这样编的,不知道 对不对。



郑重声明:资讯 【思路决定出路--键盘扫描详解_自强不息,厚德载物_百度空间】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——