verilog-实现按键消抖模块

这篇具有很好参考价值的文章主要介绍了verilog-实现按键消抖模块。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.按键消抖原理

轻触按键:相当于是一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开。
开关消抖程序verilog,Verilog,fpga开发
说明: 如上图,产生的抖动次数以及间隔时间均是不可预期的,这就需要通过滤波来消除抖动可能对外部其他设备造成的影响。一般情况下抖动的总时间会持续20ms以内。这种抖动,可以通过硬电路或者逻辑设计的方式来消除,也可以通过软件的方式完成。其中硬件电路消除抖动适用于按键数目较少的场合。

2.实现方案-状态机(Mealy型)

开关消抖程序verilog,Verilog,fpga开发

说明:

  • IDLE:时空闲状态
  • FILTER0:按下抖动滤除状态
  • DOWN:按下稳定状态
  • FILTER1:释放抖动滤除状态
  • 采用独热码编码方式,优点:电路速度快;缺点:占用资源。
    开关消抖程序verilog,Verilog,fpga开发

3.Verilog代码

**ps:**代码中涉及的脉冲边缘检测电路,可以看博主的文章:
脉冲边缘检测电路-verilog实现

(1)高电平有效的情况

高电平有效的Verilog实现
//---------------------------------------------------
//高电平有效
//输出模板  o_key_flag && !o_key_state (一个脉冲)表示按下

module key1_filter_module(

    input                               i_clk                     ,
    input                               i_rstn                    ,
    input                               i_key                     ,
    output reg                          o_key_flag                ,
    output reg                          o_key_state                  
	);


parameter
        IDEL        =  4'b0001,
        FILTER0     =  4'b0010,
        DOWN        =  4'b0100,
        FILTER1     =  4'b1000;
    

		
reg    [3:0]   state                ;
reg    [19:0]  cnt_20ms             ;
reg            en_cnt_20ms          ;//使能计数寄存器
reg            i_key_a,i_key_b      ;
reg            key_tmp_a,key_tmp_b  ;
reg            cnt_20ms_full        ;//计数满标志信号
wire           pedge,nedge          ;
 
//---------------跨时钟域处理,打两个拍子----------------//
always@(posedge i_clk or negedge i_rstn)
    if(!i_rstn)
      begin
         i_key_a <= 1'b0;
         i_key_b <= 1'b0;
      end
    else 
        begin
         i_key_a <= i_key;
         i_key_b <= i_key_a;
       end
//-------------边沿监测电路----------------------------//
always@(posedge i_clk or negedge i_rstn)
    if(!i_rstn)begin
        key_tmp_a <= 1'b0;
        key_tmp_b <= 1'b0;
    end
    else begin
        key_tmp_a <= i_key_b;
        key_tmp_b <= key_tmp_a;
    end
	
assign nedge = !key_tmp_a &  key_tmp_b  ;
assign pedge = key_tmp_a  & (!key_tmp_b);

//------------------------20ms计数器------------------//
always@(posedge i_clk or negedge i_rstn)
    if(!i_rstn)
        cnt_20ms <= 20'd0;
    else if(en_cnt_20ms)
        cnt_20ms <= cnt_20ms + 1'b1;
    else
        cnt_20ms <= 20'd0;
	
always@(posedge i_clk or negedge i_rstn)
    if(!i_rstn)
        cnt_20ms_full <= 1'b0;
    else if(cnt_20ms == 999_999)
        cnt_20ms_full <= 1'b1;
    else
        cnt_20ms_full <= 1'b0;

//----------------fsm-----------------------------
always@(posedge i_clk or negedge i_rstn)
    if(!i_rstn)begin
        en_cnt_20ms <= 1'b0;
        state       <= IDEL;
        o_key_flag  <= 1'b0;
        o_key_state <= 1'b1;
    end
    else begin
        case(state)
            IDEL :
                begin
                    o_key_flag <= 1'b0;
                    if(pedge)begin
                        state       <= FILTER0;
                        en_cnt_20ms <= 1'b1;
                    end
                    else
                        state <= IDEL;
                end
					
            FILTER0:
                if(cnt_20ms_full)begin
                    o_key_flag  <= 1'b1;
                    o_key_state <= 1'b0;
                    en_cnt_20ms <= 1'b0;
                    state       <= DOWN;
                end
                else if(nedge)begin
                    state       <= IDEL;
                    en_cnt_20ms <= 1'b0;
                end
                else
                    state <= FILTER0;
					
            DOWN:
                begin
                    o_key_flag <= 1'b0;
                    if(nedge)begin
                        state       <= FILTER1;
                        en_cnt_20ms <= 1'b1;
                    end
                    else
                        state <= DOWN;
                end
			
            FILTER1:
                if(cnt_20ms_full)begin
                    o_key_flag  <= 1'b1;
                    o_key_state <= 1'b1;
                    en_cnt_20ms <= 1'b0;
                    state       <= IDEL;
                end
                else if(pedge)begin
                    en_cnt_20ms <= 1'b0;
                    state       <= DOWN;
                end
                else
                    state <= FILTER1;
			
            default:
                begin
                    state       <= IDEL;
                    en_cnt_20ms <= 1'b0;
                    o_key_flag  <= 1'b0;
                    o_key_state <= 1'b1;
                end
				
        endcase
    end
	


endmodule

高电平有效的TESTBENCH
`timescale 1ns / 1ps

module tb_key1_filter_module;

//port
     reg  i_clk  = 1      ; 
     reg  i_rstn = 0      ;
     reg  i_key           ;
     wire o_key_flag      ;
     wire o_key_state     ;


key1_filter_module uut (
		.i_clk          (i_clk       ) , 
		.i_rstn         (i_rstn      ) , 
		.i_key          (i_key       ) , 
		.o_key_flag     (o_key_flag  ) ,
        .o_key_state    (o_key_state )
	);

    
always #10 i_clk <= ~i_clk ; //50MHZ
    
initial begin     
          i_key  <= 1;     
    #20  i_rstn  <= 1;

   #10_000_000;        
    i_key <= 0;    #1000;
    i_key <= 1;    #2000;
    i_key <= 0;    #1400;
    i_key <= 1;    #2600;
    i_key <= 0;    #1300;
    i_key <= 1;    #200;
    
    i_key <= 0;   #30_000_000;
   
    i_key <= 1;    #2000;
    i_key <= 0;    #1000;
    i_key <= 1;    #2600;
    i_key <= 0;    #1400;
    i_key <= 1;    #200;
    i_key <= 0;    #1300;
    
    i_key <= 1;   #30_000_000;
    
    end
endmodule 

(2)低电平有效的情况

低电平有效的Verilog实现
//---------------------------------------------------
//低电平有效
//输出模板  o_key_flag && !o_key_state (一个脉冲)表示按下

module key0_filter_module(

input                               i_clk                     ,
input                               i_rstn                    ,
input                               i_key                     ,
output reg                          o_key_flag                ,
output reg                          o_key_state                  
);


parameter
    IDEL        =  4'b0001,
    FILTER0     =  4'b0010,
    DOWN        =  4'b0100,
    FILTER1     =  4'b1000;


    
reg    [3:0]   state                ;
reg    [19:0]  cnt_20ms             ;
reg            en_cnt_20ms          ;//使能计数寄存器
reg            i_key_a,i_key_b      ;
reg            key_tmp_a,key_tmp_b  ;
reg            cnt_20ms_full        ;//计数满标志信号
wire           pedge,nedge          ;

//---------------跨时钟域处理,打两个拍子----------------//
always@(posedge i_clk or negedge i_rstn)
if(!i_rstn)
  begin
     i_key_a <= 1'b0;
     i_key_b <= 1'b0;
  end
else 
    begin
     i_key_a <= i_key;
     i_key_b <= i_key_a;
   end
//-------------边沿监测电路----------------------------//
always@(posedge i_clk or negedge i_rstn)
if(!i_rstn)begin
    key_tmp_a <= 1'b0;
    key_tmp_b <= 1'b0;
end
else begin
    key_tmp_a <= i_key_b;
    key_tmp_b <= key_tmp_a;
end

assign nedge = !key_tmp_a &  key_tmp_b  ;
assign pedge = key_tmp_a  & (!key_tmp_b);

//------------------------20ms计数器------------------//
always@(posedge i_clk or negedge i_rstn)
if(!i_rstn)
    cnt_20ms <= 20'd0;
else if(en_cnt_20ms)
    cnt_20ms <= cnt_20ms + 1'b1;
else
    cnt_20ms <= 20'd0;

always@(posedge i_clk or negedge i_rstn)
if(!i_rstn)
    cnt_20ms_full <= 1'b0;
else if(cnt_20ms == 999_999)
    cnt_20ms_full <= 1'b1;
else
    cnt_20ms_full <= 1'b0;

//----------------fsm-----------------------------
always@(posedge i_clk or negedge i_rstn)
if(!i_rstn)begin
    en_cnt_20ms <= 1'b0;
    state       <= IDEL;
    o_key_flag  <= 1'b0;
    o_key_state <= 1'b1;
end
else begin
    case(state)
        IDEL :
            begin
                o_key_flag <= 1'b0;
                if(nedge)begin
                    state       <= FILTER0;
                    en_cnt_20ms <= 1'b1;
                end
                else
                    state <= IDEL;
            end
                
        FILTER0:
            if(cnt_20ms_full)begin
                o_key_flag  <= 1'b1;
                o_key_state <= 1'b0;
                en_cnt_20ms <= 1'b0;
                state       <= DOWN;
            end
            else if(pedge)begin
                state       <= IDEL;
                en_cnt_20ms <= 1'b0;
            end
            else
                state <= FILTER0;
                
        DOWN:
            begin
                o_key_flag <= 1'b0;
                if(pedge)begin
                    state       <= FILTER1;
                    en_cnt_20ms <= 1'b1;
                end
                else
                    state <= DOWN;
            end
        
        FILTER1:
            if(cnt_20ms_full)begin
                o_key_flag  <= 1'b1;
                o_key_state <= 1'b1;
                en_cnt_20ms <= 1'b0;
                state       <= IDEL;
            end
            else if(nedge)begin
                en_cnt_20ms <= 1'b0;
                state       <= DOWN;
            end
            else
                state <= FILTER1;
        
        default:
            begin
                state       <= IDEL;
                en_cnt_20ms <= 1'b0;
                o_key_flag  <= 1'b0;
                o_key_state <= 1'b1;
            end
            
    endcase
end



endmodule

低电平有效的TESTBENCH
`timescale 1ns / 1ps

module tb_key0_filter_module;

//port
     reg  i_clk  = 0      ; 
     reg  i_rstn = 0      ;
     reg  i_key           ;
     wire o_key_flag      ;
     wire o_key_state     ;


key0_filter_module uut (
		.i_clk          (i_clk       ) , 
		.i_rstn         (i_rstn      ) , 
		.i_key          (i_key       ) , 
		.o_key_flag     (o_key_flag  ) ,
        .o_key_state    (o_key_state )
	);

    
always #10 i_clk <= ~i_clk ; //50MHZ
    
initial begin     
          i_key  <= 0;     
    #20  i_rstn  <= 1;

   #10_000_000;        
    i_key <= 1;    #1000;
    i_key <= 0;    #2000;
    i_key <= 1;    #1400;
    i_key <= 0;    #2600;
    i_key <= 1;    #1300;
    i_key <= 0;    #200;
    
    i_key <= 1;   #30_000_000;
   
    i_key <= 0;    #2000;
    i_key <= 1;    #1000;
    i_key <= 0;    #2600;
    i_key <= 1;    #1400;
    i_key <= 0;    #200;
    i_key <= 1;    #1300;
    
    i_key <= 0;   #30_000_000;
    
    end
endmodule 


本文来自参考:小梅哥的设计方案
https://www.bilibili.com/video/BV1KE411h7AZ?p=8&vd_source=696332c534453c3966f51e8e54ca6453
本篇随笔为学习记录所用,如有侵权,请联系博主。文章来源地址https://www.toymoban.com/news/detail-771721.html

到了这里,关于verilog-实现按键消抖模块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 用verilog编写按键消抖代码

    本代码在按键按下和松开情况下均能消抖,消抖延时20ms(时钟频率为100MHz时)。 代码如下 module key3_led2( //from system input     input    clk,     input    rstn, //from external input to pl     input    ex_key1,        //按键从PL端输入 //from pl to ps     output    reg    pl_key1    //处理

    2024年02月02日
    浏览(44)
  • 【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)

    🎉欢迎来到FPGA专栏~按键消抖模块设计与验证 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 模块设计: 🥝 按键消

    2024年02月12日
    浏览(45)
  • fpga verilog rs232 发送模块实现

    RS-232是一种串行通信协议,用于在计算机和其他外部设备之间进行数据传输。RS-232定义了电气特性、信号级别、机械特性和传输速率等规范,为串行通信提供了一种标准化的接口。 RS-232通常使用DB9连接器,用于传输和接收数据、控制信号以及地线连接。 但除了235脚其它基本

    2024年02月03日
    浏览(51)
  • 【Verilog实现FPGA上的信号延迟】—— 用Verilog代码实现将信号延迟N拍,这是FPGA中非常重要的一个操作,可以使数据在不同模块之间精确同步。

    【Verilog实现FPGA上的信号延迟】—— 用Verilog代码实现将信号延迟N拍,这是FPGA中非常重要的一个操作,可以使数据在不同模块之间精确同步。 模块是FPGA中最基本的构建模块。通常一个模块代表一个电路,包括输入、输出和处理逻辑。模块中包含的处理逻辑被称为时序逻辑。

    2024年02月04日
    浏览(75)
  • 北邮22级信通院数电:Verilog-FPGA(9)第九周实验(3)实现一个具有清零功能的按键计数器,对按键进行计数并显示

    北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章,请访问专栏: 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客   目录 一.代码部分 1.1 counter.v 1.2 debounce.v 二.管脚分配 三.实现效果

    2024年02月05日
    浏览(66)
  • FPGA模块使用Verilog调用另一个Verilog模块

    FPGA模块使用Verilog调用另一个Verilog模块 在FPGA设计中,常常需要将一个大的模块分解成多个子模块来实现。而这些子模块通常由Verilog代码编写而成。在设计中,我们需要通过调用这些子模块来实现整体的功能。本文将介绍如何使用Verilog调用另一个Verilog模块。 为了说明这个过

    2024年02月07日
    浏览(46)
  • FPGA入门学习笔记(十三)Vivado实现按键消抖

    四种状态 按键未按下:静止状态呈高电平; 按下过程中:抖动状态呈高低电平; 按键已按下:静止状态呈低电平; 释放过程中:抖动状态呈高低电平。 按键消抖思路 :区别于单片机使用20ms延时判断电平正负,FPGA中采用电平保持计时,若时间长度超过20ms则认为发生了一次

    2024年02月04日
    浏览(71)
  • 【【IIC模块Verilog实现---用IIC协议从FPGA端读取E2PROM】】

    下面是 design 设计 下面是testbench 下面是注意事项 因为时钟的不同 我们先设计出本次时钟所需要的dri_clk 在配置完dri_clk 之后 我们需要做的是对整个I2C结构 进行状态机的 书写 建议 写成经典的三段状态机的形式 同步时序描述状态转移 组合逻辑判断状态转移条件 时序电路描述

    2024年02月03日
    浏览(53)
  • 【FPGA】Verilog设计入门——时序模块及其Verilog表述

    目录 1.边沿触发型触发器及其Verilog表述 2.电平触发型锁存器及其Verilog表述  3.含异步复位/时钟使能型触发器及其Verilog表述 4.同步复位型触发器及其Verilog表述  5.异步复位型锁存器及其Verilog表述 6.Verilog的时钟过程表述的特点和规律   7.异步时序模块的Verilog表述  8.4位二进制

    2024年02月07日
    浏览(41)
  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包