08 按键消抖

news2024/10/7 13:17:34

在按键控制 LED中采用直接读取按键电平状态,然后根据电平状态控制LED。虽然直接读取按键电平状态然后执行相应处理程序的方法非常简单,但是这种方式可能存在误判问题,进而有可能导致程序功能异常,这是因为按键按下和松开时存在抖动问题,可能会使程序检测到错误的按下或松开操作。
本章节将以按键控制蜂鸣器为例讲解按键消抖算法的实现。

蜂鸣器简介

蜂鸣器按照结构原理不同可分为压电式蜂鸣器和电磁式蜂鸣器。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成;电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。压电式蜂鸣器是利用压电效应原理工作的,当对其施加交变电压时它会产生机械振动发声;电磁式蜂鸣器是接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
蜂鸣器按照驱动方式不同又可分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。
在这里插入图片描述

按键消抖原理

常见的按键均为机械弹性开关,当按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的过程中产生机械抖动,消除这种抖动的过程即称为按键消抖。
按键消抖可分为硬件消抖和软件消抖;硬件消抖主要使用 RS 触发器或电容等方法在硬件电路上实现消抖抖,一般在按键较少时使用。软件消抖的原理为按键按下或松开后,由处理器延时 5ms 至 20ms再对按键状态进行采样并判断,如下图所示软件消抖的原理图。
在这里插入图片描述

软件消抖

在按键被按下和按键被释放时都会产生抖动,而按键的抖动在数字电路中的体现就是不断变化的高低电平,由此可以绘制按键消抖模块输入信号的波形如下图所示。
在这里插入图片描述
抖动部分的 key 信号也有低电平的情况,但是因为机械抖动的原因很快又被拉高了,如果我们把每次 key 的低电平都检测到,相当于在极短的时间内按键被按下很多次,而不是我们实际操作的按下一次,所以我们需要把这段抖动的信号给滤除,只有按键值保持 20ms 及以上的稳定状态,我们才确认按键值有效,此时 key 值为高电平则按键被释放,key 值为低电平则按键被按下,所以消抖的过程就是滤除按键值保持时间小于 20ms 的值。

  • 如何滤除保持时间小于20ms的值:从 20ms 开始倒计时,如果 20ms 的倒计时还没有完成按键值就再次产生变化,此时需要从头开始 20ms 倒计时,前一次导致按键值变化的操作视为无效操作,将该次变化视为按键抖动消除;如果计完 20ms 按键状态一直没有改变,说明此次按键被按下或者被释放是有效操作。
  • 如何判断按键变化:可以给按键值打两拍(一般外部输入信号我们都使用打拍处理消除亚稳态),然后比较按键两次的打拍值,第一次打拍值与第二次打拍值一致说明按键值没有变化,第一次打拍值与第二次打拍值不一致说明按键值产生了变化。
    在这里插入图片描述

硬件设计

本次实验采用有源蜂鸣器,其原理图如下:
在这里插入图片描述
按键原理图参考按键控制 LED章节

程序功能

用 KEY0 按键来控制蜂鸣器发声,初始状态为蜂鸣器鸣叫,按下按键后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。

系统框图

系统分为两个模块,分别是按键消抖模块和蜂鸣器控制模块
在这里插入图片描述

编写代码

按键消抖代码

`timescale 1ns / 1ns	//仿真单位/仿真精度

module key_debounce #(
	parameter COUNT_WIDTH = 20,					//按键延时消抖计数器宽度
	parameter KEY_DELAY = 20'd100_0000,			//按键消抖延时
	parameter DEFAULT_LEVEL = 1'b1				//按键默认状态
)
(
	input sys_clk,								//时钟
	input sys_rst_n,							//复位
	input key_in,								//外部输入的按键值

	output reg key_filter						//消抖后的按键值
);

//延时消抖计数器,当按键按下时从KEY_DELAY开始递减计数,当其值为1时锁定按键状态
reg [COUNT_WIDTH-1:0] count;

//按键信号延迟一个时钟周期
//这里将key_debounce作为内部模块,只需要延迟一个时钟周期,用于捕获上升沿和下降沿
//例化时应将外部按键输入再延迟两个时钟周期,用于消除亚稳态(在FPGA中,对于外部输入信号均需要延迟两拍在使用,以消除亚稳态)
reg key_d1;

//按键信号延迟一个时钟周期
always @(posedge sys_clk) begin
	if(!sys_rst_n)
		key_d1 <= DEFAULT_LEVEL;
	else
		key_d1 <= key_in;
end

//检测按键跳变,当按键跳变时重置计数器为KEY_DELAY
always @(posedge sys_clk) begin
	if(!sys_rst_n)
		count <= 0;
	else if(key_d1 != key_in)
		count <= KEY_DELAY;			//按键跳变,重置计数器为KEY_DELAY
	else if(count > 0)
		count <= count - 1;			//递减计数,直到为0
	else
		count <= 0;
end

//在计数器值为1时(消抖延时结束)锁定按键状态
always @(posedge sys_clk) begin
	if(!sys_rst_n)
		key_filter <= DEFAULT_LEVEL;
	else if(count == 1)
		key_filter <= key_in;		//计数器递减为1时锁定按键状态
end

endmodule

按键消抖仿真激励代码

`timescale 1ns / 1ns	//仿真单位/仿真精度

module tb_key_debounce();

reg sys_clk;					//时钟
reg sys_rst_n;					//复位
reg key_in;						//输入按键
wire key_filter;				//消抖后的按键

initial begin
	sys_clk = 1'b0;
	sys_rst_n = 1'b0;
	key_in <= 1;
	#180
	sys_rst_n = 1'b1;
	#2000

	//按下过程
	key_in <= 0;
	#8
	key_in <= 1;
	#8
	key_in <= 0;
	#8
	key_in <= 1;
	#2
	key_in <= 0;
	#2
	key_in <= 1;
	#20
	key_in <= 0;

	//稳定保持过程
	#2000

	//释放过程
	key_in <= 1;
	#8
	key_in <= 0;
	#4
	key_in <= 1;
	#3
	key_in <= 0;
	#3
	key_in <= 1;
end

//产生时钟
always #10 sys_clk = ~sys_clk;

//例化按键消抖模块
key_debounce #(
	.COUNT_WIDTH(20),					//按键延时消抖计数器宽度
	.KEY_DELAY(25),						//按键消抖延时
	.DEFAULT_LEVEL(1'b1)				//按键默认状态
)
tb_key_debounce_inst(
	.sys_clk(sys_clk),					//时钟
	.sys_rst_n(sys_rst_n),				//复位
	.key_in(key_in),					//外部输入的按键值

	.key_filter(key_filter)				//消抖后的按键值
);

endmodule

蜂鸣器控制代码

`timescale 1ns / 1ns	//仿真单位/仿真精度

module key_beep #(
	parameter BEEP_DEFAULT_STATE = 1'b1,		//蜂鸣器默认状态
	parameter KEY_DEFAULT_LEVEL = 1'b1			//按键默认状态
)
(
	input sys_clk,								//时钟
	input sys_rst_n,							//复位
	input key_filter,							//消抖后的按键值

	output reg beep								//蜂鸣器
);

//消抖后的按键信号延迟一个时钟周期,用于检测边沿跳变
reg key_filter_d1;
//下降沿标志
wire key_negedge;

//捕获按键下降沿,当上一个时钟周期为高电平,当前时钟周期为低电平即为下降沿
assign key_negedge = key_filter_d1 & (~key_filter);

//消抖后的按键信号延迟一个时钟周期,用于检测边沿跳变
always @(posedge sys_clk) begin
	if(!sys_rst_n)
		key_filter_d1 <= KEY_DEFAULT_LEVEL;
	else
		key_filter_d1 <= key_filter;
end

//下降沿时刻翻转蜂鸣器状态
always @(posedge sys_clk) begin
	if(!sys_rst_n)
		beep <= BEEP_DEFAULT_STATE;
	else if(key_negedge == 1'b1)
		beep <= ~beep;
end

endmodule

蜂鸣器仿真激励代码

`timescale 1ns / 1ns	//仿真单位/仿真精度

module tb_key_beep();

reg sys_clk;					//时钟
reg sys_rst_n;					//复位
reg key_filter;					//消抖后的按键状态
wire beep;						//蜂鸣器

initial begin
	sys_clk = 1'b0;
	sys_rst_n = 1'b0;
	key_filter <= 1;
	#200
	sys_rst_n = 1'b1;
	#200

	//按下
	key_filter <= 0;
	#2000

	//释放
	key_filter <= 1;
	#2000

	//按下
	key_filter <= 0;
end

//产生时钟
always #10 sys_clk = ~sys_clk;

key_beep #(
	.BEEP_DEFAULT_STATE(1'b1),			//蜂鸣器默认状态
	.KEY_DEFAULT_LEVEL(1'b1)			//按键默认状态
)
tb_key_beep_inst (
	.sys_clk(sys_clk),					//时钟
	.sys_rst_n(sys_rst_n),				//复位
	.key_filter(key_filter),			//消抖后的按键值

	.beep(beep)							//蜂鸣器
);

endmodule

顶层代码

`timescale 1ns / 1ns

module top_key_beep #(
	parameter BEEP_DEFAULT_STATE = 1'b1,		//蜂鸣器默认状态
	parameter KEY_DEFAULT_LEVEL = 1'b1,			//按键默认状态
	parameter COUNT_WIDTH = 20,					//按键延时消抖计数器宽度
	parameter KEY_DELAY = 20'd100_0000			//按键消抖延时
)
(
	input sys_clk,								//时钟
	input sys_rst_n,							//复位
	input key_in,								//外部输入的按键值
	
	output beep									//蜂鸣器
);

//消抖后的按键
wire key_filter;

//外部输入按键延时两拍,用于消除亚稳态(在FPGA中,对于外部输入信号均需要延迟两拍在使用,以消除亚稳态)
reg key_in_d1;
reg key_in_d2;

//按键延迟两拍
always @(posedge sys_clk) begin
	if(!sys_rst_n) begin
		key_in_d1 <= KEY_DEFAULT_LEVEL;
		key_in_d2 <= KEY_DEFAULT_LEVEL;
	end
	else begin
		key_in_d1 <= key_in;
		key_in_d2 <= key_in_d1;
	end
end

//例化按键消抖模块
//例化按键消抖模块
key_debounce #(
	.COUNT_WIDTH(COUNT_WIDTH),				//按键延时消抖计数器宽度
	.KEY_DELAY(KEY_DELAY),					//按键消抖延时
	.KEY_DEFAULT_LEVEL(KEY_DEFAULT_LEVEL)	//按键默认状态
)
tb_key_debounce_inst(
	.sys_clk(sys_clk),						//时钟
	.sys_rst_n(sys_rst_n),					//复位
	.key_in(key_in_d2),						//外部输入的按键值

	.key_filter(key_filter)					//消抖后的按键值
);

//例化蜂鸣器控制模块
key_beep #(
	.BEEP_DEFAULT_STATE(BEEP_DEFAULT_STATE),	//蜂鸣器默认状态
	.KEY_DEFAULT_LEVEL(KEY_DEFAULT_LEVEL)	//按键默认状态
)
tb_key_beep_inst (
	.sys_clk(sys_clk),						//时钟
	.sys_rst_n(sys_rst_n),					//复位
	.key_filter(key_filter),				//消抖后的按键值

	.beep(beep)								//蜂鸣器
);

endmodule

系统仿真激励代码

`timescale 1ns / 1ns	//仿真单位/仿真精度

module tb_top_key_beep();

reg sys_clk;					//时钟
reg sys_rst_n;					//复位
reg key_in;						//输入按键
wire beep;						//蜂鸣器

initial begin
	sys_clk = 1'b0;
	sys_rst_n = 1'b0;
	key_in <= 1;
	#180
	sys_rst_n = 1'b1;
	
	#2000
	//按下过程
	key_in <= 0;
	#8
	key_in <= 1;
	#8
	key_in <= 0;
	#8
	key_in <= 1;
	#2
	key_in <= 0;
	#2
	key_in <= 1;
	#20
	key_in <= 0;
	//稳定保持过程
	#2000
	//释放过程
	key_in <= 1;
	#8
	key_in <= 0;
	#4
	key_in <= 1;
	#3
	key_in <= 0;
	#3
	key_in <= 1;

	//稳定保持过程
	#2000
	//按下过程
	key_in <= 0;
	#18
	key_in <= 1;
	#5
	key_in <= 0;
	#5
	key_in <= 1;
	#2
	key_in <= 0;
	#2
	key_in <= 1;
	#10
	key_in <= 0;
	//稳定保持过程
	#3000
	//释放过程
	key_in <= 1;
	#12
	key_in <= 0;
	#4
	key_in <= 1;
	#5
	key_in <= 0;
	#15
	key_in <= 1;
end

//产生时钟
always #10 sys_clk = ~sys_clk;

//例化按键消抖模块
top_key_beep #(
	.BEEP_DEFAULT_STATE(1'b1),			//蜂鸣器默认状态
	.KEY_DEFAULT_LEVEL(1'b1),			//按键默认状态
	.COUNT_WIDTH(20),					//按键延时消抖计数器宽度
	.KEY_DELAY(25)						//按键消抖延时
)
tb_top_key_beep_inst(
	.sys_clk(sys_clk),					//时钟
	.sys_rst_n(sys_rst_n),				//复位
	.key_in(key_in),					//外部输入的按键值

	.beep(beep)				//消抖后的按键值
);

endmodule

约束输入

管脚分配如下:
在这里插入图片描述

的 XDC 约束语句如下:

#时序约束
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
#IO 管脚约束
set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS15} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS15} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS15} [get_ports key_in]
set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS15} [get_ports beep]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1462530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WordPress后台自定义登录和管理页面插件Admin Customizer

WordPress默认的后台登录页面和管理员&#xff0c;很多站长都想去掉或修改一些自己不喜欢的功能&#xff0c;比如登录页和管理页的主题样式、后台左侧菜单栏的某些菜单、仪表盘的一些功能、后台页眉页脚某些小细节等等。这里boke112百科推荐这款可以让我们轻松自定义后台登录页…

定制学习风格、满足多元需求:Mr. Ranedeer 帮你打造 AI 家教 | 开源日报 No.178

JushBJJ/Mr.-Ranedeer-AI-Tutor Stars: 20.4k License: NOASSERTION Mr. Ranedeer 是一个个性化的 AI 辅导项目&#xff0c;主要功能包括使用 GPT-4 生成定制化提示&#xff0c;为用户提供个性化学习体验。其核心优势和特点包括&#xff1a; 调整知识深度以满足学习需求定制学…

Nginx 和 Apache 的比较

Nginx和Apache的对比 Nginx和Apache的优缺点比较 (1)nginx相对于apache的优点 ①轻量级&#xff0c;同样起web服务&#xff0c;比apache占用更少的内存及资源 ②抗并发&#xff0c;nginx处理请求是异步非阻塞的&#xff0c;而apache是阻塞型的在高并发下&#xff0c;nginx能保持…

9.vue学习笔记(组件传递Props校验+组件事件-组件传递数据+组件事件-配合“v-model”使用)

文章目录 1.组件传递Props校验1.1.默认值1.2.必选项1.3.注意事项&#xff1a;props 是只读的 2.组件事件-组件传递数据2.1.温馨提示&#xff1a;组件之间传递数据的方案 3.组件事件-配合“v-model”使用 1.组件传递Props校验 Vue组件可以更细致地声明对传入的 props 的校验要求…

基于JAVA+SpringBoot+Vue的前后端分离的电子商城

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在当今数字化时代&…

人工智能与机器学习行业新闻:颠覆企业运营方式的 AI 趋势

AI 推动业务转型 人工智能 (AI) 和机器学习已经在重塑各行各业的业务模式。AI 通过处理和整合数据支持战略决策的制定&#xff0c;其规模和速度远远超过了人脑。无疑&#xff0c;未来我们还将在 AI 领域取得许多重大突破&#xff0c;而拥有大量数据的行业可能会从人工智能革命…

C++ Primer 笔记(总结,摘要,概括)——第3章 字符串、向量和数组

目录 3.1 命名空间的using声明 3.2 标准库类型string 3.2.1 定义和初始化string对象 3.2.2 string对象上的操作 3.2.3 处理string对象中的字符 3.3 标准库类型vector 3.3.1 定义和初始化vector对象 3.3.2 向vector对象中添加元素 3.3.3 其他vector操作 3.4 迭代器介绍 3.4.…

”戏说“ 交换机 与 路由器

一般意义上说 老哥 这文章发表 的 东一榔头 西一锤 呵呵&#xff0c; 想到哪里就啰嗦到哪里 。 交换机&#xff1a; 其实就是在通道交换 路由器&#xff1a; 不光是在通道交换还要在协议上交换 下图你看懂了吗&#xff1f; &#xff08;仅仅数据交换-交换机 协议…

安卓开发:挑战每天发布一个封装类02--Wav录音封装类AudioChannel 1.0

简介 库名称&#xff1a;AudioChannel 版本:1.0 由于项目需求录音并base64编码存到服务器中&#xff0c;就顺手改装了一个别人的封装类 原封装类地址:Android AudioRecord音频录制wav文件输出 - 简书 (jianshu.com) 描述&#xff1a;此封装类基于AudioRecord实现wav的音频…

10.CSS3的calc函数

CSS3 的 calc 函数 经典真题 CSS 的计算属性知道吗&#xff1f; CSS3 中的 calc 函数 calc 是英文单词 calculate&#xff08;计算&#xff09;的缩写&#xff0c;是 CSS3 的一个新增的功能。 MDN 的解释为可以用在任何长度、数值、时间、角度、频率等处&#xff0c;语法如…

详细描述一下CrossOver2024版本的用途和作用?

当然可以。CrossOver 是一款由 CODE WEAVERS 公司开发的软件&#xff0c;其主要目标是在 macOS 和 Linux 系统上实现与 Windows 应用程序的兼容性。它不同于传统的虚拟机&#xff0c;如 Parallels 或 VMware&#xff0c;因为它并不在 macOS 上创建一个完整的 Windows 环境。相反…

【进程概念】

目录 什么是在计算机运行的程序这么多运行的程序计算机是如何管理的先描述再组织 什么是在计算机运行的程序 对于一个在磁盘可执行的二进制文件&#xff0c;也可叫做可执行程序。对于一个可执行的程序&#xff0c;程序有自己的代码和数据。一旦运行起来&#xff0c;就会在计算…

旅游分享系列之:福建旅游攻略

旅游分享系列之&#xff1a;福建旅游攻略 一、漳州1.福建土楼2.云水谣3.四菜一汤景点 二、厦门1.园林博览苑2.海上自行车道3.山海步道4.海滩5.闽南菜6.落日 三、泉州1.衙口沙滩2.海上日出3.珞珈寺4.海滩烟花 一、漳州 游玩2个景点&#xff1a;云水谣&#xff0c;四菜一汤可以住…

永恒之黑和永恒之蓝 漏洞解析及复现

充当攻击机的机器是kali&#xff0c;另外需要关闭防火墙策略。 永恒之黑&#xff08;CVE-2020-0796&#xff09; 靶机&#xff1a;windows 10的IP地址&#xff1a;192.168.200.30 原理&#xff1a;实现远程代码执行 注意&#xff1a; 这个脚本运行有时候会导致靶机蓝屏&am…

OpenAI Sora引领AI跳舞视频新浪潮:字节跳动发布创新舞蹈视频生成框架

OpenAI的Sora已经引起广泛关注&#xff0c;预计今年AI跳舞视频将在抖音平台上大放异彩。下面将为您详细介绍一款字节跳动发布的AI视频动画框架。 技术定位&#xff1a;这款框架采用先进的diffusion技术&#xff0c;专注于生成人类舞蹈视频。它不仅能够实现人体动作和表情的迁移…

(done) 什么是正定矩阵?Positive Definite Matrices

正定矩阵的定义&#xff1a;https://baike.baidu.com/item/%E6%AD%A3%E5%AE%9A%E7%9F%A9%E9%98%B5/11030459 正定矩阵的作用、验证视频&#xff1a;https://www.bilibili.com/video/BV1Ag411M76G/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c…

webpack配置杂记

1、热更新 安装webpack-dev-server : npm i webpack-dev-server -D webpack.config.js配置 module.exports {// 其他配置...,// 热更新配置devServer: {host: "localhost",port: 3000,}, } 2、入口entry&#xff1a;使用相对路径们也就是webpack程序运行的路径&am…

PNAS|多倍体物种极致突破

羊草&#xff08;Leymus chinensis&#xff09;是欧亚草原多年生优势草本植物&#xff0c;以其显著的适应性和饲料品质而闻名。尽管人们越来越认识到其生态和经济价值&#xff0c;但基因组序列的缺失及其遗传转化所面临的挑战限制了其在基础研究和野生植物改良方面的关键应用。…

transformer,视觉模型改进论文的讨论

1、efficientVIT efficientformer 模型 快48.9倍的新SAM&#xff01;清华&MIT&英伟达开源EfficientViT-SAM&#xff1a;精度不变&#xff0c;原地起飞 YOLOv8改进 | 2023主干篇 | EfficientViT替换Backbone&#xff08;高效的视觉变换网络&#xff09; - Snu77的文章 -…

《Python 语音转换简易速速上手小册》第5章 音频数据处理(2024 最新版)

文章目录 5.1 音频数据的基本处理5.1.1 基础知识5.1.2 主要案例&#xff1a;音频剪辑工具案例介绍案例 Demo案例分析 5.1.3 扩展案例 1&#xff1a;自动音量调节器案例介绍案例 Demo案例分析 5.1.4 扩展案例 2&#xff1a;语音识别预处理案例介绍案例 Demo案例分析 5.2 使用 Py…