2009年4月28日 星期二

何謂De-Bounce?!

何謂debounce,為何要debounce?



當按下按鈕時,表面上只按了一下。但是訊號的傳遞並不是很單純的由’1’直接跳到’0’。實際上的訊號會如上圖所示,當我們按下按鈕後,訊號會在高低電位之間彈跳(bounce)。

則電路所收到的訊號可能會像111110110110000000,
會和我們所預期的     111111111000000000不同。

如此一來,雖然我們只按了一下按鈕,電路可能會解讀成按了好幾下按鈕。debounce的目的就是為了要除去訊號在高低電位之間彈跳所造成的不正確輸入。

下面是之前開發板的一個按鍵程式:
`timescale 1ns/1ns
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)的脈衝,然後將這個脈衝作為控制信號去控制別的進程。。。 


  很簡單的程式,不過現在大部分高速按鍵自帶硬體濾波,而且FPGA裏可以調用PIO軟核直接生成按鍵,沒必要自己再寫了。軟核的出現,真的太方便了。

沒有留言:

張貼留言

##EasyReadMore##