09-SDRAM控制器的设计——按键的处理(边沿捕获电路、硬件消抖、Verilog消抖电路)

发布于:2025-03-18 ⋅ 阅读:(20) ⋅ 点赞:(0)

按键边沿检测▷▷▷

边沿检测经常用于按键输入检测电路中,按键按下时输入信号 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

往期阅读

01-SDRAM控制器的设计——案例总概述

02-SDRAM控制器的设计——SDRAM简介

03-SDRAM控制器的设计——解读IS42R16320D的数据手册

04-SDRAM控制器的设计——control_interface.v代码解析

05-SDRAM控制器的设计——command.v代码解析

06-SDRAM控制器的设计——异步FIFO的调用

07-SDRAM控制器的设计——Sdram_Control.v代码解析

08-SDRAM控制器的设计——top文件代码解析


网站公告

今日签到

点亮在社区的每一天
去签到