基于ZYNQ-7000系列的FPGA学习笔记7——按键控制蜂鸣器(模块化编写)

基于ZYNQ-7000系列的FPGA学习笔记7——按键控制蜂鸣器(模块化编写)

  • 1. 实验要求
  • 2. 功能分析
  • 3. 模块设计
  • 4. 波形图
    • 4.1 按键消抖模块
    • 4.2 按键控制蜂鸣器模块
  • 5.代码编写
    • 5.1 rtl代码
    • 5.2 测试代码
  • 6. 代码仿真
  • 7. 添加约束文件并分析综合

在上期的内容中,我们通过模拟按键控制led,这一期学习的内容是:按键控制蜂鸣器

1. 实验要求

在这里插入图片描述

通过按键控制领航者底板上的蜂鸣器,要求如下:

  • 初始状态蜂鸣器响起
  • 按下一次按键,改变一次按键的状态
  • 需要对输入的按键信号进行消抖,消抖的时间为20ms
  • 按下复位按键,蜂鸣器恢复默认状态

2. 功能分析

首先我们需要看一下蜂鸣器相关的原理图:
在这里插入图片描述
可以看到蜂鸣器通过一个8050的三极管驱动,连接到FPGA芯片的Bank35 ,引脚为L23。需要让蜂鸣器叫的话,给高电平就可以。

关于按键部分的内容,可以参考本系列的前面几篇,这里不做介绍。

3. 模块设计

在这里插入图片描述
由于本次的实验内容中需要我们设计多个模块,所以我设计了上述的功能框图,可以分为下面三个子模块:

  1. 按键消抖模块:作用是对输入的按键信号进行一个20ms的消抖
  2. 按键控制蜂鸣器模块:作用是对消抖之后的数据边沿采集,通过采集到的信号沿控制蜂鸣器
  3. 按键控制蜂鸣器顶层模块:分别例化了按键消抖模块和按键控制蜂鸣器模块,完成整个实验要求。

4. 波形图

4.1 按键消抖模块

在这里插入图片描述
为了防止按键的输入信号在采集的过程中出现亚稳态,我这里进行了打两拍的操作。同时为了实现按键的消抖,我也定义了一个cnt,用来记录电平保持稳定的时间,当这个时间大于20ms时才任务是按键按下了,这样就实现了按键的消抖

4.2 按键控制蜂鸣器模块

在这里插入图片描述
由于按键控制蜂鸣器模块的按键输入是消抖的后的按键信息(已经打过两拍了),所以我这里只打一个拍,用来计算是否产生了下降沿,从而判断按键是否按下

【注】:由于顶层按键控制蜂鸣器只是例化了上述两个模块,因此这里就不绘制波形图了,之间看后面仿真结果就可以。

5.代码编写

5.1 rtl代码

  1. 按键消抖模块:key_filter.v
//模块的端口定义
module key_filter(input  sys_clk,input  sys_rst_n,input  key,output reg key_filter);reg key_d0;     // 打两拍的变量定义
reg key_d1;reg change;     //这个是用来确定的是否有电平变化的,为1表示有电平变化,为0表示没有//定义计数的变量,用来判断电平是否持续了20ms
reg [19:0] cnt;
//CNT_MAX用来确定按键消抖的时间, CNT_MAX =  20ms /  (1s / 50Mhz ) =  1000_000 ,其中20ms是消抖的时间,50Mhz是系统时钟频率
parameter CNT_MAX = 20'd1000_000;   //对输入的key信号,打两拍操作
always @(posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)   begin   //初始状态下,d0和d1都是高电平,和按键未按下时一致key_d0 <= 1'b1;key_d1 <= 1'b1;endelse begin       //运行状态下,开始打拍key_d0 <= key;key_d1 <= key_d0;end
end//检测是否有电平变化,如果有的话,把change置1,否则保持0
always @(posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)change <= 1'b0;else begin if ( key_d0 != key_d1 )change <= 1'b1;else change <= 1'b0;end
end//如果change为1,说明电平有变化,重新开始计数,否则cnt减一,减到0停止
always @(posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0) cnt <= 20'd0;else beginif(change == 1'b1)cnt <= CNT_MAX;else beginif(cnt >20'd0)cnt <= cnt - 20'd1;elsecnt <= 20'd0;endend
end//如果cnt顺利的减到了1,说明电平保持了20ms,可以输出
always @(posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0) key_filter <= 1'b1;else beginif(cnt == 20'd1)key_filter <= key_d1; elsekey_filter <= key_filter;end
endendmodule

大致流程如下:首先对输入的按键信号大量拍,判断是否按键的电平是否变化,如果变化就把cnt置为最大值,如果没有变化,cnt每个系统时钟减1,直到减到1,表示抖动结束,输出当前的按键信息,否则输出上一次的按键信息。

  1. 按键控制蜂鸣器模块:key_beep.v
    module key_beep(input sys_clk,input sys_rst_n,input key_filter, //消抖后按键值output reg beep //蜂鸣器
);reg key_filter_d0; //将消抖后的按键值延迟一个时钟周期wire neg_key_filter; //按键有效脉信号//捕获按键端口的下降沿,得到一个时钟周期的脉冲信号
assign neg_key_filter = (~key_filter) & key_filter_d0;//对按键端口的数据延迟一个时钟周期
always @ (posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)key_filter_d0 <= 1'b1;elsekey_filter_d0 <= key_filter;
end//每次按键按下时,就翻转蜂鸣器的状态
always @ (posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)beep <= 1'b1;else if(neg_key_filter) //有效的一次按键被按下beep <= ~beep;elsebeep <= beep;
end
endmodule

大致流程如下:对消抖之后的按键输入打一个拍,用来判断是否产生下降沿,如果产生下降沿,说明有按键按下,改变一次蜂鸣器的状态。

  1. 顶层按键控制蜂鸣器模块:top_key_beep.v
module top_key_beep(input sys_clk , //系统时钟input sys_rst_n , //系统复位,低电平有效input key , //按键output beep //蜂鸣器
);parameter CNT_MAX = 20'd100_0000; //消抖时间 20mswire key_filter ; //按键消抖后的值//例化按键消抖模块
key_filter #( .CNT_MAX (CNT_MAX) ) u_key_filter(.sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.key            (key),.key_filter     (key_filter)
);//例化蜂鸣器控制模块
key_beep u_key_beep (.sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.key_filter     (key_filter),.beep           (beep)
);
endmodule

5.2 测试代码

`timescale 1ns/1ns  //仿真单位/精度module tb_top_key_beep();parameter CLK_PERIOD = 20;      //时钟周期20ms
parameter CNT_MAX = 20'd10;     //消抖时间 200ns//定义输入和输出的变量
reg     sys_clk;
reg     sys_rst_n;
reg     key;wire beep;//这里用来产生按键按下的信息
initial beginsys_clk <=1'b0;sys_rst_n <=1'b0;key <= 1'b0;    #190sys_rst_n <=1'b1;key <= 1'b1;    //抖动开始#20key <= 1'b0;#30key <= 1'b1;#40key <= 1'b0;#30key <= 1'b1;#40key <= 1'b0;    //抖动结束#300key <= 1'b1;    //松开按键,抖动开始#40key <= 1'b0;#30key <= 1'b1;    //抖动结束   end//产生时钟
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;//例化测试设计
top_key_beep  #(.CNT_MAX (CNT_MAX) )  u_top_key_beep(.sys_clk    (sys_clk),.sys_rst_n  (sys_rst_n),.key        (key),.beep       (beep)
);endmodule

【注】:这里的测试代码只针对顶层文件,底层的模块测试代码,暂时不需要。

6. 代码仿真

如下是仿真的结果:
在这里插入图片描述
可以看到仿真的结果和我们话的波形图是基本一致的,并且小于200ns的抖动都已经被滤除了,很不错。

7. 添加约束文件并分析综合

首先我们添加对应的约束文件

#时序约束
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
#IO 管脚约束
set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports beep]
set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports key]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

完成之后,分析综合,得到如下结果:

  1. 顶层模块:
    在这里插入图片描述
    可以看到里面分别由两个子模块连接,下面是子模块的内部结构。

  2. 按键消抖模块

在这里插入图片描述

  1. 按键控制蜂鸣器模块
    在这里插入图片描述
    下一步就是生成比特流文件,然后上板调试了,这里结果我就还是不展示了。

以上就是本期的所有内容,创造不易,点个关注再走呗。

在这里插入图片描述

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

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

相关文章

k8s,声明式API对象理解

命令式API 比如&#xff1a; 先kubectl create&#xff0c;再replace的操作&#xff0c;我们称为命令式配置文件操作 kubectl replace的执行过程&#xff0c;是使用新的YAML文件中的API对象&#xff0c;替换原有的API对象&#xff1b;而kubectl apply&#xff0c;则是执行了一…

了解Xcode在iOS开发中的作用和功能有哪些

Xcode是什么&#xff1f;它在iOS开发中的作用和功能有哪些&#xff1f; 一、Xcode是什么&#xff1f; Xcode是苹果公司针对macOS平台开发的一款集成开发环境&#xff08;Integrated Development Environment&#xff0c;简称IDE&#xff09;。它主要用于开发iOS、iPadOS、mac…

【金猿CIO展】复旦大学附属中山医院计算机网络中心副主任张俊钦:推进数据安全风险评估,防范化解数据安全风险,筑牢医疗数据安全防线...

‍ 张俊钦 本文由复旦大学附属中山医院计算机网络中心副主任张俊钦撰写并投递参与“数据猿年度金猿策划活动——2024大数据产业年度优秀CIO榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 数据要素时代&#xff0c;医疗数据已成为医院运营与决策的重要基石…

案例研究|HYPER PaaS低代码工具携手DataEase嵌入式版,服务工业制造企业数智化转型

杭州星瀚智磐科技有限公司&#xff08;以下简称为“星瀚智磐”&#xff09;成立于2021年&#xff0c;是一家专注于低代码平台研发的高科技企业。星瀚智磐的核心产品HYPER PaaS低代码工具主要为制造业用户提供数字化解决方案。HYPER PaaS基于低代码平台简单的拖拉拽操作&#xf…

Python 队列的使用:掌握先进先出的数据结构

Python 队列的使用&#xff1a;掌握先进先出的数据结构 队列是一种先进先出&#xff08;FIFO&#xff09;的数据结构&#xff0c;它在多种编程场景中都非常有用&#xff0c;比如任务调度、事件处理等。在Python中&#xff0c;我们可以通过标准库中的queue模块来实现队列。本文…

2-2-18-13 QNX系统架构之原生网络(Qnet)

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…

Ubuntu系统上mysql服务部署

前段时间搞了一个mysql服务端的部署&#xff0c;在Ubuntu系统上&#xff0c;中间也踩了许多坑&#xff0c;特此记录下。 下载 官网&#xff1a;MySQL :: MySQL Community Downloads 这个里面有不同系统的安装包&#xff0c;根据自己的系统选择&#xff0c;我选了 MySQL Com…

gitlab配置调试minio

官方文档 rails console 调试 查看配置Settings.uploads.object_store加载minio clientrequire fog/awsfog_connection Fog::Storage.new(provider: AWS,aws_access_key_id: 你的MINIO_ACCESS_KEY,aws_secret_access_key: 你的MINIO_SECRET_KEY,region: <S3 region>,e…

IIC相关介绍及oled实验(二)

//模块&#xff1a;OLED显示屏 1. 0.96寸OLED屏幕介绍 0.96 寸 4P OLED 屏幕模块是一种显示屏模块&#xff0c;它包括一个 0.96 英寸的 OLED 显示屏和四个引脚。这种 OLED 屏幕模块通常用于嵌入式系统和小型电子设备中&#xff0c;可以显示文本、图像和其他类型的信息。由于其…

window下docker使用一些多媒体应用

首先下载docker之类的就不讲了&#xff0c; 科学下载了三个内容。 1.视频多媒体&#xff1a; 在新建的文件夹创建三个子文件夹&#xff08;cache&#xff0c;config&#xff0c;media&#xff09;,然后启动命令即可。 启动命令&#xff1a; docker run -d --nameJellyfin …

【工具变量】上市公司企业所在地城市等级直辖市、副省级城市、省会城市 计划单列市(2005-2022年)

一、包含指标&#xff1a; 股票代码 股票代码 股票简称 年份 所属城市 直辖市&#xff1a;企业所在地是否属于直辖市。1是&#xff0c;0否。 副省级城市&#xff1a;企业所在地是否属于副省级城市。1是&#xff0c;0否。 省会城市&a…

计算机视觉——相机标定(Camera Calibration)

文章目录 1. 简介2. 原理3. 相机模型3.1 四大坐标系3.2 坐标系间的转换关系3.2.1 世界坐标系到相机坐标系3.2.2 相机坐标系到图像坐标系3.2.3 像素坐标系转换为图像坐标系3.2.4 世界坐标转换为像素坐标 3.3 畸变3.3.1 畸变类型3.3.1.1 径向畸变&#xff08;Radial Distortion&a…

C++面试突破---C/C++基础

1.C特点 1. C在C语言基础上引入了面对对象的机制&#xff0c;同时也兼容C语言。 2. C有三大特性&#xff08;1&#xff09;封装。&#xff08;2&#xff09;继承。&#xff08;3&#xff09;多态&#xff1b; 3. C语言编写出的程序结构清晰、易于扩充&#xff0c;程序可读性好。…

LeetCode136.只出现一次的数字

题目 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xff1a; 输入&am…

Golang内存模型总结1(mspan、mcache、mcentral、mheap)

1.内存模型 1.1 操作系统存储模型 从上到下分别是寄存器、高速缓存、内存、磁盘&#xff0c;其中越往上速度越快&#xff0c;空间越小&#xff0c;价格越高。 关键词是多级模型和动态切换 1.2 虚拟内存与物理内存 虚拟内存是一种内存管理技术&#xff0c;允许计算机使用比…

Qt Quick开发基础+实战(持续更新中…)

最近更新日期&#xff1a;2024/12/4 一、Qt Quick简介 写在前面&#xff1a; 本篇文章虽然只是作为我的学习笔记&#xff0c;但也作为我日后复习之用&#xff0c;所以会认真并详细记录&#xff0c;但会分重点。 1.3 新建Qt Quick Application工程 这节主要讲2个知识点&#x…

elementui table滚动分页加载

文章目录 概要 简化的实现示例&#xff1a; 小结 概要 在使用 Element UI 的 Table 组件时&#xff0c;如果需要实现滚动分页加载的功能&#xff0c;可以通过监听 Table 的滚动事件来动态加载更多数据。 简化的实现示例&#xff1a; <template><el-table ref"…

使用GDI对象绘制UI时需要注意的若干细节问题总结

目录 1、一个bitmap不能同时被选进两个dc中 2、CreateCompatibleDC和CreateCompatibleBitmap要使用同一个dc作为参数 3、不能删除已经被选入DC中的GDI对象 4、使用完的GDI对象&#xff0c;要将之释放掉&#xff0c;否则会导致GDI对象泄漏 5、CreateCompatibleBitmap返回错…

基于频谱处理的音频分离方法

基于频谱处理的音频分离方法 在音频处理领域&#xff0c;音频分离是一个重要的任务&#xff0c;尤其是在语音识别、音乐制作和通信等应用中。音频分离的目标是从混合信号中提取出单独的音频源。通过频谱处理进行音频分离是一种有效的方法&#xff0c;本文将介绍其基本原理、公…

Scala的模式匹配(8)

package hfdobject Test35_1 { //需求:现在有一个数组Array(1,2,3,4)。我希望能定义三个变量&#xff0c;他们的值分别是数组中的第1&#xff0c;2&#xff0c;3个元素的值 def main(args: Array[String]): Unit {val arr Array(1,2,3,4,5)//第一个元素的值&#xff1a;arr(0…