边沿检测、按键消抖的Verilog实现

边沿检测、按键消抖的Verilog实现边沿检测 按键消抖的 Verilog 实现 边沿检测和按键消抖是 FPGA 设计中比较经常用到的小模块 本篇介绍一下这两个部分的简单实现 1 边沿检测 边沿检测技术在项目应用中 非常广泛 如要有效捕获信号跳变沿 边沿检测技术的应用是必不可少的 其中有如下几个方面 1 将时钟边沿使能转换为边沿检测使能 使时钟同步化

大家好,我是讯享网,很高兴认识大家。

边沿检测、按键消抖的Verilog实现
边沿检测和按键消抖是FPGA设计中比较经常用到的小模块,本篇介绍一下这两个部分的简单实现。
1.边沿检测
边沿检测技术在项目应用中,非常广泛。如要有效捕获信号跳变沿,边沿检测技术的应用是必不可少的。其中有如下几个方面
(1)将时钟边沿使能转换为边沿检测使能,使时钟同步化。
(2)捕获信号的突变(UART,SPI 等信号使能突变)
(3)逻辑分析仪中信号的边沿检测。
(4)按键消抖中也可以使用
在这里插入图片描述
讯享网
就如上图所示,边沿检测就是清楚边沿0和1的变化顺序,时间一般都是从左往右进行,那么对于下降沿会首先检测一个1随后检测到0说明是下降沿,反之首先检测一个0随后检测到1是上升沿。这一点首先要清楚。
其次如何利用0和1来说明是哪个沿,此时我们先把0和1用寄存器寄存,利用(~0)&&1=1。有时综合后是RTL视图是一个两位的寄存器,实际原理电路如下:
在这里插入图片描述
右边寄存器寄存先来的值,左边的寄存后来的,检测到0的取反与1相与。
module byjc(
clk,
rst,
din,
posedge_d,
negedge_d
);
input clk,rst;
input din;
output posedge_d,negedge_d;

reg reg1,reg2; always@(posedge clk or negedge rst) begin if(!rst) begin reg1<=1'b0; reg2<=1'b0; end else {reg2,reg1}<={reg1,din}; /*reg1<=din; reg2<=reg1;*/ end assign posedge_d=reg1&&(~reg2); assign negedge_d=(~reg1)&&reg2; 

讯享网

endmodule
在这里插入图片描述
仿真视图,延后一拍
边沿检测有如下缺陷:
(1)增大 CLK 信号可以增强边沿检测的效率,但不能滤去跳变的杂波。
(2)减少 CLK 可以有效滤去跳变的杂波,但不能及时检测到边沿跳变。
(3)增加 DFF 能更好的滤除杂波,寄存信号,但同时检测延时大。
2.按键消抖
在这里先介绍一下按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,消除这种抖动的过程即称为按键消抖。按键消抖可分为硬件消抖和软件消抖。硬件消抖主要使用RS触发器或电容等方法实现消抖,一般在按键较少时使用。软件消抖的原理主要为按键按下或松开后延时5ms—20ms采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样,如图 所示
在这里插入图片描述
设计思想就是不断对按键输入值比较,如果发生变化开始计数,一般需要20ms,然后取稳定值。对于50M时钟,20ms需要计数次。在代码中为了说明问题暂时用1000.
module debounce(
input wire clk, rst,
input wire key_in,
output reg key_out,
output reg done
);

讯享网// localparam TIME_20MS = 1000; reg [20:0] cnt; reg en_cnt; //按键输入 always @(posedge clk or negedge rst) begin if(rst == 0) key_out <= 0; else key_out <= key_in; end //计数器 always @(posedge clk or negedge rst) begin if(rst == 0) cnt <= 0; else if(en_cnt) cnt <= cnt + 1'b1; else cnt <= 0; end //判断按键值是否变化产生使能计数 always @(posedge clk or negedge rst) begin if(rst == 0) begin en_cnt <= 0; done<=0; end else if(key_in != key_out) begin en_cnt <= 1; done<=0; cnt<=0; end else if(cnt == TIME_20MS - 1) //计数满产生完成标志 begin en_cnt <= 0; cnt<=0; done<=1; end end 

endmodule
在这里插入图片描述
仿真结果图
测试:
timescale 1ns/1nsdefine clk_period 20
module debounce_tb;

 reg clk,rst,key_in; wire done; wire key_out; reg [15:0] myrand; debounce u0( .clk(clk), .rst(rst), .key_in(key_in), .done(done), .key_out(key_out) 

);

讯享网initial clk=1; always #(`clk_period/2)clk=~clk; task press_key_in; begin repeat(20)begin myrand={$random}%65535; #myrand key_in=~key_in; end key_in=0; #20_000_000; repeat(20)begin myrand={$random}%65535; #myrand key_in=~key_in; end key_in=1; #20_000_000; end endtask initial begin rst=0; key_in=1; #(`clk_period*5)rst=1; press_key_in;#100; press_key_in;#100; $stop; end 

endmodule

小讯
上一篇 2025-02-05 18:28
下一篇 2025-03-13 19:07

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/33713.html