特權FPGA 按鍵消抖檢測程式碼

qingfeng_96發表於2018-11-10

按鍵去抖的原因及其分類就不羅嗦了。

在這裡解釋一段程式碼,程式碼是網上找的,看了半天沒懂,無奈查了半天想了半天,終於明白了。。。

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

    https://www.cnblogs.com/chengqi521/p/6149714.html

相關文章