【FPGA】四、按键消抖

2023-05-16

文章目录

一、按键消抖简介

 二、按键消抖方式

1、硬件消抖

2、软件消抖

三、程序设计

1、设计思路

2、程序代码

3、仿真验证

 总结


一、按键消抖简介

       按键在我们日常生活中是很常见的,主要有机械按键和虚拟按键。在我们用来进行FPGA开发的开发板上一般都是机械按键,由于机械按键的物理特性,按键在按下的过程中,存在一段时间的抖动,同时在释放按键的过程中也会存在抖动,这就导致在识别按键的时候可以检测到多次的按键按下,而通常检测到一次按键输入信号的状态为低电平,就可以确认按键被按下了,所以我们在使用按键时往往需要进行按键消抖,以确保按键被按下一次只检测到一次低电平。

        按键的抖动对于人类来说是感觉不到的,但是对于芯片来说,则是完全可以检测到电平的变化的,如果不对按键进行消抖处理,芯片可能会做出错误的判断,也就会导致我们的实验失败,所以进行按键消抖是非常有必要的。


 二、按键消抖方式

1、硬件消抖

        硬件消抖这种方式可以适用于在按键数较少时。硬件消抖的典型方法是,采用并联电容或者RS触发器。采用并联电容消抖是由于电容两端电压值不可突破,可以是上升沿和下降沿平滑无抖动。

        但在实际应用中,采用硬件消抖的效果往往不理想,不仅局限于按键的数量,并且这也增加了电路的成本和复杂程度,所以实际项目中采用物理消抖的方式并不常用。

2、软件消抖

        硬件消抖具有一定的局限性,当按键数量较多时,硬件消抖的方法就不是很实用了。

        采用软件进行按键消抖原理也是很简单的,就是检测到按键闭合后执行一个延时程序,机械按键的抖动一般都在20ms之类,我们只需要延时20ms后再一次去检测按键的状态,如果仍然保持闭合状态,则确认按键按下。当按键释放的时候也要进行一个20ms的延时。


三、程序设计

1、设计思路

        按键消抖,就是当按键不再抖动的时候按键有效。整体设计思路就是当检测到按键下降沿的时候开始计时20ms,如果在计时20ms期间由出现了一个上升沿,则计数器清零,等待下一个下降沿的到来便开始计数,反复进行,直到计时20ms内没有出现上升沿,就表明按键处于稳定状态了,表示按键按下。

2、程序代码

按键消抖模块代码如下:


/*========================================*
    filename    : key_filter.v
    description : 按键消抖实验
    time        : 2022-11-08 
    author      : 卡夫卡与海
*========================================*/

module key_filter(
    input       clk      ,//系统时钟 50MHZ
    input       rst_n    ,//系统复位
    input       key_in   ,//按键输入

    output reg  key_down   //按键输出 
);
//参数定义
parameter   DELAY_TIME = 1_000_000;//20ms

//信号定义
reg             filter_flag ;//抖动标志

reg             key_r0      ;//打拍
reg             key_r1      ;
reg             key_r2      ;

wire            nedge       ;//下降沿
wire            podge       ;//上升沿

reg    [19:0]   cnt_20ms    ;//计数器,计数20ms
wire            add_cnt_20ms;
wire            end_cnt_20ms;

//对输入按键进行打拍,异步信号同步并检测边沿
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        key_r0 <= -1;//负数以补码方式存放,对原码取反加一
        key_r1 <= -1;
        key_r2 <= -1;
    end
    else begin
        key_r0 <= key_in;
        key_r1 <= key_r0;
        key_r2 <= key_r1;
    end
end

assign nedge = ~key_r1 && key_r2 ? 1'b1 :1'b0;//检测下降沿
assign podge = key_r1 && ~key_r2 ? 1'b1 :1'b0;//检测上升沿

//当检测到下降沿,filter_flag为1
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        filter_flag <= 1'b0;
    end
    else if(nedge)begin
        filter_flag <= 1'b1;
    end
    else if(end_cnt_20ms)begin
        filter_flag <= 1'b0;
    end
    else begin
        filter_flag <= filter_flag;
    end
end

//当检测到filter_flag为1时开始计数 cnt_20ms
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_20ms <= 0;
    end
    else if(add_cnt_20ms)begin
        if(end_cnt_20ms)begin
            cnt_20ms <= 0;
        end
        else begin
            cnt_20ms <= cnt_20ms + 1'b1;
        end
    end
end
assign add_cnt_20ms = filter_flag;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == (DELAY_TIME - 1);

//key_down取是最后当前周期的key_r2的值,是稳定的
//当计数器计数满20ms后,并且没有抖动时,表面抖动结束
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        key_down <= 0;
    end
    else if(end_cnt_20ms)begin
        key_down <= ~key_r2;
    end
    else begin
        key_down <= 0;
    end
end

endmodule

仿真模块代码如下:

`timescale 1ns/1ns

module key_filter_tb();
    reg         clk      ;
    reg         rst_n    ;
    reg         key_in   ;

    wire        key_down ;

//参数定义
parameter   CYCLE = 20;//20ns
parameter   RST_TIME = CYCLE*3;

//产生时钟
initial begin
    clk = 1'b0;
    forever 
    #(CYCLE/2)
    clk = ~clk;
end

//产生复位
initial begin
    rst_n = 1'b0;
    #(RST_TIME);
    rst_n = 1'b1;
end

//产生激励
initial begin
    key_in = 1'b1;
    #(RST_TIME);
    key_in = 1'b0;
    #20;
    key_in = 1'b1;
    #40;
    key_in = 1'b0;
    #3000;
    key_in = 1'b1;
    #5000;
    key_in = 1'b0;
    #20000;
    $stop;
end

//模块例化
key_filter u_key_filter(
    /*input       */.clk        (clk     ),//系统时钟 50MHZ
    /*input       */.rst_n      (rst_n   ),//系统复位
    /*input       */.key_in     (key_in  ),//按键输入

    /*output reg  */.key_down   (key_down)  //按键输出 
);


endmodule

3、仿真验证

说明:

        通过仿真波形可以看到,当计数20ms之类按键状态发生跳变是,计数器清零,并重新开始计数,直到计数器20ms内按键状态没有发生改变时,此时表示按键按下。 


 总结

        按键消抖还是比较简单的,主要时要弄清楚其中的原理,这里的打拍就是寄存一次,打几拍就是寄存几次,这样使得数据更加稳定,便于进行边沿检测。

        这里按键输入只有一个按键,感兴趣的小伙伴可以去尝试对几个按键进行消抖处理,原理都是一样的,应该问题不大。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【FPGA】四、按键消抖 的相关文章

  • Quartus II 安装

    本次介绍使用的 Quartus 版本为 10 1 目前 Quartus II 官网已经没有 13 1 以下版本的安装包 大家可以安装 13 1 以上版本的软件 功能都是大同小异 下载地址 FPGA Software Download Cen
  • 基于FPGA的频率计设计

    文章目录 写在前面 1 什么是频率计 2 测量方法与基本原理 3 待测信号如何输入FPGA 一 实验程序 1 RTL图 2 Verilog 参考设计 3 指派引脚 二 调试验证 输入不同频率的方波 写在前面 1 什么是频率计 频率计是一种专
  • SmartFusion从FPGA到ARM(四)——MSS_TIMER定时器的使用

    文章目录 1 定时器资源简介 2 MSS TIMER库函数简介 3 简单的周期性中断 4 自定义产生波形 5 64位定时器的使用 6 单次中断模式 系列教程 SmartFusion从FPGA到ARM系列教程 1 定时器资源简介 SmartF
  • cdc多bit信号-握手处理

    对于多bit数据跨时钟 各个bit之间路径延迟不一样 源时钟域给的数据是2 b11 目的时钟域采样到的数据可能2 b10 因此两级触发器对于单bit数据跨时钟是可以用的 但是对于多bit数据跨时钟就会出错 握手处理的关键是利用源的时钟req
  • PLL时钟约束

    方法 1 自动创建基时钟和 PLL 输出时钟 例 derive pll clocks 这一方法使您能够自动地约束 PLL 的输入和输出时钟 ALTPLL megafunction 中指定的 所有 PLL 参数都用于约束 PLL 的输入和输出
  • Xilinx ISE系列教程(9):LabTools下载、安装、使用教程(独立的下载工具)

    文章目录 1 ISE Vivado LabTools简介 2 ISE 14 7 Lab Tools下载 安装 3 Vivado 2018 3 LabTools下载 安装 1 ISE Vivado LabTools简介 Xilinx LabT
  • FPGA(3)验证数字逻辑(与门、与非门、二选一数据选择器、2-4译码器、半加器、全加器)

    目录 一 验证与门 二 验证与非门 三 验证二选一数据选择器 四 验证2 4译码器 五 验证半加器 六 验证全加器 0 初始化定义 1 第一个半加器 2 第二个半加器 3 得到最终进位Co 代码 0决定与 1决定或 一 验证与门 只要有一个
  • Verilog之assign

    Verilog中的关键词assign主要用于如下两个地方 数据流建模 用于数据流建模的显示连续赋值语句语法格式如下
  • HDLBits刷题_Verilog Language_Procedures_Alwaysblock1

    学习内容 Since digital circuits are composed of logic gates connected with wires any circuit can be expressed as some combin
  • [HDLBits] Exams/ece241 2014 q7a

    Design a 1 12 counter with the following inputs and outputs Reset Synchronous active high reset that forces the counter
  • FPGA Lattice Diamond 开发环境搭建

    FPGA Lattice Diamond 开发环境搭建 Lattice Diamond 软件下载 在浏览器中输入 Lattice 的官网地址 http www latticesemi com 进入官网首页在上方选择产品系列选项 出现如下图所
  • [从零开始学习FPGA编程-38]:进阶篇 -语法-函数与任务

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 前言 第1章 什么是函数Function 1 1 什么是函数 1 2 函
  • 用python接收高速率的UDP数据包

    我正在使用 python 来从 FPGA 接收 UDP 数据包流 并尝试丢失尽可能少的数据包 数据包速率从大约 5kHz 到一些 MHz 我们希望在特定时间窗口 代码中的 acq time 内获取数据 我们现在有这样的代码 BUFSIZE
  • Linux驱动程序DMA传输到PC作为主机的PCIe卡

    我正在开发一个 DMA 例程 将数据从 PC 传输到 PCIe 卡上的 FPGA 我阅读了 DMA API txt 和 LDD3 ch 15 详细信息 但是 我不知道如何从 PC 到 PCIe 卡上的一致 iomem 块进行 DMA 传输
  • PyOpenCL 中的时间测量

    我正在 FPGA 和 GPU 中使用 PyOpenCL 运行内核 为了测量执行所需的时间 我使用 t1 time event mykernel queue c width c height block size block size d c
  • UIO 设备上的 mmap EINVAL 错误

    在尝试使用 UIO 而不是直接映射后 我在 Xilinx Zynq 上映射物理内存时遇到问题 dev mem 虽然计划是以普通用户身份运行应用程序 而不是root这仍在运行root 显然 第一个映射成功 其余映射到同一个文件描述符12 de
  • 模拟器和合成器之间初始化状态机的差异

    我的问题是关于合成状态机中使用的第一个状态 我正在使用莱迪思 iCE40 FPGA 用于仿真的 EDA Playground 和用于综合的莱迪思 Diamond Programmer 在下面的示例中 我生成一系列信号 该示例仅显示引用状态机
  • if 语句导致 Verilog 中的锁存推断?

    我正在编写用于合成算法的 Verilog 代码 我对哪些情况可能导致推断锁存器有点困惑 下面是这样的一段代码 虽然它在模拟中工作得很好 但我担心它可能会导致硬件问题 always b1 or b2 b1 map b2 map m1 map
  • 如何使用 Verilog 和 FPGA 计算一系列组合电路的传播延迟?

    我是 FPGA 和 HDL 的新手 但我正在尝试学习 但无法弄清楚这一点 如何通过多个级别的组合逻辑来计算或估计传播延迟 我可以仅凭经验确定这一点 还是可以在设计时弄清楚 在这种情况下 我使用 FPGA 来实现奇偶校验设置和检查电路 该电路
  • FPGA 有哪些实际应用?

    我对我的程序为一个小型七段显示器提供动力感到非常兴奋 但是当我向不在现场的人展示它时 他们总是说 那么你能用它做什么 我永远无法给他们一个简洁的答案 谁能帮我吗 第一 它们不需要具有易失性存储器 事实上 大厂商 Xilinx Altera

随机推荐

  • SpringCloud ---启动顺序

    1 启动Eureka服务模块 2 启动Eureka客户端被调用者模块 3 最后启动Eureka调用者模块
  • Zabbix6.0LTS安装流程

    安装环境选择 xff1a eSXI6 7 43 CentOS8 43 Zabbix6 0LTS 43 MySQL 43 Apache zabbix官方网站 xff1a 下载Zabbix 1 打开命令行控制台 xff08 ctrl 43 al
  • Java中Arrays类中的数组操作方法详解

    前言 我们讲到了一维数组和二维数组以及开发工具eclipse的配置 java util Arrays 类能方便地操作数组 xff0c 它提供的所有方法都是静态的 具有以下功能 xff1a 替换元素以及填充元素 xff1a 通过 fill 方
  • 【一行命令】查看Linux系统查看端口长连接数量

    netstat an grep 8080 wc l
  • JAVA中集合类概述

    目录 前言 一 集合类概述 二 Collection 1 List实现 2 set实现 三 Map 总结 前言 这篇文章是根据张席主编的 JAVA语言程序设计教程 提炼出来的一些JAVA中集合的知识 xff0c 还会加上我在编程过程中的遇到
  • 归并排序算法

    目录 何为归并排序 排序步骤 合并过程 全过程 归并排序实现代码 xff08 C语言描述 xff09 复杂度分析 归并排序的优缺点 何为归并排序 归并排序 merge sort 是建立在归并操作上的一种有效 xff0c 稳定的排序算法 xf
  • 生产者消费者设计模式

    生产者和消费者模式 是一个经典的多线程设计模式 xff0c 生产者和消费者在同一时间段内共用同一个存储空间 xff0c 生产者往存储空间中添加产品 xff0c 消费者从存储空间中取走产品 xff0c 当存储空间为空时 xff0c 消费者阻塞
  • MySQL/MariaDB 字段约束

    主键约束 primary key 唯一且不为空 主键约束 xff1a 如果为一个列添加了主键约束 xff0c 那么这个列就是主键 xff0c 主键的特点是唯一且不能为空 通常情况下 xff0c 每张表都会有主键 添加主键约束 xff0c 例
  • MySQL/MariaDB 时间函数

    获取年月日时分秒 SELECT NOW 年月日及当前时间 SELECT CURDATE 年月日 SELECT CURRENT DATE 年月日 SELECT CURTIME 时分秒 SELECT CURRENT TIME 时分秒 年份 YE
  • MySQL/MariaDB 查询语句

    基础表 emp 去重查询 DISTINCT 查询职位 SELECT job from emp 显示所有职位 SELECT DISTINCT job FROM emp 查看表中包含的所有job类型 xff0c 重复的只显示一个 输出结果 限制
  • Spring框架通过工厂实现对象实例化过程

  • Eclipse常用设置

    1 界面风格 2 代码字体字号 3 工作空间编码
  • SpringBoot整合HikariCP连接池

    整合 HikariCP 连接池 创建依赖 配置连接池 打开 application properties 配置文件 xff0c 添加如下内容 spring datasource url 61 jdbc mysql dbgoods serve
  • SpringBoot框架整合MyBatis

    添加 MyBatis 启动依赖 参考官网mybatis org spring 找到Spring Boot菜单选项 基于菜单项找到MyBatis启动依赖 xff0c 一定要设置版本 xff0c Spring Boot 中没有设置 MyBati
  • BadTokenException: Unable to add window -- token android.os.BinderProxy

    由于遇到的是BadTokenException这个异常 xff0c 所以搜资料总结了一下 xff1a 这个异常总共有一下几种出现方式 xff1a 1 Unable to add window token null is not valid
  • SpringBoot框架整合SpringMVC、Mybatis框架,对数据库操作的工作原理

    Controller层 Controller层是接收用户访问的url信息 xff0c 再将获取到的内容发送到其他层级进行处理 xff0c 处理完成后返回新的url xff0c 使用户得到想要查询或是其他操作的页面 64 Controller
  • Lombok插件应用

    Lombok安装步骤 https blog csdn net weixin 47253919 article details 119871501 spm 61 1001 2014 3001 5502 常用注解 64 Setter 用于为描述
  • 类的属性(公有属性,受保护属性,私有属性)

    x是类的公有属性 class Animal x 61 10 def test self print Animal x print self x self是类本身 xff0c 等于Animal class Dog Animal def tes
  • linux网络配置(超简单,一看就会)

    2022 11 19 文章目录 前言一 linux网络 xff1f 二 使用步骤 1 查看本机ip 2 进入root用户 3 进入配置网络的目录 4 配置网络 5 重启网络服务 6 查看IP并测试网络 总结 一 linux网络 本章以配置虚
  • 【FPGA】四、按键消抖

    文章目录 一 按键消抖简介 二 按键消抖方式 1 硬件消抖 2 软件消抖 三 程序设计 1 设计思路 2 程序代码 3 仿真验证 总结 一 按键消抖简介 按键在我们日常生活中是很常见的 xff0c 主要有机械按键和虚拟按键 在我们用来进行F