1.按鍵消抖的原理
圖1.按鍵抖動(dòng)示意圖 我們平常所用的按鍵為機(jī)械彈性開關(guān),,由于觸點(diǎn)的彈性作用,按鍵在閉合時(shí)不會(huì)馬上穩(wěn)定的接通,,而是有一段時(shí)間的抖動(dòng),,在斷開時(shí)也不會(huì)立即斷開。抖動(dòng)時(shí)間由按鍵的機(jī)械特性所決定,,一般為5ms~10ms。所以我們?cè)谧霭存I檢測(cè)時(shí)都要加一個(gè)消抖的過(guò)程,。 按鍵消抖主要有兩種方案: 一是延時(shí)重采樣,;二是持續(xù)采樣。
從理論上來(lái)說(shuō),,延時(shí)(如10ms)重采樣的準(zhǔn)確率肯定低于持續(xù)采樣,。
2.按鍵消抖的方法
(1)延時(shí)重采樣
延時(shí)重采樣的意思是,當(dāng)?shù)谝淮螜z測(cè)到鍵值由'1'變?yōu)?0'時(shí),,再延時(shí)一段時(shí)間(如10ms),再次采樣,,確認(rèn)是否仍是'0';若是'0'則認(rèn)為此時(shí)鍵值為'0',否則,,重新執(zhí)行檢測(cè)過(guò)程,。
這個(gè)方案在特權(quán)同學(xué)的《深入淺出玩轉(zhuǎn)FPGA》的p191有例程;
該方案的缺陷:a.如果延時(shí)太短,,有可能兩次采樣時(shí)都處于抖動(dòng)時(shí)間,,因此可能引起誤判;
b.如果延時(shí)太長(zhǎng),,可能檢測(cè)不出按鍵變換
(2)持續(xù)采樣
持續(xù)采樣的原理是,,當(dāng)檢測(cè)到按鍵處于某電平(如'0')時(shí),在之后的N個(gè)時(shí)鐘周期內(nèi)連續(xù)檢測(cè)此按鍵的電平,,如果一直不變,,則讀出此按鍵的電平值(如'0')。
持續(xù)采樣的優(yōu)點(diǎn):a.樣本足夠多,,減少誤判的可能性,。
b.對(duì)于按鍵按下('1'->'0'),按鍵釋放('0'->'1')都可以檢測(cè),。
持續(xù)采樣的缺點(diǎn):持續(xù)檢測(cè)的時(shí)間太長(zhǎng)(大于按鍵按下和釋放的時(shí)間差),,則可能無(wú)法檢測(cè)按鍵的變換。
1)單個(gè)按鍵的檢測(cè)
按鍵檢測(cè)的輸出有兩種方式:1.電平輸出,,此時(shí)按鍵功能猶如撥碼開關(guān),。
2.脈沖輸出,,此時(shí)每按下一次按鍵,輸出一個(gè)脈沖信號(hào),。
圖2.按鍵檢測(cè)輸出波形示意圖
如圖2所示,,Key_out1的輸出與Key_in的變換趨勢(shì)相同,只是濾除了抖動(dòng)成分,;
Key_out2則是每當(dāng)按鍵按下后輸出一個(gè)高電平脈沖,。在大多數(shù)的應(yīng)用中會(huì)用到Key_out2所示功能。
輸出為電平(用于電平判斷事件,,類似于開關(guān)選擇)
module key_scan
#(parameter DURATION = 1200)//the number of clk period
(
input wire clk, //120MHz
input wire rst_n,
input wire key_in,
output reg key_out
);
//key jitter filter
reg[11:0] low_cnt;
reg[11:0] high_cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
low_cnt <= 0;
high_cnt <= 0;
key_out <= 1'b1;
end
else
begin
if(key_in == 1'b0)
begin
high_cnt <= 0;
if(low_cnt == DURATION)
begin low_cnt <= low_cnt; key_out <= 1'b0; end
else
low_cnt <= low_cnt + 1'b1;
end
else //key_in == 1'b1
begin
low_cnt <= 0;
if(high_cnt == DURATION)
begin high_cnt <= high_cnt;key_out <= 1'b1; end
else
high_cnt <= high_cnt + 1'b1;
end
end
end
endmodule
輸出為脈沖(用于脈沖觸發(fā)事件)
module key_scan
#(parameter DURATION = 1200)//the number of clk period
(
input wire clk, //120MHz
input wire rst_n,
input wire key_in,
output wire key_out
);
//key jitter filter
reg[11:0] low_cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
low_cnt <= 0;
else
begin
if(key_in == 1'b0)
begin
if(low_cnt == DURATION)
low_cnt <= low_cnt;
else
low_cnt <= low_cnt + 1'b1;
end
else //key_in == 1'b1
low_cnt <= 0;
end
end
assign key_out = (low_cnt == DURATION -1)? 1'b1 : 1'b0;
endmodule
2)多個(gè)獨(dú)立按鍵的掃描(掃描得出鍵值)
功能:a.可以檢測(cè)出哪些鍵按下了,,甚至哪些鍵同時(shí)按下了。
b.鍵值更新后,,輸出一個(gè)脈沖信號(hào),,提升更新完成;
c.鍵值保持到下一次更新完成,。
module key_counter_scan
#(
parameter KEY_WIDTH = 4
)
(
//global clock
input clk,
input rst_n,
//key interface
input [KEY_WIDTH-1:0] key_data,
//user interface
output reg key_flag,
output reg [KEY_WIDTH-1:0] key_value //H Valid
);
//-----------------------------------
//Register key_data for compare
reg [KEY_WIDTH-1:0] key_data_r;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
key_data_r <= {KEY_WIDTH{1'b1}};
else
key_data_r <= key_data;
end
//-----------------------------------
//continue 20ms
localparam DELAY_TOP = 20'd1000_000;
//localparam DELAY_TOP = 20'd1000; //Just for test
reg [19:0] delay_cnt;
//-----------------------------------
//Key scan via counter detect.
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
delay_cnt <= 0;
else
begin
if((key_data == key_data_r) && (key_data != {KEY_WIDTH{1'b1}})) //20ms counter jitter
begin
if(delay_cnt < DELAY_TOP)
delay_cnt <= delay_cnt + 1'b1;
else
delay_cnt <= DELAY_TOP;
end
else
delay_cnt <= 0;
end
end
//-----------------------------------
//the complete of key_data capture
wire key_trigger = (delay_cnt == DELAY_TOP - 1'b1) ? 1'b1 : 1'b0;
//-----------------------------------
//output the valid key_value via key_trigger
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
key_value <= {KEY_WIDTH{1'b0}};
else if(key_trigger)
key_value <= ~key_data_r;
else
key_value <= key_value;
end
//---------------------------------
//Lag 1 clock for valid read enable
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
key_flag <= 0;
else
key_flag <= key_trigger;
end
endmodule
|
|
來(lái)自: 鹿港小鎮(zhèn)1989 > 《單片機(jī)》