打印
[DemoCode下载]

使用systick作Debounce滤波

[复制链接]
1043|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
a_ziliu|  楼主 | 2015-7-28 13:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 a_ziliu 于 2015-7-28 13:47 编辑

利用systick作计数,在一段时间之间(400ms)如果有弹跳发生,不反应动作,以io侦测的方式避开noise.


NUC123SeriesBSP_CMSIS_V3.00.001 GPIO SYSTICK Debounce.zip (1.17 MB)

沙发
gaoyang9992006| | 2015-7-28 20:33 | 只看该作者
當按下按鈕時,表面上只按了一下。但是訊號的傳遞並不是很單純的由’1’直接跳到’0’。實際上的訊號會如上圖所示,當我們按下按鈕後,訊號會在高低電位之間彈跳(bounce)。則電路所收到的訊號可能會像111110110110000000,會和我們所預期的111111111000000000不同。如此一來,雖然我們只按了一下按鈕,電路可能會解讀成按了好幾下按鈕。debounce的目的就是為了要除去訊號在高低電位之間彈跳所造成的不正確輸入。


使用特权

评论回复
板凳
gaoyang9992006| | 2015-7-28 20:33 | 只看该作者
下面是之前开发板的一个按键程序:
`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软核直接生成按键,没必要自己再写了。软核的出现,真的太方便了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

100

主题

295

帖子

6

粉丝