軟體 debounce 的方法 (使用 IOC 中斷及 TMR0 計時,而非 Delay() 函式。)

在網路 google 出來的 debounce 方式,多半是使用 delay function,這是最簡單、但是實作時不可使用的方式。

以最常用的 tack Siwtch 來說,每次操作按鍵,需要 20 msec 的 debounce 時間,用 delay function 來 debounce 實在太不理智了!!

以下這段程式碼,使用的 IC 是 PIC16F1527,它的 IOC 可以設成上升緣觸發或下降緣觸發,這樣很方便來做軟體 debounce....

一個完整的 Debounce 共有四個狀態必須被檢出(開關裝在 Low side):

1. 檢出 low 信號: 開關被按下時,由高電位變成低電位,啟動計時器。

2. 計時完成時,判斷的開關狀態: 持續為 low 時表示開關有確實的按下,為 high 的話,表示誤動作。(開關持續為 low,可以當作除彈跳完成,但是本例為開關釋放之後,才當成一次完整的開關動作。

3. 等待開關由低電位轉成高電位,表示一個完整的開關動作完成,同時再次啟動計時器,處理開關釋放時產生的彈跳。

4. 計時完成後,開關回復到原設定狀態。

 

PIC16F1527 設成 internal RC 16 MHz,所以 TMR0 每 50 usec中斷一次:

if(TMR0IF) //set TMR0 prescale disable.
    {
        TMR0IF = 0;
        TMR0 += TMR0_PRELOAD; //TMR0_PRELOAD = 59.
        debounceCnt++;
}

 

在 interrupt isr 裡面的 code:

if(IOCBFx)
{
    IOCBF = 0x00;
    if(!sw1DebounceNegFlag && !sw1DebouncePosFlag) 
    {
        IOCBN4 = 0;    //clear switch negative edge interrupt.
        sw1DebounceNegFlag = 1;
    }
    else if(sw1DebounceNegFlag && sw1DebouncePosFlag)
    {
        IOCBP4 = 0;    //stop switch positive edge interrupt.
        sw1DebounceNegFlag = 0;
        sw1Flag = ~sw1Flag;
    }
    debounceCnt = 0;  
}

 

IOCBFx 是檢查中斷的 FLAG,PIC16F1527 中對應的 register。

sw1DebounceNegFlag & sw1DebouncePosFlag 是自設的 FLAG,用來檢查按鍵的狀態。

如果中斷發生,並且開關對應的 FLAG 有設起來,則檢查 sw1DebounceNegFlag & sw1DebouncePosFlag,如果是(0,0),則關閉開關的 IOC 下降緣中斷,然後把 sw1DebounceNegFlag 設成 1,表示下降緣中斷被觸發。sw1DebounceNegFlag & sw1DebouncePosFlag 的狀態會被設成 (1,0),debounc counter 歸零,開始計時。

 

呼叫 debounce function:

void checkSwitch(void)
{
    if(sw1DebounceNegFlag && !sw1DebouncePosFlag && (debounceCnt >= DEBOUNCE_SETTING))
    {
        if(!Switch)
        {
            IOCBPx = 1; //set switch positive interrupt.
            sw1DebouncePosFlag = 1;
        }
        else
        {
            IOCBNx = 1; //recover switch negative interrupt.
            sw1DebounceNegFlag = 0;
        }
    }

    if(!sw1DebounceNegFlag && sw1DebouncePosFlag && (debounceCnt >= DEBOUNCE_SETTING))
    {
        IOCBNx = 1; //recover switch negative interrupt.
        sw1DebouncePosFlag = 0;
    }

}

當 debounce counter 計數到了,並且 sw1DebounceNegFlag & sw1DebouncePosFlag 的狀態合於 if 判斷式時,去檢查一下開關真實的 I/O 狀態,如果開關是LOW (我的開關預設是 LOW 觸發),表示開關的確是被按下的而不是誤動作,這時把 IOC 的上升緣觸發打開 (IOCBPx),等待開關被釋放時的上升緣觸發。

當開關的上升緣出發出現後,會再次進入中斷函式,我的作法是: 認為開關完成一次完整的觸發流程,在中斷裡把另一個代表流程的 FLAG 設起來 (sw1Flag)、把上升緣中斷再關掉、重啟 debounce counter 然後退出中斷。

當放開按鍵時,開關一樣會有彈跳現象,所以要重啟 counter,延遲一段時間才去把 IOCBNx 重新打開,以去除釋放開關所產生的彈跳現象。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 Bill Suen 的頭像
    Bill Suen

    箱子裡的貓

    Bill Suen 發表在 痞客邦 留言(0) 人氣()