嵌入式C语言高级编程之复杂按键扫描状态机

通常普通的按键扫描程序,网上一大堆,基于扫描延时防抖等简单的操作,这里要讲的的遇到复杂的按键处理程序,

 

普通按键扫描:基于 一个按键的短按长按释放

复杂的按键扫描:有组合按键,且按键也有长短按,以及释放

现在如何实现一个按键扫描模块去处理这种按键扫描程序呢?这里用到按键状态机为基础框架。对按键编码能较好的实现复杂按键处理。

 

 

一、对按键进行编码具体实现参考如下

//代表按键按下的电平 用来切换不同的电路 一般都如下

#define PRESS      0X00           //低电平表示按下
#define RELEASE    0X01            //搞电平表示未按下

//这里有六个按键,借用六位

#define USER_KEY_ALL_MSK   0x003F

#define USER_KEY1_PORT   P1
#define USER_KEY1_PIN    BIT0
#define USER_KEY1        P10

#define USER_KEY1_MSK   0x0001
#define USER_KEY1_POS   0

#define USER_KEY2_PORT   P1
#define USER_KEY2_PIN    BIT1
#define USER_KEY2        P11
#define USER_KEY2_MSK   0x0002
#define USER_KEY2_POS    1



#define USER_KEY3_PORT   P1
#define USER_KEY3_PIN    BIT2
#define USER_KEY3        P12

#define USER_KEY3_MSK   0x0004
#define USER_KEY3_POS    2


#define USER_KEY4_PORT   P1
#define USER_KEY4_PIN    BIT3
#define USER_KEY4        P13

#define USER_KEY4_MSK   0x0008
#define USER_KEY4_POS    3


#define USER_KEY5_PORT   P1
#define USER_KEY5_PIN    BIT4
#define USER_KEY5        P14

#define USER_KEY5_MSK   0x0010
#define USER_KEY5_POS    4


#define USER_KEY6_PORT   P4
#define USER_KEY6_PIN    BIT2
#define USER_KEY6        P42

#define USER_KEY6_MSK   0x0020
#define USER_KEY6_POS    5

//状态机,一个简单的状态,你可以设计更复杂,短按释放,长按释放,长按不释放、、等各个状态

typedef enum
{
   KEY_NULL = 0,
   KEY_PRESS,
   KEY_LONG_PRESS,
   KEY_RELEASE,

}Type_Key_Status;




二、定义实现上部分就可以对按键检测编码了,按键检测,得到按键键值编码。

     由于没有找到合适的办法循环处理,让代码更简洁,所以只能每一个按键都检测一次。

uint16_t read_key(void)
{
    uint16_t key_value =0;  
  

       if(USER_KEY1 == PRESS)
       {

         key_value |=(0x01<<USER_KEY1_POS);
       }
       else
       {
         key_value |=(0x00<<USER_KEY1_POS);
       }
       
  
       if(PRESS == USER_KEY2 )
       {
         key_value |=(0x01<<USER_KEY2_POS);
       }
       else
       {
         key_value |=(0x00<<USER_KEY2_POS);
       }       
       
       if(PRESS ==USER_KEY3)
       {
         key_value |=(0x01<<USER_KEY3_POS);
       }
       else
       {
         key_value |=(0x00<<USER_KEY3_POS);
       }       
              
       if(USER_KEY4 == PRESS)
       {
         key_value |=(0x01<<USER_KEY4_POS);
       }
       else
       {
         key_value |=(0x00<<USER_KEY4_POS);
       }       
              
       if(USER_KEY5 == PRESS)
       {
         key_value |=(0x01<<USER_KEY5_POS);
       }
       else
       {
         key_value |=(0x00<<USER_KEY5_POS);
       }       
              
       if(PRESS == USER_KEY6)
       {       
         key_value |=(0x01<<USER_KEY6_POS);
       }
       else
       {
        
         key_value |=(0x00<<USER_KEY6_POS);
       }       
        return key_value;      
}

三、最后也是最重要的一步就是按键状态扫描的实现。

// 定义一个全局的按键状态

Type_Key_Status key_status = KEY_NULL;

void key_scan(void)
{
  uint16_t old_key_value = 0,new_key_value =0;
   
  switch(key_status)
  {
    case KEY_NULL:
                  old_key_value = read_key();
                  if(old_key_value == 0)       //没按键按下
                  {
                    return;
                  }
                  delay_ms(50);                  
                  new_key_value = read_key();
                  if(old_key_value == new_key_value)
                  {
                     old_key_value = new_key_value;    //有键按下,状态跳转
                     key_short_press_callback(new_key_value) //回调按下处理函数
                     key_status = KEY_PRESS;
                    
                  
                  }else
                  {
                      key_status = KEY_NULL;
                  }                  
    break;                  
      
   case KEY_PRESS:
                  
                   delay_ms(50);
                   new_key_value = read_key();
                  if(old_key_value == new_key_value)
                  {
                     old_key_value = new_key_value;
                     key_long_press_callback(new_key_value); //回调长按下处理
                     key_status = KEY_LONG_PRESS;
                  
                  }else
                  {

                      key_short_release_callback(new_key_value); //回调短按释放处理
                      key_status = KEY_RELEASE;
                  }        
       
   break;  

   case KEY_LONG_PRESS:

                  delay_ms(50);
                   new_key_value = read_key();
                  if(old_key_value == new_key_value)
                  {
                     old_key_value = new_key_value;
                     key_long_long_press_callback(new_key_value); //回调超长按下处理
                     key_status = KEY_RELEASE;  //更具自定义功能状态去跳转

                  
                  }else
                  {

                      key_long_release_callback(new_key_value); //回调长按释放处理
                      key_status = KEY_RELEASE;
                  }  
   
   
   break;
       
  case KEY_RELEASE:
    
          release_key_handle();
          key_status = KEY_NULL;   //释放回到正常检测状态
       break;
    
  }

  


};

四、最后就是在各个按键状态的基础上实现处理函数,这里就可以对编码的那就值进行解析,分别处理,对于按键释放有组合也很好处理。

void key_short_press_handle(uint16_t key_value)
{
 
  switch(key_value & USER_KEY_ALL_MSK)
  {
  //没有组合键  
    
    case USER_KEY1_MSK:
      
    break;
    case USER_KEY2_MSK:
 
  
    break;
    case USER_KEY3_MSK:  

    break;
    case USER_KEY4_MSK:  
      

    break;
    case USER_KEY5_MSK:  

    break;
    case USER_KEY6_MSK:  

    break;
    
 //组合按键
    case  USER_KEY1_MSK|USER_KEY2_MSK  :  break;
 
    ...
  }
  
  

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章