按鍵開關(guān)是各種電子設(shè)備不可或缺的人機(jī)接口。在實(shí)際應(yīng)用中,很大一部分的按鍵是機(jī)械按鍵。在機(jī)械按鍵的觸點(diǎn)閉合和斷開時(shí),都會(huì)產(chǎn)生抖動(dòng),為了保證系統(tǒng)能正確識(shí)別按鍵的開關(guān),就必須對(duì)按鍵的抖動(dòng)進(jìn)行處理。
在系統(tǒng)設(shè)計(jì)中,有各種各樣的消除按鍵抖動(dòng)的設(shè)計(jì)方法,硬件電路和軟件設(shè)計(jì)都很成熟。不過我們這里要從另外一個(gè)角度來討論按鍵的消抖,并給出一個(gè)用verilog給出一個(gè)具體的實(shí)現(xiàn)。
首先,看一個(gè)普通的機(jī)械按鍵的觸點(diǎn)在閉合與斷開時(shí)的波形(用示波器抓?。?/p>
下面的四張圖都是按鍵在閉合的時(shí)候抓到的波形。可以看到兩個(gè)明顯的趨勢(shì):
1. 按鍵在幾個(gè)us之內(nèi)就可以達(dá)到穩(wěn)定狀態(tài),從高電平轉(zhuǎn)換到底電平;
2. 在高電平轉(zhuǎn)換到低電平的過程中,觸點(diǎn)有非常明顯的抖動(dòng)。
下面的兩張圖是按鍵在斷開的時(shí)候抓到的波形。也可以看到兩個(gè)明顯的趨勢(shì):
1. 按鍵的變化趨勢(shì)比較緩慢,從低電平變?yōu)楦唠娖叫枰蟾?0~20ms的時(shí)間;
2. 按鍵斷開時(shí)沒有閉合時(shí)那么大的抖動(dòng)
下面兩張圖是用手迅速閉合按鍵然后就斷開時(shí),按鍵的輸出波形。
在處理按鍵抖動(dòng)的程序中,必須同時(shí)考慮消除閉合和斷開兩種情況下的抖動(dòng)。所以,對(duì)于按鍵消抖的處理,必須按最差的情況來考慮。我們從上面的圖上可以看到,按鍵輸出的信號(hào)的跳變時(shí)間(上升沿和下降沿)最大是在20ms左右。按鍵一次閉合最短的時(shí)間大概是120ms左右。
如果我們把按鍵的輸出做為一個(gè)時(shí)鐘域(時(shí)鐘頻率未知,但信號(hào)的slow rate是已知的,既最大20ms左右)的信號(hào),用另外一個(gè)時(shí)鐘來采集這個(gè)按鍵的輸出,則就可以把按鍵的消抖歸結(jié)為一個(gè)最基本的CDC問題來處理。而問題的核心是如何確定采集時(shí)鐘的頻率。假設(shè)采集時(shí)鐘的周期小于20ms,那么,采集時(shí)鐘就有可能兩次采到按鍵斷開時(shí)的不確定的值,就沒有辦法避免采用CDC電路所想避免的問題。所以采集時(shí)鐘的周期必須要大于20ms。假設(shè)采集時(shí)鐘的周期大于120ms的話,就有可能采不到按鍵的閉合信號(hào),所以采集時(shí)鐘的周期必須小于120ms。我們?cè)谶@里選用周期為25ms的采集時(shí)鐘(頻率為40Hz)。
下面的verilog實(shí)現(xiàn)實(shí)際上是一個(gè)標(biāo)準(zhǔn)的CDC電路,直接可以用來做按鍵的消抖。
module RMV_BJ (
BJ_CLK, //采集時(shí)鐘,40Hz
RESET, //系統(tǒng)復(fù)位信號(hào)
BUTTON_IN, //按鍵輸入信號(hào)
BUTTON_OUT //消抖后的輸出信號(hào)
);
input B_CLK;
input RESET;
input BUTTON_IN;
output BUTTON_OUT;
reg BUTTON_IN_Q, BUTTON_IN_2Q, BUTTON_IN_3Q;
always @(posedge BJ_CLK or negedge RESET)
begin
if(~RESET)
begin
BUTTON_IN_Q <= 1'b1;
BUTTON_IN_2Q <= 1'b1;
BUTTON_IN_3Q <= 1'b1;
end
else
begin
BUTTON_IN_Q <= BUTTON_IN;
BUTTON_IN_2Q <= BUTTON_IN_Q;
BUTTON_IN_3Q <= BUTTON_IN_2Q;
end
end
wire BUTTON_OUT = BUTTON_IN_2Q | BUTTON_IN_3Q;
endmodule
在實(shí)際的實(shí)現(xiàn)中,我們首先要生成一個(gè)40Hz的時(shí)鐘,然后有多少個(gè)按鍵就將上面的模塊例化多少次就可以了。比如說我們有4個(gè)按鍵,那么下面的實(shí)現(xiàn)就可以了。其中KEY_CTL[3:0] 是按鍵的輸入,KEY_OUT[3:0]是按鍵的輸出。
RMV_BJ RMV_BJ0( .BJ_CLK(BJ_CLK), .RESET(RESET), .BUTTON_IN(KEY_CTL[0]), .BUTTON_OUT(KEY_OUT[0]) );
RMV_BJ RMV_BJ1( .BJ_CLK(BJ_CLK), .RESET(RESET), .BUTTON_IN(KEY_CTL[1]), .BUTTON_OUT(KEY_OUT[1]) );
RMV_BJ RMV_BJ2( .BJ_CLK(BJ_CLK), .RESET(RESET), .BUTTON_IN(KEY_CTL[2]), .BUTTON_OUT(KEY_OUT[2]) );
RMV_BJ RMV_BJ3( .BJ_CLK(BJ_CLK), .RESET(RESET), .BUTTON_IN(KEY_CTL[3]), .BUTTON_OUT(KEY_OUT[3]) );
下面的波形是實(shí)測(cè)出來的按鍵消抖前后的波形,紅色的為消抖前,白色的為消抖后。
要注意的是,經(jīng)過處理后的按鍵信號(hào),實(shí)際上是一個(gè)時(shí)鐘域?yàn)?0Hz的信號(hào),如果我們要將按鍵送給后級(jí)電路使用,那么必須要將其轉(zhuǎn)換到后級(jí)電路的時(shí)鐘域中,轉(zhuǎn)換的方法與上面所述CDC電路相同。
另外不同的按鍵的閉合,斷開抖動(dòng)時(shí)間都是有差異的,上面所講的例子只參照了一種普通的機(jī)械按鍵,所以可能不具有普遍性。但對(duì)于不同的按鍵,處理方法都是一樣的,只要根據(jù)按鍵特性,選定采集時(shí)鐘的頻率就可以了。
評(píng)論
查看更多