查看: 2333|回复: 9

[其他] 每天解决一个问题23:两种键盘扫描程序的比较

[复制链接]

该用户从未签到

33

主题

292

帖子

0

高级会员

Rank: 4

积分
600
最后登录
2016-4-19
发表于 2015-9-25 21:55:00 | 显示全部楼层 |阅读模式

地址:https://www.eefocus.com/luo_xinli/blog/15-03/310848_30574.html

新到公司同事写了一个键盘处理程序,我们可以浏览一下这段代码

/*********************************/
//采集当前键盘端口数据,并且返回键盘端口的值
/*********************************/
unsigned char scanKey( )
{
     unsigned char value1,value2;
     unsigned char  m,n;

     P2 =0xff;
     value1 = P2;

    if(value1!=0xff)
    {
        for(m=0;m<100;m++)
            for(n=0;n<100;n++);
         value2 = P2;

          if(value1==value2)
          {           
             while(P2!=0xff)
            {   

            }
         return value1;
     }
   }
   return 0xff;
}

这段代码运行是没有问题的,通过
        for(m=0;m<100;m++)
            for(n=0;n<100;n++);
         value2 = P2;

          if(value1==value2)
          {           
             while(P2!=0xff)
            {   

            }
         return value1;

实现了键盘去抖。关于键盘一般书上也是这么介绍的。但是这段代码确实有不足之处。首先 for(m=0;m<100;m++)
    for(n=0;n<100;n++); 是延时代码,程序一直会停留在这里,浪费了系统的效率,是系统响应其他任务的变得迟钝。而且容易造成看门狗复位。在EMC实验中容易造成系统不稳定。如果有长按下键盘不太容易实现。

    我找到另外一位工程师的一段键盘代码,如下:

  sbit SET_KEY_PIN      = P2^1;  // 设定键盘 S1
  sbit WATER_KEY_PIN    = P1^7;  // 排水键盘 S3
  sbit UP_KEY_PIN       = P2^2;  // 加键  S2
  sbit DOWN_KEY_PIN     = P2^5;  // 减键  S4
  sbit STOP_KEY_PIN     = P2^4;   // 停机键 S5
  sbit START_KEY_PIN    = P2^0;   // 启动键 S6

  sbit SET_CF_PIN       = P3^0;   //设定也许键盘

  static unsigned int  KEY_VALUE =0;

unsigned char readKey( )
{
    unsigned char keyValue = 0x00;

     SET_KEY_PIN      =1;  
     WATER_KEY_PIN    =1;
     UP_KEY_PIN       =1;
     DOWN_KEY_PIN     =1;
     STOP_KEY_PIN     =1;
     START_KEY_PIN    =1;
  if( !SET_KEY_PIN )    keyValue  = SET_KEY_BIT;
  if( !WATER_KEY_PIN )  keyValue |= WATER_KEY_BIT;
  if( !UP_KEY_PIN )     keyValue |= UP_KEY_BIT;
  if( !DOWN_KEY_PIN )   keyValue |= DOWN_KEY_BIT;
  if( !STOP_KEY_PIN )   keyValue |= STOP_KEY_BIT;
  if( !START_KEY_PIN )  keyValue |= RUN_KEY_BIT;
  return keyValue;
}

void keyScan( )
{
    static unsigned char stateMachine = 0;
    static unsigned char keyValue1 = 0;
    static unsigned char keyValue2 = 0;

    switch( stateMachine )
    {
      case 0:
             keyValue1=readKey( );
             if(!keyValue1) return;
             KEY_DELAY_DEC_TIMER = KEY_DELAY_DEC_TIMER_MAX;
             stateMachine = 1;        
           break;
      case 1:
          if( KEY_DELAY_DEC_TIMER )
          {
               keyValue2=readKey( );

              if( keyValue1 != keyValue2) stateMachine = 0;
           }
           else
           {
               if(( keyValue2== STOP_KEY_BIT )
                   ||( keyValue2== SET_KEY_BIT ))
               {
                   stateMachine = 2;
                   KEY_DELAY_INC_TIMER =0;
                }
               else
               {
                    KEY_VALUE = keyValue2;
                    stateMachine = 3;
               }

            }
         break;
       case 2: //等待延时3秒以上
             keyValue2 = readKey( );
             if( keyValue2 )
             {
                  if( KEY_DELAY_INC_TIMER > KEY_DELAY_INC_TIMER_MAX)  
                  {                  
                      if(keyValue2== STOP_KEY_BIT )
                  {
                      //清除错误
                      KEY_VALUE = CLEAR_ER_KEY_CMD;
                   }
                   else
                   {

                       if( keyValue2== SET_KEY_BIT )
                       {

                           //设定键--进入用户设定菜单
                           KEY_VALUE = ENTER_USER_MENU_CMD;
                        }
                       else
                        {
                             KEY_VALUE = 0;

                         }
                    }
                      stateMachine = 3;
                 }
             }
            else
            {

                     KEY_VALUE = keyValue1;
                      stateMachine = 3;
            }

             break;
     case 3:  //等待键盘释放
               keyValue2 = readKey( );
               if( !keyValue2 )
               {
                   stateMachine = 0;
               }  
               break;
     default:
              break;
   }
}

unsigned int getKey( )
{
    unsigned int keyVlue ;

     keyVlue = KEY_VALUE;

     KEY_VALUE = 0x00;

      return keyVlue;

}

    readKey( )是读取键盘IO脚电压。键盘弹起时IO脚电平为低,键盘按下时IO脚电平位高。读取并且返回。 keyScan( )是键盘扫描程序,调用 readKey( )更新本地全局变量KEY_VALUE 。KEY_DELAY_DEC_TIMER 是键盘扫描定时器,在定时器中递减。代码如下:
INTERRUPT (TIMER4_ISR, INTERRUPT_TIMER4)
{
    if( KEY_DELAY_DEC_TIMER > 0 ) KEY_DELAY_DEC_TIMER--;
    TMR4CN &= ~0xC0;                    // Clear Timer 4 overflow/underflow flag


}

在KEY_DELAY_DEC_TIMER_MAX定时器中断次数时间范围完成一次键盘扫描。采用了类似状态机的处理方法。主程序每执行一次keyScan( ),读取一次IO脚,执行效率比较高,键盘处理任务需要的时间比较短。在KEY_DELAY_DEC_TIMER时间范围内更新一次KEY_VALUE 。 getKey( )是提供给应用程序,获取当前键盘的稳定状态的值。并且将KEY_VALUE 清零。程序架构比较好,分层也很清楚!

我们看看在主程序调用:
   while(1)
  {
      Watchdog_operation(FEED);

   。。。。
     keyScan( );
     key = getKey( );
     exeKeyCmd( key );
   。。。。。


   }

   我推荐这位工程师的键盘处理方法,显得比较成熟、老练。扩展性好,代码复用率也很好!



我知道答案 目前已有9人回答
回复

使用道具 举报

  • TA的每日心情
    开心
    2018-7-23 21:04
  • 签到天数: 103 天

    连续签到: 1 天

    [LV.6]常住居民II

    228

    主题

    5379

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    16704
    最后登录
    1970-1-1
    发表于 2015-9-25 23:29:49 | 显示全部楼层
    多谢分享,第2种也很庞大哈
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    33

    主题

    292

    帖子

    0

    高级会员

    Rank: 4

    积分
    600
    最后登录
    2016-4-19
     楼主| 发表于 2015-9-26 22:17:46 | 显示全部楼层
    lkl0305 发表于 2015-9-25 23:29
    多谢分享,第2种也很庞大哈

    不谢 不谢
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2017-2-9 14:16
  • 签到天数: 17 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    25

    主题

    1785

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2250
    最后登录
    2024-6-11
    发表于 2015-9-26 22:50:58 | 显示全部楼层
    谢谢楼主分享
    freescaleic.org.png
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    33

    主题

    292

    帖子

    0

    高级会员

    Rank: 4

    积分
    600
    最后登录
    2016-4-19
     楼主| 发表于 2015-9-27 16:12:58 | 显示全部楼层

    又在刷金币额
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    69

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    280
    最后登录
    2016-3-18
    发表于 2015-10-22 00:05:21 | 显示全部楼层
    多谢分享  最近正在写类似程序
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    51

    主题

    307

    帖子

    0

    高级会员

    Rank: 4

    积分
    651
    最后登录
    2020-9-4
    发表于 2015-10-22 09:01:47 | 显示全部楼层
    aasd 发表于 2015-10-22 00:05
    多谢分享  最近正在写类似程序

    呵呵,很好
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-6 07:38
  • 签到天数: 736 天

    连续签到: 1 天

    [LV.9]以坛为家II

    21

    主题

    3486

    帖子

    6

    金牌会员

    Rank: 6Rank: 6

    积分
    5093
    最后登录
    2024-1-7
    发表于 2015-10-22 09:07:40 | 显示全部楼层
    谢谢分享
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    该用户从未签到

    24

    主题

    167

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    446
    最后登录
    2018-6-11
    发表于 2015-10-22 10:32:59 | 显示全部楼层
    学习学习     
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    189

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    244
    最后登录
    2020-10-19
    发表于 2015-10-22 13:05:05 | 显示全部楼层
    利用状态机键盘扫描效率高很多啊
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-22 15:51 , Processed in 0.109626 second(s), 31 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表