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

news2025/1/14 13:19:31

基于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) begin
    if(sys_rst_n == 1'b0)   begin   //初始状态下,d0和d1都是高电平,和按键未按下时一致
    key_d0 <= 1'b1;
    key_d1 <= 1'b1;
    end
    else begin       //运行状态下,开始打拍
    key_d0 <= key;
    key_d1 <= key_d0;
    end
end

//检测是否有电平变化,如果有的话,把change置1,否则保持0
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(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) begin
    if(sys_rst_n == 1'b0) 
    cnt <= 20'd0;
    else begin
        if(change == 1'b1)
        cnt <= CNT_MAX;
        else begin
            if(cnt >20'd0)
            cnt <= cnt - 20'd1;
            else
            cnt <= 20'd0;
        end
     end
end

//如果cnt顺利的减到了1,说明电平保持了20ms,可以输出
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(sys_rst_n == 1'b0) 
    key_filter <= 1'b1;
    else begin
        if(cnt == 20'd1)
        key_filter <= key_d1; 
        else
        key_filter <= key_filter;
    end
end

endmodule

大致流程如下:首先对输入的按键信号大量拍,判断是否按键的电平是否变化,如果变化就把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) begin
    if(!sys_rst_n)
    key_filter_d0 <= 1'b1;
    else
    key_filter_d0 <= key_filter;
end

//每次按键按下时,就翻转蜂鸣器的状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
    beep <= 1'b1;
    else if(neg_key_filter) //有效的一次按键被按下
    beep <= ~beep;
    else
    beep <= 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; //消抖时间 20ms

wire 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 begin
    sys_clk <=1'b0;
    sys_rst_n <=1'b0;
    key <= 1'b0;    
    #190
    sys_rst_n <=1'b1;
    key <= 1'b1;    //抖动开始
    #20
    key <= 1'b0;
    #30
    key <= 1'b1;
    #40
    key <= 1'b0;
    #30
    key <= 1'b1;
    #40
    key <= 1'b0;    //抖动结束
    #300
    key <= 1'b1;    //松开按键,抖动开始
    #40
    key <= 1'b0;
    #30
    key <= 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.coloradmin.cn/o/2253850.html

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

相关文章

Android 分词的两种方式

前言&#xff1a; 本文分别介绍了原生和三方(Jieba)两种分词方式的使用和注意事项 1、安卓原生BreakIterator分词 比较简单&#xff0c;但是效果不太行 /*** 功能&#xff1a;原生分词* 参数&#xff1a;text&#xff1a;需要分词的语句* 返回值&#xff1a;return&#xf…

python之Django连接数据库

文章目录 连接Mysql数据库安装Mysql驱动配置数据库信息明确连接驱动定义模型在模型下的models.py中定义表对象在settings.py 中找到INSTALLED_APPS添加创建的模型 测试testdb.py中写增删改查操作urls.py添加请求路径启动项目进行测试 连接Mysql数据库 安装Mysql驱动 pip inst…

JavaWeb学习(1)(同步或异步请求、依赖jQuery简单实现Ajax技术)

目录 一、Web的基本流程与页面局部刷新。 &#xff08;1&#xff09;web开发时基本流程。 &#xff08;2&#xff09;页面的"全局刷新"与"局部刷新"。 二、Ajax技术。 &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;基本特点。 1、与服务…

spark sql 环境安装,java 默认路径和 安装配置!

yum安装java 查看默认路径 update-alternatives --config java # Java 环境变量 export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jreexport PATH$JAVA_HOME/bin:$PATH# Spark 环境变量 export SPARK_HOME/home/vagrant/soft/sparkexport PATH…

网络层总结

网络层任务&#xff1a; 分组 从源主机 经多个网络/多段链路 传输到目的主机 两种重要的功能&#xff1a; 分组转发、 路由选择 网络层向其上层提供的两种服务 —— 面向连接的虚电路服务、无连接的数据报服务 面向连接的虚电路服务&#xff1a; 可靠通…

python学习笔记15 python中的类

上一篇我们介绍了python中的库 &#xff0c;学习了一些常见的内置库。详细内容可点击–>python学习笔记14 python中的库&#xff0c;常见的内置库&#xff08;random、hashlib、json、时间、os&#xff09; 这一篇我们来看一下python中的类 创建一个类 class 类的名称():de…

MySQL数据集成到广东省追溯平台的销售信息同步方案

销售信息同步--外购上报流程2&#xff1a;MySQL数据集成到广东省特殊食品电子追溯平台 在现代数据驱动的业务环境中&#xff0c;确保销售信息的准确性和及时性至关重要。本文将分享一个具体的技术案例&#xff0c;展示如何通过轻易云数据集成平台&#xff0c;将MySQL中的销售信…

【推荐算法】推荐系统的评估

这篇文章是笔者阅读《深度学习推荐系统》第五章推荐系统的评估的学习笔记&#xff0c;在原文的基础上增加了自己的理解以及内容的补充&#xff0c;在未来的日子里会不断完善这篇文章的相关工作。 文章目录 离线评估划分数据集方法客观评价指标P-R曲线ROC/AUCmAPNDCG A/B 测试分…

移植NIOS10.1工程,NIOS10.1路径修改

移植NIOS10.1工程&#xff0c;NIOS10.1路径修改 因工程的需要&#xff0c;使用的NIOS10.1&#xff0c;比较老&#xff0c;这个版本的路径是使用的绝对路径&#xff0c;导致移植工程市回报路径的错误&#xff0c;在13.1之后改为了相对路径&#xff0c;不存在这个问题。 需要修…

WPF+LibVLC开发播放器-LibVLC播放控制

接上一篇&#xff1a; LibVLC在C#中的使用 实现LibVLC播放器播放控制 界面 界面上添加一个Button按钮用于控制播放 <ButtonGrid.Row"1"Width"88"Height"24"Margin"10,0,0,0"HorizontalAlignment"Left"VerticalAlignme…

iOS与Windows间传文件

想用数据线从 windows 手提电脑传文件入 iPhone&#xff0c;有点迂回。 参考 [1]&#xff0c;要在 windows 装 Apple Devices。装完、打开、插线之后会检测到手机&#xff0c;界面&#xff1a; 点左侧栏「文件」&#xff0c;不是就直接可以传&#xff0c;而是要通过某个应用传…

两个畸变矩阵相乘后还是一个2*2的矩阵,有四个畸变元素。1、畸变矩阵吸收了法拉第矩阵。2、畸变矩阵也给法拉第旋转角带来模糊(求解有多种可能)

角度一&#xff1b;恢复畸变的时候也把法拉第旋转恢复了 角度二&#xff1a;求解法拉第旋转角的时候 前面乘的复系数的不同也会带来法拉第旋转角和畸变的不同解 注意&#xff1a;无论多少个畸变矩阵相乘&#xff0c;结果都是2*2的矩阵&#xff0c;也就是畸变参数可以减少…

【Linux】基础IO_文件系统IO_“一切皆文件”_缓冲区

目录 1. 理解"⽂件" 1-1 狭义理解 1-2 ⼴义理解 1-3 ⽂件操作的归类认知 1-4 系统⻆度 访问文件&#xff0c;需要先打开文件&#xff01;那么是由谁打开文件&#xff1f;&#xff1f;&#xff1f; 操作系统要不要把被打开的文件管理起来&#xff1f; 2. 回顾…

【LeetCode】498.对角线遍历

无论何时何地&#xff0c;我都认为对于一道编程题&#xff0c;思考解法的时间用于是实际动手解决问题的2倍&#xff01;如果敲键盘编码需要5min&#xff0c;那么思考解法的过程至少就需要10分钟。 1. 题目 2. 思想 其实这就是一道模拟题&#xff0c;难度中等。做这种题的关键就…

Jupyter Lab打印日志

有时候在 jupyter 中执行运行时间较长的程序&#xff0c;且需要一直信息&#xff0c;但是程序执行到某些时候就不再打印了。 可以开启 日志控制台&#xff0c;将日志信息记录在控制台中。 参考&#xff1a;https://www.autodl.com/docs/jupyterlab/

Hbase整合Mapreduce案例1 hdfs数据上传至hbase中——wordcount

目录 整合结构准备java API 编写pom.xmlMain.javaMap.javaReduce 运行 整合结构 准备 上传hdfs data.txt数据 data.txt I am wunaiieq QAQ 123456 Who I am In todays interconnected world the role of technology cannot be overstated It has revolutionized the way we …

temu登录接口逆向分析(含Py纯算)

文章目录 1. 写在前面2. 接口分析3. 算法还原 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…

python中什么叫做脚本

Python一种面向对象的动态类型语言&#xff0c;是一种脚本语言&#xff0c;常用于各种服务器的维护和自动化运行。它具有丰富和强大的库。它常被称为胶水语言&#xff0c;因为它能够把用其他语言制作的各种模块很轻松地联结在一起。 以.py 结尾的文件就是Python脚本&#xff0…

全面解析 Transformer:改变深度学习格局的神经网络架构

目录 一、什么是 Transformer&#xff1f; 二、Transformer 的结构解析 1. 编码器&#xff08;Encoder&#xff09; 2. 解码器&#xff08;Decoder&#xff09; 3. Transformer 模型结构图 三、核心技术&#xff1a;注意力机制与多头注意力 1. 注意力机制 2. 多头注意力&…

虚幻引擎---材质篇

一、基础知识 虚幻引擎中的材质&#xff08;Materials&#xff09; 定义了场景中对象的表面属性&#xff0c;包括颜色、金属度、粗糙度、透明度等等&#xff1b;可以在材质编辑器中可视化地创建和编辑材质&#xff1b;虚幻引擎的渲染管线的着色器是用高级着色语言&#xff08;…