网站公告列表     本站开通全国范围代收货款业务,详情请点击  [dycxin  2008年5月14日]        
加入收藏
设为首页
联系站长
您现在的位置: EDA加油站 >> 51单片机 >> 实验板DIY >> 多功能实验板 >> 正文
  [推荐]键盘扫描改进方法详解           ★★★ 【字体:
键盘扫描改进方法详解
键盘扫描改进方法详解
作者:未知    51单片机来源:本站原创    点击数:    更新时间:2008-8-14    

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

好了,我们来个改进版的按键扫描程序
键盘按下?YES---延时去抖----键盘按下?YES-----确实按下了,按键有效---A按键释放?YES--退出
   NO                           NO                                       NO
  退出                         退出                                    返回A
这是大多数人的按键扫描程序,在一般的场合也能用。这个程序比第一个要好点,但也好不到哪里去。为什么?判断按键释放的方法太笨了,如果我们一直按下这个键盘会怎么样?程序在此死等,可能你说我还有中断,但中断处理完了你还得回来傻等!而且其他按键也将被屏蔽。现在我来谈谈自己的看法 。先假设按键平时是高电平,按下后是低电平。也就是按键低电平有效
那么一个完整的按键过程会发生什么?按键输入脚电平变化顺序是  高----》低----》高
                                                          未按键  按下键   键释放
真正的高手看到这里就恍然大悟,后面的基本不用看了。
好的按键扫描程序不是判断按键是否被按下,而是判断按键电平变化的变化顺序是否符合  高----》低

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

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

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

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

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

我的按键是这样处理的
1.读健状态,与上次健状态比较,不同,更新健状态和当前时间,相同则时间不变(或者加一)
2.当前时间与最后一次更新按键时间比较,超出规定时间,则可以判断健已经稳定。
3.与以前比较,就可以进行健处理了。

缺点,用的RAM多,优点,不等待

#include<reg52.h>
#include<keydefine.h>

void ReadKey(void)
{
        byte i,Temp0;
        bit KeyFlag;
        static byte Q0;         

        P1 = 0xff;
        Temp0 = ~P1;

        if(Temp0 != Qsw0)
        {
               Qsw0 = Temp0;
                KeyTime = Time20ms;
        }
        else
        {
                if(Time20ms - KeyTime > 3)
                        {KeyFlag = 1;}         
        }

        if(KeyFlag)
        {        KeyFlag = 0;

                i = Qsw0 &~Q0 & 0xbb; //健按下
                if(i)
                {  
                        if(i & 0x80)        {KeyValue = BryRightKey;}
                        if(i & 0x20)        {KeyValue = AddRightKey;}
                        if(i & 0x10)        {KeyValue = SubbRightKey;}
                        if(i & 0x08)        {KeyValue = ReadPhotoRightKey;}
                        if(i & 0x02)        {KeyValue = LgyRightKey;}
                        if(i & 0x01)        {KeyValue = LightRightKey;}
                }

               i = Q0 &~Qsw0  & 0xbb; //健松开
                if(i)
                {
                   //健松开,处理代码;
                }   
                Q0 = Qsw0;         
        }
}
这是我的一个项目中的键盘扫描函数,基于UCOSII的,功能有按下处理一次,连续按住一段时间能连续处理,函数返回键值,键盘扫描是单独一个任务,定时扫描的,在时间上没有大的等待,这样说可以帮助理解


INT8U KeyScan(void)
{
    static INT8U keyrepeat,keyprevalue,times,fastad;
    INT8U KeyOut=0xfb;
    INT8U keyvalue;
    INT8U keyfirst;
    for(;KeyOut!=0x1f;KeyOut=KeyOut>>1)
    {
      KeyOutPort &= 0xf8;
      KeyOutPort |= (KeyOut&0x07);
      __delay_cycles(5);
      keyvalue = KeyInputPort&0x38;
      if(keyvalue!=0x38)
      {
          keyvalue |= (KeyOut&0x07);
          if(keyprevalue==keyvalue)
          {
              if(keyrepeat!=0xff) keyrepeat=0xff;
              else if((keyvalue==KeyLeft)||(keyvalue==KeyRight)||(keyvalue==KeyUp)||(keyvalue==KeyDown))
              {
                  if(fastad==0xff)    //针对调整按键 进行快速按键处理
                  {
                      if(times>=(100/KeyScanDelay)) times=0;
                      else
                      {
                          times++;
                          keyvalue=0xff;
                      }
                  }
                  else if(times>=(1000/KeyScanDelay))
                  {
                      fastad=0xff;
                      times=0;
                  }
                  else  
                  {
                      times++;
                      keyvalue=0xff;
                  }
              }
              else keyvalue=0xff;
          }
          else  
          {
              keyprevalue = keyvalue;
              keyfirst = 0xff;
          }
          break;
      }
      else keyvalue = 0;
    }
    if(keyvalue==0)  
    {
        keyrepeat = 0;
        keyprevalue = 0;
        times = 0;
        fastad = 0;
    }
    else if((keyvalue==0xff)||(keyfirst==0xff)) keyvalue = 0;
    return keyvalue;
}
51单片机录入:dycxin    责任编辑:dycxin 
  • 上一个51单片机:

  • 下一个51单片机:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    DS18B20温度传感器C51程序,…
    基于频谱分析的机电设备状态…
    AT89s8252单片机在3G基站控制…
    单片机实现智能荧光鉴伪
    智能盲人导行仪的设计与实现
    基于AT89C51型单片机的CAN总…
    STC单片机IO管脚毁坏动态自检…
    具备跳号跳频和跳址的nrf905…
    51单片机边沿触发中断响应时…
    8051单片机在线升级软件的方…
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    EDA加油站|我要EDA网|山东电子网--东营市荣燕商贸有限公司版权所有! 站长:阿荣
    联系电话:0546-7870320,13371507828 电邮:51edacn@163.com
    山东东营西城济南路百祥电脑商城B302室 邮编:257000 鲁ICP备07018763号  鲁ICP备07000091号 鲁ICP备05003434号
    公司帐号:1615011209000037682 户名:东营市荣燕商贸有限公司 开户行:工行西城支行石油大学分理处