天天看點

多功能(單擊、輕按兩下、長按)按鍵設計

多功能(單擊、輕按兩下、長按)按鍵設計

使用者基本操作定義:  

   1.長按事件:任何1次出現的長按操作都屬于長按事件  

   2.單擊事件:1次短按操作後,間隔0.5s内沒有短按操作  

   3.輕按兩下事件:2次短按操作間隔時間<0.5s,則2次短按操作為1次輕按兩下事件,且2次短按都取消  

特别操作情況定義: 

   1.短按操作和長按操作間隔<0.5s,以及,長按操作和短按操作間隔<0.5s,均不産生輕按兩下事件 

   2.連續n次(n為奇數)短按操作,且間隔均<0.5s,産生(n-1)/2次輕按兩下事件+1次單擊事件 

   3.連續n次(n為偶數)短按操作,且間隔均<0.5s,産生n/2次輕按兩下事件 

對按鍵操作者的建議:     

   由于按鍵的多功能性質,建議操作者每次在單擊/長按/輕按兩下按鍵事件發生後,隔0.5s後再進行下一次的按鍵操作。因為在特别操作情況下,程式是保證按定義進行判斷和處理的,主要是怕操作者自己記不清楚導緻操作失誤。 

對軟體設計者的要求: 

   1.應該全面進行分析,給出嚴格定義和判斷條件,如上所示。如果自己都不清楚,你的設計出的系統就不穩定,不可靠。 

   2.在1的基礎上,編寫出符合要求的程式,并進行全面測試。 

具體程式如下:

/*============= 
低層按鍵(I/0)掃描函數,即低層按鍵裝置驅動,
隻傳回無鍵、短按和長按。具體輕按兩下不在此處判斷。
===============*/ 
#define key_input    HAL_GPIO_ReadPin(GPIO_Key,GPIO_Key_Pin)    // 按鍵輸入口  

#define N_key    0             //無鍵  
#define S_key    1             //單鍵  
#define D_key    2             //雙鍵  
#define L_key    3             //長鍵  
#define key_state_0 0  
#define key_state_1 1  
#define key_state_2 2  
unsigned char key_driver(void)  
{  
    static unsigned char key_state = key_state_0, key_time = 0;  
    unsigned char key_press, key_return = N_key;  
    key_press = key_input;                    // 讀按鍵I/O電平  
    switch (key_state)  
    {  
      case key_state_0:                              // 按鍵初始态  
        if (!key_press) key_state = key_state_1;      // 鍵被按下,狀态轉換到按鍵消抖和确認狀态  
        break;  
        
      case key_state_1:                      // 按鍵消抖與确認态  
        if (!key_press)  
        {  
             key_time = 0;                   //   
             key_state = key_state_2;   // 按鍵仍然處于按下,消抖完成,狀态轉換到按下鍵時間的計時狀态,但傳回的還是無鍵事件  
        }  
        else  
             key_state = key_state_0;   // 按鍵已擡起,轉換到按鍵初始态。此處完成和實作軟體消抖,其實按鍵的按下和釋放都在此消抖的。
        break;  
        
      case key_state_2:  
        if(key_press)  
        {  
             key_return = S_key;        // 此時按鍵釋放,說明是産生一次短操作,回送S_key  
             key_state = key_state_0;   // 轉換到按鍵初始态  
        }  
        else if (++key_time >= 100)     // 繼續按下,計時加10ms(10ms為本函數循環執行間隔)  
        {  
             key_return = L_key;        // 按下時間>1000ms,此按鍵為長按操作,傳回長鍵事件  
             key_state = key_state_3;   // 轉換到等待按鍵釋放狀态  
        }  
        break;  
      case key_state_3:                 // 等待按鍵釋放狀态,此狀态隻傳回無按鍵事件  
        if (key_press) key_state = key_state_0; //按鍵已釋放,轉換到按鍵初始态  
        break;  
    }  
    return key_return;  
}      
/*=============  
中間層按鍵處理函數,調用低層函數一次,處理輕按兩下事件的判斷,傳回上層正确的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。
本函數由上層循環調用,間隔10ms  
===============*/  

unsigned char key_read(void)  
{  
    static unsigned char key_m = key_state_0, key_time_1 = 0;  
    unsigned char key_return = N_key,key_temp;  
      
    key_temp = key_driver();  
      
    switch(key_m)  
    {  
        case key_state_0:  
            if (key_temp == S_key )  
            {  
                 key_time_1 = 0;               // 第1次單擊,不傳回,到下個狀态判斷後面是否出現輕按兩下  
                 key_m = key_state_1;  
            }  
            else  
                 key_return = key_temp;        // 對于無鍵、長鍵,傳回原事件  
            break;  

        case key_state_1:  
            if (key_temp == S_key)             // 又一次單擊(間隔肯定<500ms)  
            {  
                 key_return = D_key;           // 傳回輕按兩下鍵事件,回初始狀态  
                 key_m = key_state_0;  
            }  
            else                                 
            {                                  // 這裡500ms内肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層傳回的都是無鍵  
                 if(++key_time_1 >= 50)  
                 {  
                      key_return = S_key;      // 500ms内沒有再次出現單鍵事件,傳回上一次的單鍵事件  
                      key_m = key_state_0;     // 傳回初始狀态  
                 }  
             }  
             break;  
    } 
    return key_return;  
}      

下面,根據程式分析按鍵事件的反映時間: 

  1.對于長鍵,按下超過1s馬上響應,反應最快 

  2.對于雙鍵,第2次按鍵釋放後馬上得到反應。 

  3.對于單鍵,釋放後延時拖後500ms才能響應,反應最慢。這個與需要判斷後面是否有輕按兩下操作有關,隻能這樣。實際應用中,可以調整兩次單擊間 隔時間定義,比如為300ms,這樣單擊的響應會快一點,單按鍵操作人員需要加快按鍵的操作過程。如果産品是針對老年人的,這個時間不易太短,因為年紀大的人,反應和動作都比較慢。 

  當然,上面兩段可以合在一起。這樣做的目的,是為了可以友善的擴充為N擊(當然,需要做修改)。可是最底層的就是最基本的操作處理短按和長按,不用改動的。至于輕按兩下,還是N擊,在中間層處理。這就是程式設計中分層結構的優點。 

測試代碼環境如下:  

void TIM4_IRQHandler(void)       // 10ms定時器中斷
{  
       time_10ms_ok = 1;  
} 


main(viod)   
{   
    .........   
    while   
    {   
        if (time_10ms_ok)            //每10ms執行一次,   
        {   
             time_10ms_ok =0;   
             key = key_read();       //《====== 10ms一次調用按鍵中間層函數,根據傳回鍵值,點亮不同的LED燈,全面測試按鍵操作是否正常   
             if (key == L_key)   
                 ........//
             else if(key == D_key)   
                 ........//  
             else if(key == S_key)   
                 ........//   
         }   
     }   
}      

  通過以上程式即可實作多功能按鍵的設計。在實際應用中可能還有不同需求變化,再在此架構上對程式進行調整即可。