【FPGA入门】第五篇、按键消抖
目录
第一部分、按键抖动现象
第二部分、消抖思路及代码
1、简单的按键消抖思路
2、实际按键消抖思路
3、实际按键消抖模块代码
第三部分、总结
第一部分、按键抖动现象
只要学习过单片机的都会知道,按键在按下去和松开的那个瞬间都存在抖动,在单片机消除抖动最简单的方式就是延时。
在FPGA的开发过程中,按键也不是理想状态。所以在按下按键和松开按键的瞬间都是存在机械抖动的。
这种抖动可分为前抖动(按下瞬间带来的抖动),后抖动(松开瞬间带来的抖动),如下图所示。
无论是前抖动还是后抖动,持续时间大约是5~10ms。

第二部分、消抖思路及代码
1、简单的按键消抖思路
如下图为最简单的按键检测思路。这种思路,在不考虑按键存在抖动的情况下,用寄存器打拍的方式(pipeline),将key延时一个时钟周期,变为key_old。
接着再通过检测key与key_old之间的信号差,来判断按键是否按下。

实现代码如下:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : 2624507313@qq.com
// File : key_shift_led.v
// Create : 2023-04-14 13:58:37
// -----------------------------------------------------------------------------
module key_shift_led(input wire clk,input wire rst_n,input wire key1,output wire [3:0]led);
//寄存器打拍,延迟key一个时钟周期
reg key_old;
//led流水状态寄存器
reg [3:0]led_shift = 4'b0001;//获取key_old信号
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginkey_old <= 1'b1;endelse beginkey_old <= key1;end
end
//理想按键按下检测方式
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginled_shift <= 4'b0001;endelse if (key1 == 1'b0 && key_old == 1'b1) beginled_shift <= {led_shift[2:0],led_shift[3]};end
end
//led状态赋值
assign led = led_shift;endmodule
这种简单的消抖方式存在以下问题:
有的时候,按下按键,会看到LED灯一次性跳过两个,或者三个,没有实现按一下,跳一下的功能。
2、实际按键消抖思路
在消除抖动之后,如果检测到按键按下(低电平持续了5ms),那么就输出一个周期的单脉冲标志,来表示按键按下。
这么做的原因:人在正常按下按键,松开按键,按键稳定的时间一般是大于五毫秒的。
cnt_5ms:这个计数器在clk下计数,清零方式为key == 1,cnt_5ms == 5ms计数值
stable_flag:保证press_flag有且仅有一个时钟周期的高电平。cnt_5ms这个计数器在,key == 0,cnt_5ms == 5ms计数值的时候翻转,清零为key == 1
如果不这样搞得话,那么stable_flag在稳定时间里面就会有多个高脉冲。
press_flag:在cnt_5ms == 5ms计数值,stable_flag == 0的时候翻转。这样才是一个周期的单脉冲。
实际按键检测的时序图如下图所示:

3、实际按键消抖模块代码
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : 2624507313@qq.com
// File : key_shift_led_elim.v
// Create : 2023-04-14 12:38:11
// -----------------------------------------------------------------------------
module key_shift_led_elim(input wire clk,input wire rst_n,input wire key1,output wire [3:0]led);
//变量
reg [17:0]cnt_5ms;//0~249,999表示5ms时间到了
reg stable_flag;
reg press_flag;
//保存led流水状态的寄存器
reg [3:0]shift_led = 4'b0001;//cnt_5ms毫秒计数器
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_5ms <= 1'b0;endelse if(cnt_5ms == 'd249_999)begincnt_5ms <= 1'b0;endelse if (key1 == 1'b0) begincnt_5ms <= cnt_5ms + 1'b1;endelse begincnt_5ms <= 1'b0;end
end
//stable_flag在key == 0稳定到5ms后,一直拉高
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginstable_flag <= 1'b0;endelse if (key1 == 1'b0 && cnt_5ms == 'd249_999) beginstable_flag <= 1'b1;endelse if(key1 == 1'b1)beginstable_flag <= 1'b0;end
end
//press_flag按下的一个周期的脉冲
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginpress_flag <= 1'b0;endelse if (stable_flag == 1'b0 && cnt_5ms == 'd249_999) beginpress_flag <= 1'b1;endelse beginpress_flag <= 1'b0;end
end
//按下按键shift_led移位
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginshift_led <= 4'b0001; endelse if (press_flag == 1'b1) beginshift_led <= {shift_led[2:0],shift_led[3]};//位置调换end
end
//led状态流水
assign led = shift_led;endmodule
第三部分、总结
这篇博客介绍了FPGA检测按键消抖的两种方式,通过检测按键来控制LED的移动。最简单的检测方式带来的问题就是偶尔会出现不灵敏的现象;实际的消抖方式能很好解决按键抖动的问题。
最后希望我的博客对你有帮助,有需要的小伙伴可以查看本专栏更多的往期文章👾👾👾
FPGA的学习之旅_大屁桃的博客-CSDN博客
相关文章:
【FPGA入门】第五篇、按键消抖
目录 第一部分、按键抖动现象 第二部分、消抖思路及代码 1、简单的按键消抖思路 2、实际按键消抖思路 3、实际按键消抖模块代码 第三部分、总结 第一部分、按键抖动现象 只要学习过单片机的都会知道,按键在按下去和松开的那个瞬间都存在抖动,在单片…...
【MySql】MySql的事务基础篇
文章目录 CURD加控制什么是事物为什么会出现事务事务的版本支持事务的提交方式 CURD加控制 模拟一个买票系统的场景如下所示: MySQL注定会被多个客户端进行访问的,这个是肯定的,存储的都是数据,数据在上层可能有一个线程在用&…...
docker创建Ubuntu,Ubuntu创建桌面环境,本机使用VNC连接
题目:docker创建Ubuntu,Ubuntu创建桌面环境,本机使用VNC连接 文章目录 前言docker创建基于Ubuntu:20.04的容器使用ssh连接容器容器安装桌面环境本机电脑使用VNC连接测试用python来创建的ui能否显示坑参考 前言 为什么我想要用ubuntu的桌面环…...
理解redis的多线程和IO多路复用
参考资料 https://blog.csdn.net/TZ845195485/article/details/119745735 Redis单线程和多线程问题的背景 Redis里程碑版本迭代 Redis的单线程 主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取(socket读&a…...
iOS 开发 | 自定义不规则 label
把我之前发布在简书的博客搬运过来。 目录 场景思路具体实现1. 自定义一个继承自UILabel的IrregularLabel2. 在初始化方法中进行相应初始化和设置3. 在layoutSubviews方法中进行路径的设置 最终效果箭头 label 场景 最近 App 改版,以下是截取的部分 UI 设计图&…...
client-go的Indexer三部曲之三:源码阅读
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 《client-go的Indexer三部曲》全部链接 基本功能性能测试源码阅读 本篇概览 本文是《client-go的Indexer三部曲》系列的终篇,主要任务是阅读和…...
收件地址解析成 省+市+区+详细地址的形式
项目中的源代码在我的GitHub:https://github.com/weitw/address-analyzer 先看效果: 如上图,address数输入的地址,Address对象是解析后的地址。可以支持逆推上一级,且支持地址白话解析。 一、项目介绍 1、解析规则 …...
数据结构与算法基础(青岛大学-王卓)(5)
叮叮咚咚,新一期来袭,我还在吃桃子,吃桃子,吃桃子。。。串和python的字符串差不多,数组和广义表像是python的list 文章目录 串(string) - 字符串概念及术语串的类型定义存储结构(同线性表)串的模式匹配算法…...
微信小程序开发入门学习01-TDesign模板解读
目录 1 使用模板创建小程序2 app.json3 页面布局总结 原来我们使用微信开发者工具,比较困难的是前端框架的选择上,官方也没有提供一套框架供我们使用,最近开发者工具已经提供了一套前端框架,后续我们开发的效率会因为使用模板提高…...
使用 Jetpack Compose 创建自定义的对话框(Dialog)
在 Jetpack Compose 中,对话框(Dialog)是一种常见的用户界面组件,用于展示重要的信息、确认操作或者收集用户输入。本篇博客将带你深入了解 Jetpack Compose 中的对话框,并展示如何创建自定义的对话框,以满…...
c++ auto学习笔记
一、auto的意义 在C11中赋予auto的意义是:在声明变量时,根据初始化表达式自动推断该变量的类型。声明函数时作为函数返回值的占位符(用在函数返回类型后置的情况)。 如 auto i 6; //auto推断为intauto func()->int //函数返…...
【随机种子初始化】一个神经网络模型初始化的大坑
1 问题起因和经过 半年前写了一个模型,取得了不错的效果(简称项目文件1),于是整理了一番代码,保存为了一个新的项目(简称项目文件2)。半年后的今天,我重新训练这个整理过的模型&…...
翻过那座山——Gitlab流水线任务疑难之编译有子模块的项目指南
📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不是…...
手机照片删除后如何恢复
在如今移动互联网和智能手机时代,拍摄照片已经成为了人们常见的一种生活方式,尤其是通过手机拍摄照片已经成为了许多人记录生活点滴、分享经验和表达情感等的必备工具。但是,随着手机照片量的激增,意外删除手机中珍贵照片的事件也…...
SpringBoot 线上服务假死,CPU 内存正常,什么情况?
背景 开发小伙伴都知道线上服务挂掉,基本都是因为cpu或者内存不足,出现GC频繁OOM之类的情况。本篇文章区别以上的情况给小伙伴们带来不一样的服务挂掉。 还记得哔哩哔哩713事故中那场诡计多端的0吗? 图片 对就是这个0,和本次事…...
kotlin从入门到精通之内置类型
基本类型 声明变量 val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量。 var(variable的简写)用来声明一个可变的变量,这种变量在初始…...
实战指南:使用Spring Boot实现消息的发送和接收
当涉及到消息发送和接收的场景时,可以使用Spring Boot和消息中间件RabbitMQ来实现。下面是一个简单的示例代码,展示了如何在Spring Boot应用程序中创建消息发送者和接收者,并发送和接收一条消息。 首先,你需要进行以下准备工作 确…...
常用的数据结构——栈
目录 1、入栈 2、出栈 3、获取栈顶的元素 4、从栈中查找元素 栈是一种常见的数据结构,栈的特点是后进先出,就像我们叠盘子,拿走上面的盘子才能拿到下一个。java中的栈java.util.Stack是通过java.util.Vector实现的,所以底层都…...
C++完成淄博烧烤节管理系统
背景: 这次我们结合今年淄博烧烤做一个餐厅管理系统,具体需求如下,我们选择的是餐饮商家信息管理 问题描述: 淄博烧烤今年大火,“进淄赶烤”是大家最想干的事情,淄博烧烤大火特火的原因,火的…...
我心中的TOP1编程语言
目录 一、评选最佳编程语言时需要考虑哪些标准 (一)易用性 (二)执行效率 (三)语言功能特性 (四)工具生态环境 (五)开发者社区 二、不同编程语言的优点…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
