zoukankan      html  css  js  c++  java
  • FPGA按键去抖verilog代码

    按键去抖的原因及其分类就不罗嗦了。

    在这里解释一段代码,代码是网上找的,看了半天没懂,无奈查了半天想了半天,终于明白了。。。

    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

  • 相关阅读:
    倒计时浏览器跳转JavaScript
    C#.NET中使用存储过程的方法及其优点
    利用GridView控件导出其他文件(导出Excel,导出Word文件)
    c#.net用JavaScript实现 时钟显示
    程序执行一半后可以跳出对话框选择是否继续执行
    FreeMarker 中文官方参考手册 For Freemarker 2.3.23
    Spring技术内幕之Spring Data JPA-自定义Repository实现
    ehcache入门基础示例
    SpringData JPA 接口和方法
    Springboot中使用缓存
  • 原文地址:https://www.cnblogs.com/chengqi521/p/6149714.html
Copyright © 2011-2022 走看看