用單片機或ARM做的產品經常會遇到有鍵盤輸入的產品,而鍵盤輸入有一個繞不過去的問題就是:鍵盤去抖。見下圖
當按鍵開關閉合或者斷開時各有一段電平不穩定的時期,按鍵開關在閉合時不會馬上就穩定的接通,在斷開時也不會一下子徹底斷開,而是在閉合和斷開的瞬間伴隨了一連串的電平抖動。這種抖動一般都在10ms左右。為了確保程序對按鍵的一次閉合或者一次斷開只響應一次,必須進行按鍵的去抖處理。當檢測到按鍵狀態變化時,不是立即去響應動作,而是先等待閉合或斷開穩定后再進行處理。
按鍵去抖方法可分為硬件去抖和軟件去抖,硬件去抖不在本文的討論中,本文只討論軟件去抖。
一般的軟件去抖就是程序在檢測到按鍵閉合或斷開時調用一段延時子程序(在C語言中叫函數),程序在此死等10ms或更長。延時過后再檢測按鍵的狀態是否與延時前的狀態一致,若一致就執行鍵盤程序部分,若不一致,則跳過執行鍵盤程序。
這種方法在程序工作量不是很大時是沒有問題的。但在一些CPU負荷量比較大的程序中,特別是在一些程序運轉中有比較多的在不確定時間就會發生的中斷的情況下(外部中斷、串口中斷、定時器中斷等),在這里死等,就有可能造成某部分程序不能很好地被執行,甚至程序跑飛等嚴重問題。
本人經過多年的編程,總結了一套解決這問題的方法,供大家參考。
程序是用51匯編語言寫的,大家若要用C語言編寫,參考這流程圖改一下就成。
先解釋這流程圖中的變量和子程序:
KSTEP:步進指示變量,當程序從主程序進入到此子程序后,立刻根據這KSTEP的值跳到相應的程序段。
KEYSCAN:讀鍵盤子程序,若你的按鍵數量不多的話,直接讀IO口。按鍵數量多的話,就要用矩陣方式讀鍵盤,這里不作贅述。
HASK:位變量,讀鍵盤子程序中的位變量,當讀鍵盤子程序KEYSCAN檢測到有鍵閉合時置“1”,反之置“0”。
R2:鍵值變量,讀鍵盤子程序KEYSCAN讀出的鍵值。
KVALU:鍵值變量,R2的鍵值送到這里,供此子程序下一次判斷或主程序使用。
K20MS:20ms計時器變量,當第一次檢測到有鍵閉合時往里面送值10。程序初始化中設定定時器中斷為2ms時間間隔。進入定時器中斷后,首先判斷K20MS是否為0?若為0則直接退出定時器中斷;若不為0則將K20MS減1后再退出定時器中斷。這樣K20MS變量從10減到0時間為20ms。鍵斷開時也是一樣地執行。
KAVA:位變量,告訴主程序:鍵閉合(斷開)有效。
程序解釋:
1.程序初始化時KSTEP的值為0,所以一進入本子程序,程序馬上就跳到標號KSC0處,在此處調用讀鍵盤子程序KEYSCAN。
1.1從KEYSCAN出來后,若位變量HASK的值為0,說明沒有鍵閉合,程序直接跳到標號RET處退出。
1.2若位變量HASK的值為1,就是有鍵閉合,此時將數值1送入步進指示變量KSTEP中,便于下次進入本子程序時,程序直接跳到標號KSC1處。再將從KEYSCAN子程序讀出來的鍵值送入變量KVALU中,用于下次再調用讀鍵盤子程序KEYSCAN時與R2讀出的鍵值進行比較。
最后將數值10送入20ms計時器變量K20MS中,用于2ms定時器中斷后減1,然后退出子程序。
2.當主程序再次調用本子程序時,程序馬上就跳到標號KSC1處。
2.1在此處首先判別20ms計時器變量K20MS是否減到0(也就是判別20ms延時到了沒有?),若K20MS不為0(20ms延時還沒有到),則立即退出。
2.2若K20MS為0(說明20ms延時時間到了),再次調用讀鍵盤子程序KEYSCAN。調用KEYSCAN子程序后,再次判別位變量HASK是否有效?
2.2.1若HASK無效,說明上次(KSC0處)可能是受到一次干擾。于是復位KSTEP(清0),退出。使下次調用本程序時,又從頭開始。
2.2.2若HASK有效,則將這次從KEYSCAN讀出的鍵值與上次讀出并存在KVALU中的鍵值進行比較。
2.2.2.1若比較值不同,則程序跳到標號KE1處,將新的鍵值存入KAVALU中,20ms后再調用KEYSCAN子程序,再次比較。
2.2.2.2若比較值相同,則說明本次鍵閉合有效,于是置位KAVA(當主程序是鍵按下執行時),告訴主程序,鍵閉合有效,可以執行此鍵所要做的程序了。同時將數值2送入步進指示變量KSTEP中,便于下次進入本子程序時,程序直接跳到標號KSC2處。最后將數值10送入20ms計時器變量K20MS中,在下次進入KSC2標號處,也得等20ms之后再判別鍵是否斷開。
3.現在主程序調用本子程序時,程序馬上就跳到標號KSC2處,在此也一樣,首先判別20ms計時器變量K20MS是否減到0(也就是判別20ms延時到了沒有?),若K20MS不為0(20ms延時還沒有到),則立即退出。若K20MS為0,調用讀鍵盤子程序KEYSCAN。
調用KEYSCAN子程序后,判別位變量HASK是否有效?
3.1若HASK無效,說明按鍵可能被釋放斷開,于是將數值3送入步進指示變量KSTEP中,便于下次進入本子程序時程序可以直接跳到標號KSC3處。最后將數值10送入20ms計時器變量K20MS中,在下次進入KSC3標號處,也得等20ms之后再判別鍵是否繼續斷開狀態。
3.2若HASK有效,說明按鍵繼續閉合狀態,再比較KEYSCAN讀出的鍵值與上次讀出在KVALU中的鍵值進行比較。
3.2.1若比較值不同,則程序跳到標號KE0處,重新開始。
3.2.1若比較值相同,則說明按鍵還沒有斷開,繼續將數值10送入20ms計時器變量K20MS中,等20ms之后再進入標號KSC2處,再次判別按鍵是否斷開。
4.當主程序調用本子程序時,程序程序馬上跳到標號KSC3處,還是首先判別20ms計時器變量K20MS是否減到0,若K20MS不為0(20ms延時還沒有到),則立即退出。若K20MS為0,調用讀鍵盤子程序KEYSCAN。
調用KEYSCAN子程序后,判別位變量HASK是否有效?
4.1若HASK無效,說明按鍵已經完全釋放斷開,于是將數值0送入步進指示變量KSTEP中,便于下次進入本子程序時,程序從頭開始,同時置位KAVA(當主程序是鍵釋放執行時),告訴主程序,鍵釋放有效,可以執行此鍵所要做的程序了。
4.2如果位變量HASK繼續有效,說明又有鍵閉合了(雖然這種概率比較小,但程序得編進去),根據新鍵值與老鍵值的相同與不同,分別跳到標號KE3處,或者標號KE0處執行。
說明:KE3標號和KE7標號下面都有SETBKAVA,實際編程時只用一次,根據你的主程序是在鍵按下執行還是鍵釋放執行選用。
本程序的特點就是:在等鍵閉合或斷開去抖的那20ms時間,不是死等,而是做好標記及置好必要的變量值后立即退出到主程序去做其他事情。程序每次從進入到退出這個子程序中所花的時間一般為十幾微秒(不含讀鍵盤子程序KEYSCAN所花的時間,KEYSCAN花的時間根據按鍵數量的多少而不同,一般為幾個微秒到幾十微秒)。
來源;21ic
評論
查看更多