《FPGA学习》->蜂鸣器播放

news2024/9/20 16:39:52
🍎 与其担心未来,不如现在好好努力。在这条路上,只有奋斗才能给你安全感。你若努力,全世界都会为你让路。

蜂鸣器的发声原理由振动装置和谐振装置组成,而蜂鸣器又分为无源他激型与有源自激型。本实验采用无源蜂鸣器,蜂鸣器的发声不同是靠频率不同进行控制的,音调的大小是靠占空比也决定的。

下面附上蜂鸣器的电路图:

由蜂鸣器电路图可以看出,蜂鸣器打开需要BEEP端口为高电平,关闭则是让BEEP端口为低电平。

清楚了蜂鸣器控制方式以后,我们再来看一下如何让蜂鸣器发出“哆来咪发索拉西“的声音。

上图是蜂鸣器发出不同声音的一个频率表。由频率可以得到具体的计数周期,开发板的晶振频率为50MHz,那低音1的计数周期就应该为:,我们可以定义一个音的时间周期为500ms,当计数到190839的一半时,把蜂鸣器打开,当计数到190839时,把蜂鸣器关闭,下一个计数从0重新计数。这样它就能发出低音1的音,也就是"哆"音,同时它的一个占空比就是50%。发出第一个音后,我们可以在第二个500ms让蜂鸣器发出低音2,也就是"来"音,以此类推,我们只定义低音1~低音7总共7个音,定义一个3位宽的数就可以把它们都罗列出来。下面是这次任务的一个波形图。

参照波形图,我们对任务进行代码编写:

module beep          //模块开始,定义名称为beep
#(
    parameter CNT_MAX  = 25'd24_999_999 ,    //定义全局变量CNT_MAX,时间周期为500ms
    parameter DO       = 18'd190839     ,    //定义全局变量DO,计数值为190839,发“哆”音
    parameter RE       = 18'd170067     ,    //定义全局变量RE,计数值为170067,发“来”音
    parameter MI       = 18'd151514     ,    //定义全局变量MI,计数值为151514,发“咪”音
    parameter FA       = 18'd143265     ,    //定义全局变量FA,计数值为143265,发“发”音
    parameter SO       = 18'd127550     ,    //定义全局变量SO,计数值为127550,发“嗦”音
    parameter LA       = 18'd113635     ,    //定义全局变量LA,计数值为113635,发“拉”音
    parameter XI       = 18'd101214          //定义全局变量XI,计数值为101214,发“西”音
)
(
    input    wire    sys_clk   ,     //定义sys_clk为输入模式   (时钟)
    input    wire    sys_rst_n ,     //定义sys_rst_n为输入模式 (复位)
    
    output    reg        beep_out          //定义beep_out为寄存器类型的输出模式
);

    reg     [24:0]    cnt ;            //定义cnt为25位宽的寄存器类型
    reg     [17:0]    freq_cnt;        //定义freq_cnt为18位宽的寄存器类型
    reg     [2:0]   cnt_500ms;        //定义cnt_500ms为3位宽的寄存器类型
    
    reg     [17:0]    freq_data;        //定义freq_data为18位宽的寄存器类型

always@(posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)        //复位信号到来     
            begin
                cnt <= 25'd0;        //使cnt清0    
            end
        else    if(cnt == CNT_MAX)   //判断cnt是否计数到最大值   
            begin
                cnt <= 25'd0;        //使cnt清0         
            end
        else 
            cnt <= cnt+ 25'd1;         //使cnt + 1        
    end
    
always@(posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)        //复位信号到来               
            begin
                cnt_500ms <= 3'd0;        //使cnt_500ms清0          
            end
        else    if(cnt_500ms == 3'd6&&cnt == CNT_MAX)   //判断cnt_500ms是否计数到3'd6   
            begin
                cnt_500ms <= 3'd0;        //使cnt_500ms清0       
            end
        else    if(cnt == CNT_MAX)   //判断cnt是否计数到最大值    
            begin
                cnt_500ms <= cnt_500ms+ 3'd1;   //使cnt_500ms + 1           
            end
        else 
            cnt_500ms <= cnt_500ms;      //使cnt_500ms保持不变  
    end

always@(posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)        //复位信号到来                
            begin
                freq_data <= DO;    //把DO的值赋给freq_data
            end
        else case(cnt_500ms)
            3'd0:freq_data <= DO ;        //把DO的值赋给freq_data
            3'd1:freq_data <= RE ;      //把RE的值赋给freq_data
            3'd2:freq_data <= MI ;      //把MI的值赋给freq_data
            3'd3:freq_data <= FA ;      //把FA的值赋给freq_data
            3'd4:freq_data <= SO ;      //把SO的值赋给freq_data
            3'd5:freq_data <= LA ;      //把LA的值赋给freq_data
            3'd6:freq_data <= XI ;      //把XI的值赋给freq_data
            default:freq_data <= DO ;   //把DO的值赋给freq_data
            endcase    
    end 
        
always@(posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)        //复位信号到来                
            begin
                freq_cnt <= 18'd0;        //使freq_cnt清0          
            end    
        else     if((freq_cnt == freq_data)||(cnt == CNT_MAX))  //判断freq_cnt是否计数到freq_data或者cnt计数到最大值
            begin
                freq_cnt <= 18'd0;        //使freq_cnt清0           
            end
        else 
            freq_cnt <= freq_cnt+ 18'd1;  //使freq_cnt + 1 
    end
    
always@(posedge sys_clk or negedge sys_rst_n)
    begin
        if(sys_rst_n == 1'b0)       //复位信号到来                
            begin
                beep_out <= 1'b0;           //使beep_out清0          
            end
        else     if(freq_cnt >= freq_data/2)  //判断freq_cnt是否计数到freq_data的一半
            begin
                beep_out <= 1'b1;         //使beep_out置1          
            end 
        else 
            begin
                beep_out <= 1'b0;         //使beep_out清0          
            end 
    end
    
endmodule     //模块结束

下面是仿真的波形:

从图中可以看出cnt_500ms的值是从0计数到6,再次计数会变为0,刚好对应7个音,符合我们要求。

freq_data中的数据对应不同音调的计数周期,因为数值太大,所以在编写仿真文件时,这里把数值改小了,方便查看波形。

cnt的值仿真文件里设置的数为100,这里计数到100会从0开始,与任务波形图符合。

下面是仿真代码:

`timescale 1ns/1ns        //时间尺度预编译指令      时间单位/时间精度
                          
module tb_beep();         //定义模块名称为tb_beep
                          
reg     sys_clk;          //定义sys_clk为reg型
reg     sys_rst_n;        //定义sys_rst_n为reg型
wire    beep_out;         //定义beep_out为reg型

initial                          //初始化
    begin                        
        sys_clk   = 1'b1  ;      //使sys_clk初始化为高电平状态
        sys_rst_n = 1'b0  ;      //使sys_clk初始化为低电平状态
        #20                      //延时20ns
        sys_rst_n = 1'b1  ;      //使sys_rst_n电平拉高
    end                          
                                 
always #10 sys_clk = ~sys_clk;   //使sys_clk电平10ns电平状态反转一次

beep                             //例化对象名称
#(
    .CNT_MAX(25'd100)    ,       //改变parameter定义的参数
    .DO     (18'd19)     ,
    .RE     (18'd17)     ,
    .MI     (18'd15)     ,
    .FA     (18'd14)     ,
    .SO     (18'd12)     ,
    .LA     (18'd11)     ,
    .XI     (18'd10)    
)
beep_inst                        //实例化名称
(                                
    .sys_clk      (sys_clk  ),      //使sys_clk信号端口例化为sys_clk
    .sys_rst_n    (sys_rst_n),   //使sys_rst_n信号端口例化为sys_rst_n
                                 
    .beep_out     (beep_out )    //使beep_out信号端口例化为beep_out
);

endmodule     //模块结束    

🔥🔥🔥本系列文章持续更新,喜欢的话可以关注收藏~🔥🔥🔥

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

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

相关文章

嵌入物理(PINN)还是基于物理(AD)?

文章目录1. 传统"反演问题"1.1 反演问题是什么1.2 常见反演问题1.3 传统反演问题的困境2. 深度学习优势3. AD inversion 例子3.1 ADsurf3.2 ADseismic关于PINN的内容大家可以直接google PINN (Physical-informed neural network),其主要的目的是用一个神经网络拟合物…

K8S 部署 Jenkins

本文使用 bitnami 镜像部署 Jenkins 官方文档&#xff1a;https://github.com/bitnami/charts/tree/main/bitnami/jenkins 添加 bitnami 仓库 helm repo add bitnami https://charts.bitnami.com/bitnami自定义 values.yaml storageClass&#xff1a;集群的存储类&#xff…

(考研湖科大教书匠计算机网络)第五章传输层-第八节1:TCP连接管理理论部分(三次握手与四次挥手)

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航此部分内容借鉴博主【小林coding】 &#xff0c;其对计算机网络内容的图解可以说是深入浅出&#xff0c;尤其是三次握手和四次挥手这一部分&#xff0c;堪称全网最佳。所这…

OpenEuler安装软件方法

在树莓派上烧录好OpenEuler后上面是什么软件都没有的&#xff0c;像一些gcc的环境都需要自己进行配置。官方提供的安装命令是yum&#xff0c;但是执行yum是找不到命令的&#xff1a;   这个其实是因为OpenEuler中默认的安装软件使用了dnf而不是yum&#xff0c;所以软件的安装…

智能小车红外跟随原理

红外跟随电路红外跟随电路由电位器R17&#xff0c;R28&#xff1b;发光二极管D8&#xff0c;D9&#xff1b;红外发射管 D2&#xff0c;D4和红外接收管D3&#xff0c;D5和芯片LM324等组成,LM234用于信号的比较&#xff0c;并产生比较结果输出给单片机进行处理。智能小车红外跟随…

OpenGL学习日志之纹理

引言 为了使我们渲染的模型拥有更多细节&#xff0c;我们可以添加足够多的顶点&#xff0c;然后给每一个顶点都添加顶点颜色。但是这样就会产生很多额外的开销&#xff0c;因此就出现了纹理映射技术&#xff0c;我们通过纹理采样为物体的表面添加更多的细节。 纹理定义 通俗…

超25亿全球月活,字节依然没有流量

&#xff08;图片来源于网络&#xff0c;侵删&#xff09; 文|螳螂观察 作者| 搁浅虎鲸 注意看&#xff0c;这个男人叫梁汝波&#xff0c;是字节跳动的联合创始人&#xff0c;也是接棒张一鸣的新任CEO。 在字节跳动十周年之际&#xff0c;他发表了激情昂扬的演讲。“激发创…

【Datawhale图机器学习】图嵌入表示学习

图嵌入表示学习 学习视频&#xff1a;https://www.bilibili.com/video/BV1AP4y1r7Pz/ 如何把节点映射成D维向量&#xff1f; 人工特征工程&#xff1a;节点重要度、集群系数、Graphlet图表示学习&#xff1a;通过随机游走构造自监督学习任务。DeepWalk、Node2Vec矩阵分解深度…

win10字体模糊怎么办?看下面4种宝藏解决方法

最近很多用户反映电脑安装了Win10系统后出现字体发虚&#xff0c;模糊不清的问题&#xff0c;这看起来让人非常难受。win10字体模糊怎么办&#xff1f;来看下面4种宝藏解决方法&#xff01;下面的方法适用于各类台式电脑以及笔记本电脑哦&#xff01; 操作环境&#xff1a; 演示…

ESP开发环境搭建

一、windows中搭建 esp-idf tool(可选),下载连接如下:https://dl.espressif.com/dl/esp-idf/?idf4.4 下载安装tools后进入vscode进行插件安装&#xff08;未离线下载idf工具也可以通过第二步通过插件下载安装&#xff09; 1. vscode安装编译环境 ESP-IDF 需要安装一些必备工…

高并发系统设计之负载均衡

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 文章目录DNS负载均衡Nginx负载均衡负载均衡算法负载均衡配置超时配置被动健康检查与主动健康检查LVS/F5Nginx当我们的应用单实例不能支撑用户请求时&#xff0c;此时就需要扩容&#xff0c;从一台服务器扩容到…

【matplotlib】可视化解决方案——如何设置轴标签的透明度和大小

概述 Axes 标签对于读者理解图表非常重要&#xff0c;它描述了图表中展现的数据内容。通过向 axes 对象添加标签&#xff0c;可以有效理解图表所表达的内容。首先来了解一下 matplotlib 是如何组织图表的。最上层是一个 Figure 实例&#xff0c;包含绘图中所有可见和不可见的内…

北斗导航 | 2023 PTTI会议论文 2023 ITM会议论文 2022 ION GNSS+ 会议论文下载:ION 美国导航学会

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 2023 PTTI会议论文 2023 ITM会议论文 2022 ION GNSS+ 论文下载百度云链…

Teradata当年数据仓库的“一哥”为何突然退出中国市场:苦撑了3年,员工早有预料

2月15日&#xff0c;Teradata天睿公司官宣即将撤离中国市场。 又是一个艰难的决定&#xff0c;听着似乎很熟悉。Teradata为什么突然宣布结束在中国的直营&#xff1f;其实&#xff0c;回顾Teradata在中国市场的发展状况&#xff0c;一点也不突然。 多年前&#xff0c;我曾经与…

Excel表格自动转Json数据

Excel表格转JSON格式在实际工作中&#xff0c;我们常常使用Excel记录各种数据&#xff0c;但在各种应用系统传输数据却使用JSON格式&#xff0c;这就需要把Excel转为JSON。如果能把数据转换传输过程自动化就更完美了。Excel转JsonXX公司生产日报表为例&#xff0c;生产工人用Ex…

JSR303基本使用以及整合springboot统一异常处理

目录 一、前言 什么是JSR303 二、JSR303基本使用&#xff08;普通使用&#xff09; 1&#xff09;、引入jar包 2&#xff09;、实体类对需要校验的数据进行校验 3)、对前端传递过来的参数进行限制 三、JSR303基本使用&#xff08;分组校验&#xff09; 1)、创建分组 2)…

leaflet 根据两个坐标值,设置arc弧线和Marker(079)

第069个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中根据提供的两个点,绘制出marker,同时将两点间绘制出一条弧线。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共88行)安装插件相关API参考…

最全面的SpringBoot教程(六)——SpringBoot运行原理分析

前言 本文为 最全面的SpringBoot教程&#xff08;六&#xff09;——SpringBoot运行原理分析 相关知识&#xff0c;下边将对SpringBoot运行原理以及自动配置原理进行详尽的分析介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考…

计算机网络 物理层

1&#xff0c;物理层的基本概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。现有的计算机网络中的硬件设备和传输媒体的种类非常繁多&#xff0c;而通信手段也有许多不同方式。物理层的作用正是要尽可能地屏蔽掉这…

【ts + webpack】贪吃蛇小游戏

目录 一、项目搭建 1.1 初始化项目 二、项目界面布局 三、完成Food类 四、完成记分牌类 五、初步完成snake类 六、创建游戏控制器类 - 键盘事件 七、GameControl - 使蛇移动 八、蛇撞墙和吃食检测 一、项目搭建 1.1 初始化项目 1.使用init命令生成package.json文件 …