verilog学习笔记- 11)按键控制蜂鸣器实验

news2025/1/17 14:05:31

简介:

蜂鸣器按照驱动方式主要分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。

                                             左边为有源蜂鸣器 右边为无源蜂鸣器

从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置,可以看出有绿色电路板的一种是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。相较于有源蜂鸣器,无源蜂鸣器成本更低,且发声频率可控。而有源蜂鸣器控制相对简单,由于内部自带震荡源,只要加上合适的直流电压即可发声。


实验任务:

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


硬件设计:

我们可以看到蜂鸣器受到三极管的控制,这里三极管充当开关的作用,它基极连接到 FPGA 的 IO 引脚当 FPGA 输出高电平时三极管导通,蜂鸣器鸣叫反之蜂鸣器停止鸣叫。

管脚分配如下表所示:

对应的 TCL 约束语句如下:

set_location_assignment PIN_E16 -to key
set_location_assignment PIN_D12 -to beep
set_location_assignment PIN_M2 -to sys_clk
set_location_assignment PIN_M1 -to sys_rst_n
set_instance_assignment -name CURRENT_STRENGTH_NEW 12MA -to beep

由于蜂鸣器需要的驱动电流较大,使用默认 8mA 的驱动电流有可能出现蜂鸣器发声较小的情况,解决方法是将蜂鸣器输出的驱动电流修改成 12mA 或者是 16mA,如下图所示: 


程序设计:

由实验任务可知,我们只需要在按键按下时改变蜂鸣器的鸣叫状态,但实际上在按键按下的过程中存在按键抖动的干扰,体现在数字电路中就是不断变化的高低电平,为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。因此本系统应至少包含按键消抖模块和蜂鸣器控制模块,按键控制蜂鸣器系统框图如图

查看软件生成的模块端口及信号连接图。首先在对工程进行编译,然后点击菜单栏的【Tools】→【NetList Viewers】→【RTL Viewer】

需要注意的是,必须已经执行过综合或编译之后,才能打开模块端口及信号连接图。打开之后,按下键盘的【Ctrl】键,滚动鼠标的滚轮可以对生连接图进行放大和缩小。模块端口及信号连接图可以比较清晰的查看各个模块端口信号的连接,同时双击模块,也可以进一步查看模块的原理图。

顶层模块有以下两个模块,按键消抖模块(key_debounce)蜂鸣器控制模块(beep_control)。顶层模块(top_key_beep)完成了对另外两个模块的例化。按键消抖模块,主要起到延时采样,防止按键抖动的干扰。蜂鸣器控制模块,通过对按键信号的识别,起到控制蜂鸣器鸣叫的作用。

按键消抖模块(key_debounce):对按键信号延时采样,将消抖后的按键信号和按键数据有效信号输出至 beep_control 模块。蜂鸣器控制模块(beep_control):根据输入的按键信号和按键数据有效信号,来控制蜂鸣器的鸣叫。

 

按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,消除这种抖动的过程即称为按键消抖。软件消抖的原理主要为按键按下或松开后延时 5ms—20ms 采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样,如图:

顶层模块代码如下:

1 module top_key_beep(
2 input sys_clk, //时钟信号 50Mhz
3 input sys_rst_n, //复位信号
4 
5 input key, //按键信号 
6 output beep //蜂鸣器控制信号
7 );
8 
9 //wire define
10 wire key_value;
11 wire key_flag;
12 
13 //*****************************************************
14 //** main code
15 //*****************************************************
16 
17 //例化按键消抖模块
18 key_debounce u_key_debounce(
19 .sys_clk (sys_clk),
20 .sys_rst_n (sys_rst_n),
21 
22 .key (key),
23 .key_flag (key_flag),
24 .key_value (key_value)
25 );
26 
27 //例化蜂鸣器控制模块
28 beep_control u_beep_control(
29 .sys_clk (sys_clk),
30 .sys_rst_n (sys_rst_n),
31 
32 .key_flag (key_flag), 
33 .key_value (key_value),
34 .beep (beep)
35 );
36 
37 endmodule

在顶层模块中例化了按键消抖模块和按键控制蜂鸣器模块。

按键消抖模块代码如下:

1 module key_debounce(
2 input sys_clk, //外部 50M 时钟
3 input sys_rst_n, //外部复位信号,低有效
4
5 input key, //外部按键输入
6 output reg key_flag, //按键数据有效信号
7 output reg key_value //按键消抖后的数据 
8 );
9 
10 //reg define 
11 reg [31:0] delay_cnt;
12 reg key_reg;
13 
14 //*****************************************************
15 //** main code
16 //*****************************************************
17 always @(posedge sys_clk or negedge sys_rst_n) begin
18 if (!sys_rst_n) begin
19 key_reg <= 1'b1;
20 delay_cnt <= 32'd0;
21 end
22 else begin
23 key_reg <= key;
24 if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
25 delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为 20ms)
26 else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始 20ms 倒计时
27 if(delay_cnt > 32'd0)
28 delay_cnt <= delay_cnt - 1'b1;
29 else
30 delay_cnt <= delay_cnt;
31 end 
32 end 
33 end
34 
35 always @(posedge sys_clk or negedge sys_rst_n) begin
36 if (!sys_rst_n) begin
37 key_flag <= 1'b0;
38 key_value <= 1'b1; 
39 end
40 else begin
41 if(delay_cnt == 32'd1) begin //当计数器递减到 1 时,说明按键稳定状态维持了 20ms
42 key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
43 key_value <= key; //并寄存此时按键的值
44 end
45 else begin
46 key_flag <= 1'b0;
47 key_value <= key_value;
48 end 
49 end 
50 end
51 
52 endmodule

程序中第 25 行不断检测按键状态,一旦发现按键状态发生改变,就给计数器 delay_cnt 赋初值 1000000。在按键状态不发生改变时,delay_cnt 递减从而实现倒计时的功能,在倒计时过程中,一旦检测到按键状态发生改变,则说明有抖动产生,此时重新给 delay_cnt 赋初值,并开始新一轮倒计时。在 50Mhz 时钟驱动下,delay_cnt 若能由 1000000 递减至 1,则说明按键状态保持稳定时间达 20ms,此时输出一个时钟周期的通知信号 key_flag,并将此时的按键数据寄存输出。

蜂鸣器控制模块的代码如下:

1 module beep_control(
2 //input
3 input sys_clk, //系统时钟
4 input sys_rst_n, //复位信号,低电平有效
5 
6 input key_flag, //按键有效信号
7 input key_value, //消抖后的按键信号 
8 output reg beep //蜂鸣器控制信号 
9 );
10 
11 //*****************************************************
12 //** main code
13 //*****************************************************
14 always @ (posedge sys_clk or negedge sys_rst_n) begin
15 if(!sys_rst_n)
16 beep <= 1'b1;
17 else if(key_flag && (~key_value)) //判断按键是否有效按下
18 beep <= ~beep; 
19 end
20 
21 endmodule

beep 初始状态为高电平,蜂鸣器鸣叫,当检测到按键有效信号 key_flag 为高电平,同时按键信号 key_value 为低电平时说明按键被有效按下,此时 beep 取反,蜂鸣器停止鸣叫。当按键再次按下时,beep再次取反,蜂鸣器重新开始鸣叫。

Test bench 模块代码如下:

1 `timescale 1 ns/ 1 ns
2 module tb_top_key_beep();
3 
4 //parameter define
5 parameter T = 20;
6 
7 //reg define
8 reg key;
9 reg sys_clk;
10 reg sys_rst_n;
11 reg key_value;
12 
13 // wire define 
14 wire beep;
15 
16 //*****************************************************
17 //** main code 
18 //*****************************************************
19 
20 //给信号初始值
21 initial begin
22 key <= 1'b1;
23 sys_clk <= 1'b0;
24 sys_rst_n <= 1'b0;
25 #20 sys_rst_n <= 1'b1; //在第 20ns 的时候复位信号信号拉高
26 #30 key <= 1'b0; //在第 50ns 的时候按下按键
27 #20 key <= 1'b1; //模拟抖动
28 #20 key <= 1'b0; //模拟抖动
29 #20 key <= 1'b1; //模拟抖动
30 #20 key <= 1'b0; //模拟抖动
31 #170 key <= 1'b1; //在第 300ns 的时候松开按键
32 #20 key <= 1'b0; //模拟抖动
33 #20 key <= 1'b1; //模拟抖动
34 #20 key <= 1'b0; //模拟抖动
35 #20 key <= 1'b1; //模拟抖动
36 #170 key <= 1'b0; //在第 550ns 的时候再次按下按键
37 #20 key <= 1'b1; //模拟抖动
38 #20 key <= 1'b0; //模拟抖动
39 #20 key <= 1'b1; //模拟抖动
40 #20 key <= 1'b0; //模拟抖动
41 #170 key <= 1'b1; //在第 800ns 的时候松开按键
42 #20 key <= 1'b0; //模拟抖动
43 #20 key <= 1'b1; //模拟抖动
44 #20 key <= 1'b0; //模拟抖动
45 #20 key <= 1'b1; //模拟抖动
46 end
47 
48 //50Mhz 的时钟,周期则为 1/50Mhz=20ns,所以每 10ns,电平取反一次 
49 always # (T/2) sys_clk <= ~sys_clk;
50 
51 //例化 key_beep 模块 
52 top_key_beep u1 (
53 .beep(beep),
54 .key(key),
55 .sys_clk(sys_clk),
56 .sys_rst_n(sys_rst_n)
57 ); 
58 
59 endmodule

仿真波形图如下:

测试代码中,为了方便仿真波形的查看,将按键消抖模块中的延时采样的延时时间改为四个时钟周期(将按键消抖模块中的第 26 行代码 delay_cnt <= 32'd1000000; 改为 delay_cnt <= 32'd4;)。tb_key_beep 模块中第 22 行到第 45 行为信号的激励。从图 10.4.5 可以看到,第 50ns 时,将 key 拉低,并在 50 至 130ns时模拟按键抖动,可见在按键抖动停止后的第 4 个时钟周期时,key_flag 出现一个时钟周期的高电平,同时beep 被拉低(蜂鸣器停止鸣叫);在第 300ns 时松开按键,随后模拟按键抖动,同理可知在抖动结束后的第四个时钟周期,key_flag 信号被拉高。读者可以仔细观察仿真波形结合代码深入理解,仔细体会 key_flag信号和 key 信号之间的关系。


下载验证:

功能正常 

 

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

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

相关文章

JAVA JVM学习

1.JVM介绍 越界检查肯定有用&#xff0c;防止覆盖别的地方的代码。 JVM来评价java在底层操作系统的差异。 2.程序计数器 我们java源代码会变成一条一条jvm指令。 在物理上实现程序计数器&#xff0c;是用一个寄存器。这样速度更快。 程序计数器不会内存溢出 2.1 线程私有 …

clickhouse整合ldap,无需重启

测试你的ladp服务ldapsearch -x-bdcexample,dccom -H ldap://ldap.forumsys.com应该输出类似以下的内容# extended LDIF # # LDAPv3 # base <dcexample,dccom> with scope subtree # filter: (objectclass*) # requesting: ALL # ​ # example.com dn: dcexample,dccom o…

【Premake】构建工程

Premake 一、什么是Premake&#xff1f; Premake 是一种命令工具&#xff0c;通过读取项目脚本&#xff0c;来生成各种开发环境的项目文件。 开源地址&#xff1a;https://github.com/premake/premake-core 下载地址&#xff1a;https://premake.github.io 实例地址&#xf…

揭秘HTTP/3优先级

编者按 / 相对于HTTP2&#xff0c;HTTP/3的优先级更加简单&#xff0c;浏览器厂商更可能实现统一的优先级策略。本文来自老朋友Robin Marx&#xff0c;已获授权转载&#xff0c;感谢刘连响对本文的技术审校。翻译 / 核子可乐技术审校 / 刘连响原文链接 / https://calendar.per…

【MySQL数据库入门】:面试中常遇到的 ‘ 数据类型 ’

文章目录数据类型1.数据类型分类2.数值类型2.1 tinyint类型2.2 bit类型2.3 小数类型2.3.1 float2.3.2 decimal3.字符串类型3.1 char3.2 varchar3.3 char和varchar比较4.日期和时间类型5.enum和set数据类型 1.数据类型分类 2.数值类型 2.1 tinyint类型 create table tt1(num t…

解决unable to find valid certification path to requested target

问题描述 最近java程序去调用远程服务器接口时报错了&#xff1a; I/O error on POST request for “https://XXX.xyz/create”: sun.secu rity.validator.ValidatorException: PKIX path building failed: sun.security.provi der.certpath.SunCertPathBuilderException: una…

终极 3D 图形工具包:Ab3d.PowerToys 10.2.X Crack

Ab3d.PowerToys改进了 Ab3d.Utilities.Triangulator 通过添加对带孔的多个多边形进行三角剖分的支持&#xff08;之前只能对没有任何孔的单个多边形进行三角剖分&#xff09;。这可用于从文本创建 3D 网格。 Ab3d.Utilities.PolygonAnalyzer 现在是一个公共类&#xff0c;可用于…

【学习笔记】【Pytorch】五、DataLoader的使用

【学习笔记】【Pytorch】五、DataLoader的使用学习地址主要内容一、DataLoader模块介绍二、DataLoader类的使用1.使用说明2.代码实现好的文章学习地址 PyTorch深度学习快速入门教程【小土堆】. 主要内容 一、DataLoader模块介绍 介绍&#xff1a;分配数据集。 二、DataLoade…

EMS运行数据处理-pandas降采样、合并多表

文章目录read_csv读取出错。因为多余异常列数据解决方法pd.to_datetime(df[time_key])但time_key出现不能转换的序列解决方法pandas 提取时间序列年、月、日方法一:pandas.Series.dt.month() 方法提取月份方法二:strftime() 方法提取年、月、日方法三:pandas.DatetimeIndex.mon…

【阶段三】Python机器学习20篇:机器学习项目实战:AdaBoost回归模型

本篇的思维导图: 项目实战(AdaBoost回归模型) 项目背景 本项目应用AdaBoost回归算法进行项目实战,整体流程包括数据收集、数据预处理、探索性数据分析、特征工程、模型构建及优化、模型评估。 数据收集 本次建模数据来源于网络,数据项统计如下: 编号

问题:在 ArcMap 中编辑数据时,无法使用捕捉功能

问题&#xff1a;在 ArcMap 中编辑数据时&#xff0c;无法使用捕捉功能 说明 编辑时&#xff0c;捕捉命令无法按预期运行。无法连接要素&#xff0c;因为指针没有捕捉到地图文档中的边缘和折点。 原因 此问题可能由以下原因之一引起&#xff1a; 捕捉选项已禁用 当前编辑会…

foxmail 发送邮件到 Poste邮件服务的端口设置

Poste服务器 发件端口设置的是 587 端口&#xff0c;没有开通 465 端口。 在foxmail用户账号设置中&#xff0c;发送端口不使用 ssl 默认是 25&#xff0c;使用 ssl 使用的是 465 端口。 一、无效设置的3种情况 1、在发送邮件的时候&#xff0c;不使用 ssl&#xff0c; 端口…

某固态放大器输出单次微波脉冲信号测量方案

某固态放大器输出单次微波脉冲信号测量方案摘要测量指标范围频率测量测量方案仪器选择衰减器混频器信号发生器频谱分析仪可行性分析脉宽和功率测量方案一方案二仪器选择检波器衰减器示波器可行性分析摘要 某固态放大器输出单次微波脉冲信号测量&#xff0c;需测量单个脉冲的频…

Java锁之ReentrantLock(源码详解)

视频地址Java学习文档 ReentrantLock 这个Java中重要的锁&#xff0c;我想可能很多人只是听过&#xff0c;并没有使用过&#xff0c;我在看RocketMQ客户端源码的时候发现大量的使用了这个ReentrantLock&#xff0c;从而引起了我的兴趣&#xff0c;下面我们一起从源码的角度来学…

JDK7时间相关类超详细总结(含多个实例)

JDK7时间相关类一、概述二、Date类1.构造函数2.常用函数1️⃣格式2️⃣实例三、 SimpleDateFormat类1.概述2.构造方法3.常用方法1️⃣格式2️⃣实例四、Calendar类1.概述2.使用方法3.常用方法4.实例五、结语一、概述 本文主要介绍JDK7中的时间相关类 二、Date类 1.构造函数 …

JSP SSM评估文档管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSPSSM评估文档管理系统 是一套完善的系统源码&#xff0c;对理解JSP java SrpingMVC mybiats 框架 MVC编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档 &#xff0c;系统主要采用B/S模式开发。 研究的基本…

从零备战蓝桥杯——动态规划(子序列篇)

文章目录啥也别说了直接进入正题&#xff1a;不连续子序列问题300. 最长递增子序列1143. 最长公共子序列1035. 不相交的线连续子序列问题674. 最长连续递增序列718. 最长重复子数组53. 最大子数组和编辑距离问题392. 判断子序列困难题&#xff1a;115. 不同的子序列583. 两个字…

使用 ORM 方式查询 Mongodb 里的数据,再也不用记 Mongodb 的语法(ORM Bee)

使用ORM方式查询Mongodb里的数据,再也不用记Mongodb的语法&#xff08;ORM Bee) Mongodb的语法可读性差&#xff0c;要写复杂查询&#xff0c;要求技术能力高&#xff1b;Java驱动&#xff0c;还要使用另一种语法&#xff1b;学习成本太高了。 可以使用ORM方式&#xff0c;轻松…

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 (四)移位运算与乘法

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 &#xff08;四&#xff09;移位运算与乘法 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN博客 &#x1f9e8;未经作者允许&#xff0c;禁止转载 &#x1f511;系列专栏&#xff1a;牛客Ve…

C++:函数对象:Lambda:Lambda详解(三)

1&#xff1a;定义 lambda表达式就是一个函数&#xff08;匿名函数&#xff09;&#xff0c;也就是一个没有函数名的函数。为什么不需要函数名了&#xff1f; 因为我们直接&#xff08;一次性的&#xff09;用它&#xff0c;不需要其他地方调用它。lambda表达式也叫闭包&#x…