軟體 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 重新打開,以去除釋放開關所產生的彈跳現象。
留言列表