按键边沿检测
边沿检测经常用于按键输入检测电路中,按键按下时输入信号 key 变为低电平,按键抬起变为高电平。当输入的信号为理想的高低电平时(不考虑毛刺和抖动),边沿检测就发挥了很重要的作用。
由于输入的信号为一个连续值,我们需要通过时钟进行采样。根据采样定理,采样时钟的频率需要至少为被采信号频率的 2 倍。
设计的边沿检测电路的功能为:检测到 1 个下降沿或上升沿时,对应的下降沿输出信号 edge_pos、edge_neg 分别输出 1 个脉冲(即一个时钟周期的高电平)。下面以下降沿进行分析。
分析:在边沿检测的过程中,通过 1 个寄存器来寄存上一个时钟沿的输入值 D ,当寄存器输出 Q 与输入 D 的值分别为1、0时,证明检测到下降沿。

如上图所示,在第 2 个时钟周期的低电平期间,D 由高变低,在第 3 个时钟周期的上升沿,Q由高变低。在 D 由高变低的时刻,Q 为 1 ,D 为 0 ,证明检测到下降沿。
按键边沿捕获模块:

测试验证模块:

按一次按键,对应的LED灯就会亮。LED亮代表检测到了下降沿。
Signaltap 波形图:

按键硬件消抖电路
友晶科技很多板子的按键(都是按下为低电平)其实是已经有硬件消抖电路的, 这样的板子的按键的值 直接input 进来后 直接用就可以。
比如DE2-115 DE1-SOC DE10-Standard 等等。这里都用74HC245芯片来消抖:


按键Verilog消抖电路
如果没有硬件上的消抖,我们可以手写Verilog代码替代消抖电路。
模板一
模板一的Verilog消抖的原理主要为按键按下或松开后延时 1ms—20ms 采样(这个时间是根据按键的机械特性自行决定)。
假设时钟是50M,按键消抖的思路是检测到按下时延时 50000个时钟周期,再检测,如果状态仍为按下,则确认是按下的;如果状态为弹起的,则确认是干扰,无按键按下。
按键消抖的Verilog实现的模板一如下:
module key_debounce //按键消抖模块 ( input clk, //系统时钟 input rst_n, //系统复位 input key[0], //按键输入 output reg key_value, //有效的按键值 ); reg [31:0]cnt;//计数器 reg value;//中间寄存器 always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 0; //初始状态下寄存器清零 key_value <= 0; //有效按键值清零 value <= 0; //中间寄存器清零 end else begin if(cnt == 50000) begin cnt <= 0;//每隔0.001秒检测一次 将key的值寄存到value寄存器当中(如果系统时钟是50MHz) value <= key[0]; if(value == 1 && key[0] == 0) //按键按下为0,平时为1 key_value <= 1; end else begin cnt <= cnt + 1; key_value <= 0; end end end endmodule
模板二
模板二的检测原理是只有按键按下的状态持续50000个周期(这个时间可以自己再定义)以上,才认定是按键被按下了一次,否则算作是干扰被忽略掉。
模板二实现的是多个按键的去抖。
按键消抖的Verilog实现的模板二如下:
module debounce ( clk, reset_n, data_in, data_out ); parameter WIDTH = 32; // set to be the width of the bus being debounced parameter POLARITY = "HIGH"; // set to be "HIGH" for active high debounce or "LOW" for active low debounce parameter TIMEOUT = 50000; // number of input clock cycles the input signal needs to be in the active state parameter TIMEOUT_WIDTH = 16; // set to be ceil(log2(TIMEOUT)) input wire clk; input wire reset_n; input wire [WIDTH-1:0] data_in; output wire [WIDTH-1:0] data_out; reg [TIMEOUT_WIDTH-1:0] counter [0:WIDTH-1]; wire counter_reset [0:WIDTH-1]; wire counter_enable [0:WIDTH-1]; // need one counter per input to debounce genvar i; generate for (i = 0; i < WIDTH; i = i+1) begin: debounce_counter_loop always @ (posedge clk or negedge reset_n) begin if (reset_n == 0) begin counter[i] <= 0; end else begin if (counter_reset[i] == 1) // resetting the counter needs to win begin counter[i] <= 0; end else if (counter_enable[i] == 1) begin counter[i] <= counter[i] + 1'b1; end end end if (POLARITY == "HIGH") begin assign counter_reset[i] = (data_in[i] == 0); assign counter_enable[i] = (data_in[i] == 1) & (counter[i] < TIMEOUT); assign data_out[i] = (counter[i] == TIMEOUT) ? 1'b1 : 1'b0; end else begin assign counter_reset[i] = (data_in[i] == 1); assign counter_enable[i] = (data_in[i] == 0) & (counter[i] < TIMEOUT); assign data_out[i] = (counter[i] == TIMEOUT) ? 1'b0 : 1'b1; end end endgenerate endmodule
全部0条评论
快来发表一下你的评论吧 !