嵌入式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;
 
    ...
  }
  
  

}

 

 

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