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

ops/2025/3/18 17:29:50/

按键边沿检测▷▷▷

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


http://www.ppmy.cn/ops/166828.html

相关文章

css基本功

为什么 ::first-letter 是伪元素&#xff1f; ::first-letter 的作用是选择并样式化元素的第一个字母&#xff0c;它创建了一个虚拟的元素来包裹这个字母&#xff0c;因此属于伪元素。 grid布局 案例一 <!DOCTYPE html> <html lang"zh-CN"><head&…

C#-委托delegate

一.C#-委托delegate C#中委托即C中函数指针,通过delegate关键字可声明一个代理.代理可像指针一样作为参数传递和调用. <1.声明一个代理类型 class Test{public delegate string CreateNativeString(); }<2.创建代理变量 class Main{public Test.CreateNativeString poi…

本地部署Jina AI Reader:用Docker打造你的智能解析引擎

本地部署Jina AI Reader&#xff1a;用Docker打造你的智能解析引擎 &#x1f31f; 引言&#xff1a;为什么需要本地部署&#xff1f;&#x1f4cc; 场景应用图谱&#x1f527; 部署指南&#xff08;Linux环境&#xff09;1. 环境准备2. Docker部署3. 验证服务状态 &#x1f680…

前端如何实现生成excel文件,并下载

后端很忙没有实现配合&#xff0c;主要由前端来实现&#xff0c;需要点击下载模版生成一个excel并下载的功能&#xff0c; 这是格式 <a href"javascript:void(0)"click"downloadTemplate">下载模板</a> import * as XLSX from "xlsx&qu…

【存储中间件】Redis核心技术与实战(四):Redis高并发高可用(Redis集群介绍与搭建)

文章目录 Redis集群集群前置知识数据分布理论节点取余分区一致性哈希分区虚拟一致性哈希分区虚拟槽分区为什么槽的范围是0 &#xff5e;16383&#xff1f; Redis数据分区Redis 虚拟槽分区的特点集群功能限制 搭建集群节点配置集群创建创建集群随机主从节点指定主从节点创建集群…

Harmony NEXT开发之创建自定义组件

目录 自定义组件的基本用法 自定义组件的基本结构 成员函数/变量 自定义组件的参数规定 build()函数 自定义组件通用样式 在ArkUI中&#xff0c;UI显示的内容均为组件&#xff0c;由框架直接提供的称为系统组件&#xff0c;由开发者定义的称为自定义组件。在进行 UI 界面…

基于 easyExcel 3.1.5依赖的包 实现动态表头 动态表格内容

1.需求&#xff1a;需要导出的EXCEL示例&#xff1a; 2.依赖&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.5</version></dependency> 3.工具类&#xff1a; p…

ZooKeeper的五大核心作用及其在分布式系统中的关键价值

引言 在分布式系统的复杂架构中&#xff0c;协调多个节点的一致性、可靠性和高可用性始终是技术挑战的核心。​Apache ZooKeeper作为业界广泛采用的分布式协调服务&#xff0c;凭借其简洁的树形数据模型&#xff08;ZNode&#xff09;和高效的原子广播协议&#xff08;ZAB&…