FPGA学习笔记---利用连续赋值语句延时功能实现按键消抖

        最近一直在学习FPGA,今天在学习延时语句时,发现了连续赋值的一个特点。在连续赋值语句中添加延时时,任何小于延迟值的输入变化都会被滤除而不会体现在输出上。比如  #10 B = A; 当A的变化小于10ns时,在输出B上不会体现出来。

       突然就想到了利用这个特点是不是就可以消除按键抖动。延时时间为20ms,用连续赋值语句读取按键输入口的值,那么当按键在20ms内抖动时,输出值不会有变化,只有当按键值稳定20ms以上时,输出值才会有变化。这样不就实现了按键消抖了吗?说干就干,就先测试一下这种方法是否可行。

     首先验证连续赋值语句的延时功能。

编写代码如下:

`timescale 1ns/1ns
module assign_test(
    a,
    b
);
    input  [3:0] a;
    output [3:0] b;

assign #8 b = a;    
endmodule 

延时8ns将a的值赋给b,只有a的值稳定时间大于等于8ns时,b上才有值输出,否则a的值在8ns以内变化时,输出b上无变化。

测试文件如下:

`timescale 1ns/1ns
module assign_test_tb;

    reg  [3:0] a;
    wire [3:0] b;

 assign_test assign_test(
    .a  (a),
    .b  (b)
);
    initial  begin
        a = 4'd0;
        #5;
        a = 4'd1;
        #8;
        a = 4'd2;
        #5;
        a = 4'd3;
        #3;
        a = 4'd4;
        #10;
        a = 4'd5;
        #5;
        a = 4'd6;
        #15;
        a = 4'd7;
        #5;
        
        $stop;
    end
endmodule

测试文件中a的值不停变化,看输出b的值怎样变化。

仿真波形如下:

      由仿真波形可以看出,a的值从0变化到6,输出b的值依次为1、4、6,数字1的持续时间为8ns,数字4的持续时间为10ns,数字6的持续时间为15ns。其他数字的持续时间都小于8ns,所以输出b上检测不到。说明在连续赋值语句中使用延时可以获取到稳定的输出信号,滤除掉信号中间的干扰。

   利用这个特点来测试按键消抖,代码如下:

`timescale 1ns/1ns
module key_check(
    clk,
    rst_n,
    key_in,
    led
);
parameter DELAY = 20_000_000;       //20ms    
    input clk;
    input rst_n;
    input key_in;                   //按键输入信号
    output reg led;                 //led指示灯    
    wire key_sta;                   //按键稳定输出后信号  
assign #DELAY  key_sta = key_in;    //利用连续赋值语句的延时功能对按键进行消抖 
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        led <= 1'b0;
    else if(key_sta == 1'b0)
        led <= 1'b1;
    else
        led <= 1'b0;  
end
endmodule

在连续赋值语句前增加20ms的延时,只有按键输入信号稳定20ms以上时,才会输出到key_sta上,然后根据key_sta的电平状态改变led灯的亮灭。

测试代码如下

`timescale 1ns/1ns
module key_check_tb;
parameter T = 20;            //20ns  50M时钟
    reg clk;
    reg rst_n;
    reg key_in;
    wire led;
key_check key_check(
  .clk      (clk),
  .rst_n    (rst_n),
  .key_in   (key_in),
  .led      (led)
);
    initial clk = 1'b0;
    always #(T/2) clk = ~clk;
    initial begin
        rst_n = 1'b0;
        key_in = 1'b1;
        #(20 * T + 1);
        rst_n = 1'b1;
        #(T * 100);
        
        repeat(3) begin
            //按下抖动
            key_in = 1'b0;
            #(T * 50_000);
            key_in = 1'b1;
            #(T * 10_000);
            
            key_in = 1'b0;
            #(T * 20_000);
            key_in = 1'b1;
            #(T * 30_000);
            
            key_in = 1'b0;
            #(T * 10_000);
            key_in = 1'b1;
            #(T * 10_000);
            
            //按下
            key_in = 1'b0;
            #(T * 2000_000);
        
            //弹起抖动
            key_in = 1'b1;
            #(T * 50_000);
            key_in = 1'b0;
            #(T * 10_000);
            
            key_in = 1'b1;
            #(T * 20_000);
            key_in = 1'b0;
            #(T * 30_000);
            
            key_in = 1'b1;
            #(T * 10_000);
            key_in = 1'b0;
            #(T * 10_000);
        
            //弹起
            key_in = 1'b1;
            #(T * 5000_000);
        end
        $stop;
    end
endmodule

测试代码中模拟了3次按键抖动,下面看输出波形

        通过波形可以看出当key_in的状态发生改变并稳定20ms时,key_sta的状态才会发生改变。输入信号key_in上有抖动,而key_sta状态是稳定的,没有发生抖动。而led输出状态刚好和key_sta状态相反,符合设计要求。

      看来通过对连续赋值语句加延时的方法可以进行按键消抖,理论上验证也是成功的。但是目前在网上没有搜到类似的方法,不知道这种方法在实际应用中会不会出现问题。如果看到这篇文章朋友有这方面经验的话,可以一起讨论下这种按键消抖方法的可行性。

更正

      通过最近几天学习和查资料时明白了,延时语句如:#开头的延时语句,不可综合成硬件电路延时,综合工具会忽略所有延时代码,但不会报错
    如:a=#10 b;
    这里的#10是用于仿真时的延时,在综合的时候综合工具会忽略它。也就是说,在综合的时候上式等同于a=b;

延时语句在前仿真时,可以看到延时效果。但是在后仿真时,会被忽略掉,不起任何作用。

前仿真波形:

 

后仿真波形

       通过仿真波形可以明显看出,上述的按键延时方法在前仿真时起到了消抖的作用,但是在后仿真中没有起到消抖作用。所以这种按键消抖方法在实际项目中不能使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值