FPGA-----按键消抖

FPGA按键消抖

led、数码管、蜂鸣器都学完了。接下来就是给工程加按键,来实现更多的功能。但按键的加入必须先进行消抖,否则会出问题。这篇文章结尾有万能按键消抖模版,直接运用就行。



前言

按键抖动:按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。当按下一次按键,可能在A点检测到一次低电平,在B点检测到一次高电平,在C点又检测到一次低电平。同时抖动是随机,不可测的。那么按下一次按键,抖动可能会误以为按下多次按键。
所以要对按键进行消抖。


一、具体方式

1.延迟采样

需要在检测到按键抖动的时刻延时20ms再采样

2.抖动稳定后采样

需要不停的检测到按键抖动,直到信号稳定之后再延时20ms,之后采样

这里推荐一个写的很好的博客:
【FPGA】按键消抖
这章博客对按键消抖讲解的非常好。
我就直接偷懒,上万用模版

二、模版

// key #(.KEY_WIDTH(4)) key_inst(
//     /*input                           */.sys_clk     (sys_clk),
//     /*input                           */.sys_rst_n   (sys_rst_n),
//     /*input       [KEY_WIDTH - 1:0]   */.key_in      (),
//     /*output  reg [KEY_WIDTH - 1:0]   */.key_flag    ()
// );

module key#(
    parameter   KEY_WIDTH = 3'd4
    )(
    input                           sys_clk     ,
    input                           sys_rst_n   ,
    input       [KEY_WIDTH - 1:0]   key_in      ,
    output  reg [KEY_WIDTH - 1:0]   key_flag
);

parameter  CNT_MAX = 20'd1000_000;     //20ms消抖时间

localparam  IDLE    =   4'b0001,
            DONE    =   4'b0010,
            HOLD    =   4'b0100,
            UP      =   4'b1000;

reg     [3:0]   state;

reg     [KEY_WIDTH - 1:0]   key_in_reg0,
                            key_in_reg1,
                            key_in_reg2;

reg     [KEY_WIDTH - 1:0]   key_reg;

wire                        key_in_negedge,
                            key_in_posedge;

/* 打拍 */
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) begin
        key_in_reg0 <= {KEY_WIDTH{1'd1}};    /* 同步 */
        key_in_reg1 <= {KEY_WIDTH{1'd1}};    /* 同步 */
        key_in_reg2 <= {KEY_WIDTH{1'd1}};    /* 边沿 */
    end
    else begin
        key_in_reg0 <= key_in;
        key_in_reg1 <= key_in_reg0;
        key_in_reg2 <= key_in_reg1;
    end

/* 按位与,只要有一位出现了下降沿/上升沿,就会将该信号拉高 */
assign key_in_negedge = ((key_in_reg2 & ~key_in_reg1) != 'd0)? 1'b1 : 1'b0;
assign key_in_posedge = ((~key_in_reg2 & key_in_reg1) != 'd0)? 1'b1 : 1'b0;

reg     start_cnt;

reg             cnt_flag;
reg     [19:0]  cnt;
wire            add_cnt,end_cnt;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)		
        start_cnt <= 1'b0;
    else    if(end_cnt)
        start_cnt <= 1'b0;
    else    if(key_in_negedge || key_in_posedge)
        start_cnt <= 1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt <= 20'd0;
    else    if(add_cnt) begin
        if(end_cnt)
            cnt <= 20'd0;
        else
            cnt <= cnt + 1'b1;
    end
    else
        cnt <= 20'd0;

assign add_cnt = start_cnt;
assign end_cnt = add_cnt && ((cnt == CNT_MAX - 1) || (key_in_negedge));

/* 触发缓存 */
always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)								
        key_reg <= 'd0;
    else    if(key_in_negedge)
        key_reg <= key_in_reg1;


always@(posedge sys_clk or negedge sys_rst_n)	
    if(!sys_rst_n)								
        state <= IDLE;
    else    case(state)
        IDLE    :   if(key_in_negedge)
                        state <= DONE;
        DONE    :   if(end_cnt) begin
                        if(key_in == key_reg)
                            state <= HOLD;
                        else
                            state <= IDLE;
                    end
        HOLD    :   if(key_in_posedge)
                        state <= UP;
        UP      :   if(end_cnt)
                        state <= IDLE;
        default :   state <= IDLE;
    endcase

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        key_flag <= 'd0;
    else    if(state == HOLD && key_in_posedge)
        key_flag <= ~key_in_reg2;
    else
        key_flag <= 'd0;


endmodule

最上边就是例化模版,有工程需要用到按键消抖的话,直接分出一个模块,把这个模版复制进去,然后在顶层文件中例化这个模块(把上边的例化模版加进顶层再连线就行)。非常实用。


总结

偷懒,这个万用模版直接发在百度网盘里了,就在资源里
在这里插入图片描述
博客上传的工程都在百度网盘,有压缩包也有整个文件,可以自行下载。
链接:https://pan.baidu.com/s/1lQqqWZXfb3i6XHwkKf52zg
提取码:yang

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值