状态机实现按键检测

 

最近发现GPIO的中断功能有点问题,查了两天确实也没查出来为什么,毕竟中断管理也不没那么容易,所有暂且用扫描的办法来解决,下面这个算法很经典,记下,备以后参考.


--------------------------------------------file "key.h"----------------------------------------------

#ifndef KEY_H
#define KEY_H

/*----------------key definition--------------*/

#define  NO_KEY           0x00

#define  PLAY_KEY         0x01         /*  vcd   key   */
#define  STOP_KEY         0x02
#define  NEXT_KEY         0x03
#define  PREV_KEY         0x04
#define  REPEAT_KEY       0x05
#define  PROGRAM_KEY      0x06
#define  REMAIN_KEY       0x07
#define  VOCAL_ASSIST_KEY 0x08
#define  VOLUME_UP_KEY    0x09
#define  VOLUME_DOWN_KEY  0x0a
#define  TV_MODE_KEY      0x0b
#define  EJECT_KEY        0x0c
#define  FB_KEY           0x0d
#define  FF_KEY           0x0e

#define  POWER_KEY        0x20         /* common key  */
#define  CLOCK_KEY        0x21
#define  SLEEP_KEY        0x22
#define  FUNCTION_KEY     0x23
#define  TONE_KEY         0x24
#define  EQ_KEY           0x25
#define  SBASS_KEY        0x26
#define  RADIO_KEY        0x27
#define  TAPE_KEY         0x28
#define  AUX_KEY          0x29
#define  VCD_KEY          0x30

#define  MEM_KEY          0x31        /*  radio key  */
#define  MEM_MINUS_KEY    0x32
#define  MEM_PLUS_KEY     0x33
#define  AM_STEP_KEY      0x34
#define  BAND_KEY         0x35
#define  SEARCH_UP_KEY    0x36
#define  SEARCH_DOWN_KEY  0x37
#define  AUTO_SEARCH_UP_KEY     0x38
#define  AUTO_SEARCH_DOWN_KEY   0x39

/*---------------end key definition-----------*/

#define  KEY_IDLE_STATE     0
#define  KEY_SHAKE_STATE    1
#define  KEY_COMPLEX_STATE  2
#define  KEY_REPEAT_STATE   3
#define  KEY_WAIT_UP        4


extern unsigned char shake_cancel_timer;
extern unsigned char complex_key_timer;
extern unsigned char repeat_key_timer;
extern unsigned char current_key;
extern unsigned char current_state;

extern void scan_key();
extern void process_panel_key();
extern unsigned char is_repeat_key(unsigned char);

#endif

------------------------------------------------file "key.c"-----------------------------------------------

#include "key.h"
#include "display.h"

unsigned char current_state;    /* RADIO /  VCD  /TAPE /AUX */
unsigned char current_key;
unsigned char key;

unsigned char is_repeat_key(unsigned char);
void scan_key();
void process_panel_key();

/*====================================================================================================
                                    扫描面板按键程序
====================================================================================================*/
void scan_key()
{
   set_row1;
   set_row2;
   set_row3;
   set_row4;
   key = NO_KEY;

   clear_col1;
   set_col2;
   set_col3;
   set_col4;
   if (check_row1_low)     key = SEARCH_DOWN_KEY;   
   if (check_row2_low)     key = SEARCH_UP_KEY;
   if (check_row3_low)     key = BAND_KEY;  

   if (check_row4_low)     key = EJECT_KEY; 

   set_col1;
   clear_col2;
   set_col3;
   set_col4;
   if (check_row1_low)     key = MEM_MINUS_KEY;
   if (check_row2_low)     key = MEM_PLUS_KEY;
   if (check_row3_low)     key = MEM_KEY;
   if (check_row4_low)     key = AM_STEP_KEY;

   set_col1;
   set_col2;
   clear_col3;
   set_col4;
   if (check_row1_low)     key = SLEEP_KEY;   
   if (check_row2_low)     key = SBASS_KEY; 
   if (check_row3_low)     key = CLOCK_KEY;  
   if (check_row4_low)     key = VOLUME_DOWN_KEY;         

   set_col1;
   set_col2;
   set_col3;
   clear_col4;
   if (check_row1_low)     key = POWER_KEY;
   if (check_row2_low)     key = FUNCTION_KEY;
   if (check_row3_low)     key = TONE_KEY;  
   if (check_row4_low)     key = VOLUME_UP_KEY;

}

/*====================================================================================
                                   处理面板按键程序
=====================================================================================*/
unsigned char shake_cancel_timer;
unsigned char complex_key_timer;
unsigned char repeat_key_timer;
unsigned char scan_key_state;
unsigned char key_bak;
unsigned char repeat_key;


void process_panel_key()
{
  scan_key();
  switch (scan_key_state)
  {
    case KEY_IDLE_STATE:   //按键空闲状态
       if (key!=NO_KEY)  //如果有按键按下,则进入按键消抖状态。
     {
         key_bak = key;          
         shake_cancel_timer = 1;  //消抖时间设定为20ms
         scan_key_state = KEY_SHAKE_STATE;
       }else            //如果没有按键按下,继续为空闲检测状态。
       {
         scan_key_state = KEY_IDLE_STATE;
       }
     break;
    case KEY_SHAKE_STATE: //按键去抖状态
      if (!shake_cancel_timer)
      {
         if (key == key_bak)     //消抖后,如果按键未变,进入复合检测状态。
         {
            scan_key_state = KEY_COMPLEX_STATE;
            complex_key_timer = 100;  //复合判断时间为200ms 小于200ms为原功能,大于200ms为复合功能。
         }else                  //确认为按键抖动。
         {
            scan_key_state = KEY_IDLE_STATE;
         }
      }
     break;
   case KEY_COMPLEX_STATE: //按键复合处理状态
      if (!complex_key_timer)
      {
        if (key == key_bak)  //复合检测时间到,按键仍按下。
        {
            if (key == SEARCH_UP_KEY)       //执行next的复合功能。
            {
              current_key = AUTO_SEARCH_UP_KEY;
            }else if (key == SEARCH_DOWN_KEY) //执行prev的复合功能。
            {
              current_key = AUTO_SEARCH_DOWN_KEY;
            }else                     //执行没有复合功能的按键。
            {
              current_key = key;
            }

            if (is_repeat_key(key))   //检测为可重复按键时,进入重复状态。
           {
             repeat_key = current_key;
             scan_key_state = KEY_REPEAT_STATE;
             repeat_key_timer = 20; // 按键重复时间为200ms,如果连续按键,每200ms执行重复按键操作。
            }else                    //检测为不可重复按键时,进入按键抬起等待状态。
            {
             scan_key_state = KEY_WAIT_UP;
            }
         }else       //按键已经抬起,执行未复合功能。
         {
           current_key = key_bak;
           scan_key_state = KEY_IDLE_STATE;
         }
       }else         
       {
          if (key != key_bak)          //按键抬起,执行未复合功能。
          {
             current_key = key_bak;
             scan_key_state = KEY_IDLE_STATE;
           }
       }
      break;
    case KEY_REPEAT_STATE:    //按键重复处理状态
      if (key == key_bak)
      {
        if (!repeat_key_timer)    //按键重复时间到,再次执行按键功能。
        {
           repeat_key_timer = 20; // 按键重复时间为200ms,如果连续按键,每200ms执行重复按键操作。
           current_key = repeat_key;
        }
      }else                     //按键抬起,回到按键空闲检测状态。
      {
           scan_key_state = KEY_IDLE_STATE;
      }
     break;
   case KEY_WAIT_UP:             //按键等待抬起状态
     if (key!= key_bak)
     {
        scan_key_state = KEY_IDLE_STATE;   //按键抬起,返回按键空闲检测状态。
     }
    break;
  }

}
/*------------------------------------------------------------------------------------------------*/
unsigned char is_repeat_key(unsigned char r_key)    //重复按键检测通行函数。
{
   if ((r_key == VOLUME_UP_KEY)||(r_key == VOLUME_DOWN_KEY)||(r_key == SEARCH_UP_KEY)||(r_key == SEARCH_DOWN_KEY))
   {
       return 1;
   }else
   {
       return 0;
   }
}
/*-----------------------------------------------------------------------------------------------*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zyhorse2010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值