引言
通常按鍵所用的開關都是機械彈性開關,當機械觸點斷開、閉合時,由於機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上就穩定的接通,在斷開時也不會一下子徹底斷開,而是在閉合和斷開的瞬間伴隨了一連串的抖動,如圖1所示。

分析
按鍵穩定閉合時間長短是由操作人員決定的,通常都會在 100ms 以上,刻意快速按的話能達到 40-50ms 左右,很難再低了。抖動時間是由按鍵的機械特性決定的,一般都會在 10ms以內,為了確保程序對按鍵的一次閉合或者一次斷開只響應一次,必須進行按鍵的消抖處理。
方法一
在絕大多數情況下,我們是用軟件即程序來實現消抖的。最簡單的消抖原理,就是當檢測到按鍵狀態變化后,先等待一個 10ms 左右的延時時間,讓抖動消失后再進行一次按鍵狀態檢測,如果與剛才檢測到的狀態相同,就可以確認按鍵已經穩定的動作了。實際應用中,這種做法局限性大(實時性差)。
方法二
啟用一個定時中斷,每 2ms 進一次中斷,掃描一次按鍵狀態並且存儲起來,連續掃描 8 次后,看看這連續 8 次的按鍵狀態是否是一致的。8 次按鍵的時間大概是 16ms,這 16ms 內如果按鍵狀態一直保持一致,那就可以確定現在按鍵處於穩定的階段,而非處於抖動的階段,如下圖2所示。

代碼片
//外部中斷觸發(下降沿) void EXTI15_10_IRQHandler(void) { if ( RESET != EXTI_GetFlagStatus( EXTI_Line5 ) ) { static u32 lasttime = 0; if( (g_tickCount - lasttime) > 100 ) { T_1min_cnt = TIM2OpenTime; TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); lasttime = g_tickCount; } EXTI_ClearITPendingBit( EXTI_Line5 ); } }
/* Tim2 部分中斷服務函數 */ void TIM2_IRQHandler(void)//250us { if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { T_250us_cnt++; if ( T2_250us_cnt >= 8 )//2ms IRQ { T2_250us_cnt = 0; static u8 Keybuf1 = 0xff,WG_AKeyBuf = 0xff; Keybuf1 = ( ( Keybuf1 << 1 ) | GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_5) );//緩存區左移1位,並將當前值移入最低位 if ( 0x00 == Keybuf1 )//連續8次掃描都為0,即16毫秒內都檢測到按下狀態,即認為按鍵按下 { Key1Sta = 0; } else if ( 0xff == Keybuf1 )//按鍵彈起 { Key1Sta = 1; } else//其它情況則說明按鍵狀態尚未穩定,則不對 KeySta 變量值進行更新 //Key1Sta = 1;//default value } TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); } }
