一種相對高效的按鍵消抖方法

按鍵軟件消抖自我接觸單片機開始就已經存在這個問題了,網上的辦法無非是延時消抖和定時輪詢。對於寫裸機的我來說這兩種方法都不可避免的會有資源浪費掉,今天突然有了靈感,想到了一種相對高效的辦法來解決消抖問題。

硬件平臺:STM32F103RCT6開發板

開發環境:WIN7-64bit+MDK5+STD庫

按鍵消抖的必要性在此我就不多說了。直接步入正題。

在使用本方法前請注意,本方法需要一個全局時間戳的支持。

第一步:初始化全局時間戳的定時器,一般採用SysTick定時器來產生,每ms一次tick即可。

第二步:初始化按鍵對應的IO,複用爲邊沿觸發的外部中斷。

第三步:在外部中斷函數中添加按鍵事件處理函數。

代碼如下:

typedef struct _Key_t
{
    u32 last_time;
    enum
    {
        May_Press,
        Release,
    }private_state;
    enum
    {
        No_Press,
        Short_Press,
        Long_Press,
    }state;
}Key_t;

#define Is_ShortPress_Threshold   1500
簡單定義一個按鍵狀態的結構體,用於管理每個按鍵的狀態。順便再定義一個長短按的識別閾值,用於區分按鍵的長短按。

if(key_state.private_state==Release)                
{
    if(KEY==0)
    {
        key_state.private_state=May_Press;
        key_state.last_time=course_ms();
    }
}
else if(key_state.private_state==May_Press)
{
    if(KEY==1)
    {
        if((course_ms()-key_state.last_time>10)&&(course_ms()-key_state.last_time<Is_ShortPress_Threshold))
        {
            key_state.state=Short_Press;
            key_state.private_state=Release;
        }
        else if(course_ms()-key_state.last_time>Is_ShortPress_Threshold)
        {
            key_state.state=Long_Press;
            key_state.private_state=Release;
        }
        else
            key_state.private_state=Release;
    }
}
以上爲需要添加到中斷處理函數的按鍵事件處理函數,算法的核心是一個狀態機。在本例中,按鍵被默認上拉,按下接地。course_ms()爲獲取全局時間戳的函數。

思路解釋如下:按鍵狀態結構體有一個用於識別的狀態位,默認處於Release,也就是釋放的狀態。一旦按鍵被按下,中斷觸發,此時檢查是否是Relase狀態,如果是就檢查按鍵是否被拉低,如果是,此時進入May_Press狀態,也就是可能是按下的,並且記錄此時的時間戳,這一步是消抖的關鍵。當按鍵被釋放,由於是邊沿觸發,會再次進行處理,此時檢查和上一次觸發之間的時間戳之差,如果小於10ms我們就認爲是抖動,此時不會對按鍵輸出狀態進行修改,而是直接將按鍵狀態置回Relase狀態,反之檢查差值和長短按閾值之間的關係,將state置位爲對應的狀態。消抖的核心在於記錄時間戳,而這只是一個簡單的賦值操作,並不耗費時間。

效率上來說,延時消抖花費時間在無意義延時上,而相對較好的定時輪詢還是不可避免的在輪詢,而現在這種方式完全是中斷性質的。唯一多出的開銷(全局時間戳)並不是只可以用於按鍵消抖,另外在HAL庫中存在直接獲取tick的函數,這樣實現就更方便了。經實際測試,消抖效果可以達到其他兩種消抖算法的水平。




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