羅立輝
【摘要】本文首先簡要介紹了獨立按鍵檢測主動查詢與中斷查詢這兩種方式的優(yōu)缺點。根據這兩種方式的優(yōu)缺點,本文著重討論了具有跟大優(yōu)勢的中斷查詢方式的按鍵檢測方案的實現(xiàn)原理和過程。并且,針對按鍵普遍存在的抖動問題,本文由簡單到復雜的過渡方式,詳細深入地介紹進行方案的優(yōu)化和改良的目的以及方法。
【關鍵詞】按鍵延時抖動掃描
1主動查詢方式的優(yōu)缺點
對于主動循環(huán)查詢方式,最大的優(yōu)點在于原理簡單,比較適合于MCU處理的任務不是特別多的情況。如果MCU大循環(huán)的輪詢周期較長,很有可能在按鍵按下的瞬間錯過了。這是主動查詢方式的最大缺點。另外,該方式比較浪費CPU的時間資源。檢測按鍵的處理程序需要有個延遲消抖的過程。對于機械彈性開關,一般需要的的延遲消抖時間為10ms。很多程序都是使用一般的延時函數(shù)來實現(xiàn)消抖的目的。然而對于很多復雜的產品,CPU需要執(zhí)行繁重的任務。在10ms時間里,CPU可以執(zhí)行上千上萬條其他任務的匯編指令。
2中斷查詢的方式的優(yōu)缺點
中斷查詢方式主要缺點在于,該方式需要占用MCU一個外部中斷功能(有些功能簡單、價錢低廉的MCU,其IO引腳復用功能資源有限),以及處理程序稍微復雜一下。與主動查詢相比,中斷查詢方式則有響應時間短、穩(wěn)定可靠等優(yōu)點。一旦有中斷響應,CPU一定立即響應中斷請求。因此,中斷查詢方式不存在“錯過”、“漏檢”的情況。按鍵檢測的原理圖設計圖1所示:
圖1 按鍵檢測的原理圖設計圖
在原理圖1設計中,為了檢驗按鍵被按下,MCU在中斷服務程序里,通過程序翻轉LED亮滅狀態(tài),以便讀者更容易理解其中的原理機制。
經過測試,每按一下按鍵,LDE燈都實現(xiàn)了翻轉的動作。該函數(shù)基本實現(xiàn)了預期的功能。在中斷函數(shù)里,筆者使用了簡單的的概率統(tǒng)計方法,提高準確性。這個中斷服務程序運行的時間大概為5us*20=0.1ms,遠遠少于相對通常的軟件延時方式所用的10ms,因此提高了CPU對資源的使用效率。但是,以上的中斷服務程序尚未徹底解決處理機械彈性按鍵本質上所具有的脈沖抖動的問題。首先,筆者在此描述以上程序運行起來后有何不良癥狀。有些情況下,按下一次按鍵,LED燈會翻轉2遍。有極少數(shù)情況下,LED甚至連續(xù)翻轉3到4次。這種現(xiàn)象不是用戶所期望的。這說明以上程序設計仍達不到穩(wěn)定的要求,很有必要進行再深入的代碼優(yōu)化。
結合以上給出的中斷服務程序,我們就很容易理解LED連續(xù)翻轉的現(xiàn)象了。不論圖中提到的前沿抖動還是后沿抖動,均可能導致CPU再次、多次進入中斷處理程序。因此,問題的重點在于,如何通過優(yōu)化算法和代碼,在按鍵抖動期間,避免多次進入中斷,或者避免進入中斷后重復執(zhí)行相同的任務。本文從實現(xiàn)的難易程度這個角度考慮,選擇了后者,即結合MCU定時器的功能,達到了“避免進入中斷后重復執(zhí)行相同的任務”的目的。
以下筆者講解了在原有程序的基礎上,如何結合MCU定時器的功能,進一步徹底解決按鍵抖動帶來的不穩(wěn)定問題。考慮到有部分讀者的基礎可能不是太好,為了降低本文設計思路的理解難度,筆者認為很有必要先給讀者簡要介紹一下有關定時器幾個非常經典的函數(shù)及其功能意義。關于定時器,有以下5個相關的函數(shù):
函數(shù)1:void clock_init(void)
對于函數(shù)1,顧名思義,該函數(shù)就是要對定時器temer進行初始化,否則函數(shù)2~5無效。
函數(shù)2:void timer_set(struct timer *t, clock_time_t interval)
該函數(shù)用于設置某定時器timer需要的時間間隔interval大?。ㄒ詍s為單位)。這就好比如有個漏水的水龍頭。水龍頭間隔恒定時間里每一滴的滴水大小,相當于函數(shù)里定時器的最小計數(shù)單位。水龍頭下面有個刻有刻度的水杯。而這里的interval,則相當于水杯的容量。
函數(shù)3:int timer_expired(struct timer *t)//判斷定時器timer是否時間滿了,為真返回1,否則返回0。這就好比如,某人外出走開了,在她回來之前看到水杯的前一刻,她不知道水杯是否滿了,因為她不知道自己離開了多長時間。而水杯里的水從完全沒水到剛好積滿這個時間差,永遠都是固定的。如果一直沒人將水杯倒掉,超過這個時間差,則水杯將一直處于溢出的狀態(tài)。當她回來查看水杯到底滿了還是沒滿的這個動作,相當于程序執(zhí)行了該函數(shù)。她只有兩個可能的結果,要么水杯滿了,要么還沒滿。
函數(shù)4:void timer_reset(struct timer *t)//復位定時器timer。該函數(shù)相當于水杯匯聚的滴水,不論水杯里的水有多滿,一律將水全倒掉,在將水杯放回水龍頭下面重新積水。
函數(shù)5:void timer_restart(struct timer *t)//重啟定時器timer。這個函數(shù)就好比如有個電子鬧鐘,有人將里面的電池拆下來后,又馬上將電池重新安裝回去。這樣,這個電子鬧鐘就“重啟”了。
由于優(yōu)化后的中斷服務程序中,添加了if(timer_expired(&key_timer))等相關語句,自按鍵被按下后,在接下來key_timer限定的50ms之內,除了第一次中斷函數(shù)能進入該if語句里面執(zhí)行LED翻轉的語句,其它由抖動導致的中斷服務程序均不能進入該if語句執(zhí)行LED翻轉語句。只有當key_timer限定的50ms滿了之后,程序才可以接受檢驗按鍵下一次被按下的動作。新程序重新下載到MCU后,經測試部測試,已經徹底解決了LED多次翻轉的問題。
3 結語
目前該技術方案應用在lemuse專業(yè)音箱等產品中已經超過2年時間。事實充分論證了本文介紹的整個按鍵檢測方案具有很強的實用性、成本低廉、準確性高、可靠性高等優(yōu)點。