二、13【FPGA】按键消抖

前言

学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。

学习视频:是根据野火FPGA视频教程——第十六讲
https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3

理论学习

按键常常作为系统复位信号和控制信号的外部输入,主要分为自锁按键、机械按键和薄膜按键等。开发板上一般采用机械按键,但是当机械触电断开、闭合时,由于机械触电的弹性作用,一个按键开关在闭合时不会马上稳定导通,断开时不会一下子完全断开,会出现瞬间的抖动。影响按键的输入状态,因此需要对按键进行消抖处理。

抖动时常由按键本身决定,一般在5ms~10ms。

1、硬件消抖

        按键较少时可以使用硬件消除抖动,即使其在状态第一次出发后就保持。这里用到了RS触发器作为常用的硬件去抖。

 当按键未按下时输出0,按下为1。按键因弹性抖动而产生瞬时断开(抖动跳开B),只要不返回原始状态A,双稳态电路的状态不会改变,输出保持0,不会产生抖动波形。

2、软件消抖

        当按键较多时使用硬件消抖需要占用太多资源,因此通过软件编程消抖。即检测到按键闭合后执行一个延时程序,由于抖动时间在5~10ms,我们产生一个20ms的延时,当前后两个状态相同时才能确定按键的真实状态

实战演练

1、设计规划

实现一个按键消抖模块,将按键做消抖处理后正常被其他模块调用

2、程序设计

2.1 波形图绘制

按键脉冲产生方式:

  • 传统方法:当按键被检测按下时,延时20ms+10ms时间重新检测,如果依然是低电平则产生一个时钟单位的脉冲。问题:这里计数器需要将10ms的时间计算在内浪费资源。
  • 脉冲计数器:当检测到按键被按下时开始脉冲计数,当20ms后(50MHz,计数到999999)后产生一个时钟单位的脉冲,且重新计数。当按键未按下时,计数器清零。问题:当按键按的时间过长时,将会产生多个脉冲。
  • 保持计数:当计数器计到999999时,计数器的值将会保持,只有检测到按键未按下的高电平时,才会被清零。因此计数器确定被按下时计数器的999998值只会出现一次。这时产生一时钟周期的脉冲即可。

2.2 代码编写 

module key_filter
#(
    parameter CNT_MAX = 20'd999_999       //最大计数时间20ms
)
(
    input wire sys_clk,
    input wire sys_rst_n,
    input wire key_in,
    output reg key_flag
    );
    reg [19:0] cnt; 
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt <= 20'd0;
        else if(key_in == 1'b1)
            cnt <= 20'd0;
        else if(key_in == 1'b0 && cnt == CNT_MAX)
            cnt <= CNT_MAX;
        else 
            cnt <= cnt + 1'b1;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            key_flag <= 1'b0;        
        else if(cnt == CNT_MAX - 1'b1)
            key_flag <= 1'b1;
        else 
            key_flag <= 1'b0;
endmodule

三、逻辑仿真

3.1 仿真文件的编写

`timescale 1ns / 1ns
//
// Company: 追逐者——桥的小作坊
// Create Date: 2022/05/12 17:19:33
// Design Name: 按键消抖
// Module Name: tb_key_filter
//
module tb_key_filter();
    reg sys_clk ;
    reg sys_rst_n ;
    reg key_in ;
    reg [7:0] tb_cnt ;
    wire key_flag ;
    
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end 
    always #10 sys_clk = ~sys_clk;
//通过计数器模拟按键抖动过程
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            tb_cnt <= 8'd0;
        else if(tb_cnt == 8'd249)
            tb_cnt <= 8'd0;
        else 
            tb_cnt <= tb_cnt + 8'd1;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            key_in <= 1'b1;
        else if(((tb_cnt >= 8'd19) && (tb_cnt <= 8'd49))
             ||((tb_cnt >= 8'd149) && (tb_cnt <= 8'd199)))
             key_in <= {$random} % 2;
        else if((tb_cnt < 8'd19) || (tb_cnt > 8'd199))
            key_in <= 1'b1;
        else
            key_in <= 1'b0;   
//实例化            
key_filter 
#(
    .CNT_MAX(20'd24)      //最大计数时间20ms
)
key_filter_inst
(
    .sys_clk  (sys_clk  ),
    .sys_rst_n(sys_rst_n),
    .key_in   (key_in   ),
    .key_flag (key_flag )
);          
endmodule

3.2 仿真波形图对比

 

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐者-桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值