按鍵去抖的原因及其分類就不羅嗦了。
在這里解釋一段代碼,代碼是網上找的,看了半天沒懂,無奈查了半天想了半天,終於明白了。。。
module sw_debounce(
clk,
rst_n,
sw1,
sw2,
sw3,
//output
led_d3,
led_d4,
led_d5
);
input clk;
input rst_n;
input sw1,sw2,sw3; //Active low
output led_d3;
output led_d4;
output led_d5;
// ---------------------------------------------------------------------------
// 通過降采樣對sw1~sw3 的輸入做低通濾波,將其高頻分量濾除,得到low_sw 值
// ---------------------------------------------------------------------------
reg [19:0] cnt;
always @ (posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 20'd0;
else
cnt <= cnt + 1'b1;
reg [2:0] low_sw;
always @(posedge clk or negedge rst_n)
if (!rst_n)
low_sw <= 3'b111;
else if (cnt == 20'hfffff) //每隔20MS 檢測一次按鍵
low_sw <= {sw3,sw2,sw1};
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
reg [2:0] low_sw_r; //將low_sw 信號鎖存一個時鍾周期,延時不是真的“鎖存”
always @ ( posedge clk or negedge rst_n )
if (!rst_n)
low_sw_r <= 3'b111;
else
low_sw_r <= low_sw;
wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
//當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
reg d1;
reg d2;
reg d3;
always @ (posedge clk or negedge rst_n)
if (!rst_n)
begin
d1 <= 1'b0;
d2 <= 1'b0;
d3 <= 1'b0;
end
else
begin
if ( led_ctrl[0] ) d1 <= ~d1;
if ( led_ctrl[1] ) d2 <= ~d2;
if ( led_ctrl[2] ) d3 <= ~d3;
end
assign led_d5 = d1 ? 1'b1 : 1'b0;
assign led_d3 = d2 ? 1'b1 : 1'b0;
assign led_d4 = d3 ? 1'b1 : 1'b0;
具體原理:通常,按鍵抖動會產生10--20MS 的毛刺,因此要做的實際上就是在20MS 中采樣一次,當
檢測到按鍵下降沿的時候,就認定按下,其他狀態忽略。采用 50MHz 晶振,時鍾周期是20ns,
else if (cnt == 20'hfffff) //每隔20MS 檢測一次按鍵
low_sw <= {sw3,sw2,sw1};
reg [2:0] low_sw_r; //將low_sw 信號鎖存一個時鍾周期,延時不是真的“鎖存”
always @ ( posedge clk or negedge rst_n )
if (!rst_n)
low_sw_r <= 3'b111;
else
low_sw_r <= low_sw;
wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
//當檢測到按鍵有下降沿變化時,代表該按鍵被按下,按鍵有效
個人覺得,鎖存一個時鍾周期, 在 FPGA 里的應用實在是太多了,幾乎所有的程序都要用到,作用無非
是防止競爭冒險,將一個信號延遲一個時鍾周期(low_sw_r[2:0]),原來的信號取反(~low_sw[2:0]),2
個信號與一下,便可以檢測到一個下降沿的變化,從而產生一個寬度為一個時鍾周期(20ns)的脈沖,然
后將這個脈沖作為控制信號去控制別的進程。。。
上面都是轉自一位兄弟的博客,我在這里解釋一下關於鎖存一個周期是怎么回事。這里的所存是通過非阻塞語句實現的,always塊是並行的,同時執行,非阻塞語句的賦值是先計算所有等式右邊的表達式的值,然后一齊賦值,在計算期間,也就是在always塊結束以前,等式左邊等待賦值的變量仍然保持原來的值,這樣,第二級鎖存器low_sw_r所存的永遠是low_sw上一次的值,這樣就實現了將信號鎖存一個周期。
wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);這是一個很經典的下降沿檢測語句。因為非阻塞賦值語句,low_sw_r中是low_sw上一個周期的值,將其與這個周期的low_sw取反后相與,就得到按鍵是否按下的檢測結果,0是沒按下,1是按下。
轉載自:http://www.cnblogs.com/lamapig/archive/2010/10/03/1841537.html