新闻  |   论坛  |   博客  |   在线研讨会
按键debounce
suoluoji | 2010-12-07 14:49:20    阅读:14229   发布文章

按键debounce

   何謂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软核直接生成按键,没必要自己再写了。软核的出现,真的太方便了。

 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
suoluoji  2010-12-07 14:51:16 

好好研究下~~

推荐文章
最近访客