FPGA开发——蜂鸣器实现音乐播放器的设计

news2024/9/19 10:43:06

一、概述

我们在进行蜂鸣器的学习的时候,总会在想既然蜂鸣器能够发出声音,那么它能够播放音乐吗,今天这篇我们文章我们就一起来学习怎样使用使用蜂鸣器来播放音乐,也就是怎样成为一个音乐播放器。

1、蜂鸣器的类型

在设计的时候其实蜂鸣器的类型也对我们最后所实现的效果有一点影响,蜂鸣器分为有源和无源两种,有源蜂鸣器的器件内部本身就带有振荡器,本身来讲完全不用我们进行外部振荡,二无源蜂鸣器是不带振荡器的,所以当涉及到相关频率使用时就需要我们使用外部振荡。这里因为我们使用PWM进行设计实现,所以如果有条件的话使用无源蜂鸣器所实现的效果会更好。

2、PWM介绍

PWM(Pulse Width Modulation),即脉冲宽度调制,是一种模拟信号电平数字编码方法。它通过将有效的电信号分散成离散形式,从而来降低电信号所传递的平均功率。PWM技术的核心在于通过调节脉冲的时间宽度(占空比)来等效地获得所需要合成的相应幅值和频率的波形。通过调整PWM信号的占空比和频率,可以实现声音的音量调节和音调变化。

  • 占空比:占空比是脉冲处于较高电压的时间占整个脉冲周期的百分比。通过改变占空比,可以实现对信号、能量等的调节。例如,在LED电路中,高占空比意味着LED非常明亮,而低占空比则意味着LED较为暗淡。
  • 频率:频率是单位时间内脉冲信号的次数。PWM信号的频率越高,控制效果越接近模拟信号,但也会受到电路响应时长的限制。

3、PWM调制的实现方式

硬件实现:许多微控制器和数字信号处理器(DSP)已包括了PWM控制器芯片,因此可以更轻松地实施数字化控制。这些芯片通过内部定时器或计数器来生成PWM信号,并通过调整相关参数来改变占空比和频率。
软件实现:在没有内置PWM控制器的系统中,也可以通过软件编程来模拟PWM信号。这通常涉及到对定时器中断的精确控制,以及在高电平和低电平之间快速切换IO口的输出状态。

4、音符的相关设计

这是关于高中低音符的频率和周期表,我们将会参考这个对代码进行设计。

二、工程实现

1、本次播放的音乐

本次我们设计得比较简单,设计了一个《我有一头小毛驴》的简单音乐播放器,具体乐谱如下:

2、基本构建思路

在本次的设计中,采用了一个音符播放播放0.5秒的设计,针对上述乐谱,采用四个字符为一组的方式进行划分,便于代码的赋值。利用三个计数器完成对于音乐播放的相关设计,第一个播放器用于技术每个音符技术的相关频率,第二个计数器用于对于在0.5秒播放时间内对于每个音符重复的次数进行计数,而第三个计数器用于对音符的播放顺序进行一个计数,由此关于音符的设置就设计完成,最后就是对于蜂鸣器进行占空比调制,对每个音符的频率进行一个8分频就完成了最终功能。

3、设计文件的编写

这里新建一个beep.v文件,如下:

//蜂鸣器
module beep(
  input         clk,
  input         rst_n,
  output    reg    beep_out
);
parameter CLK_CLY=50_000_000;//时钟频率
localparam  H1  =CLK_CLY/523,
            H1_L=CLK_CLY/262,
            H1_H=CLK_CLY/1047,
            H2  =CLK_CLY/587,
            H3  =CLK_CLY/659,
            H4  =CLK_CLY/698,
            H5  =CLK_CLY/784,
            H6  =CLK_CLY/880,
            H7  =CLK_CLY/988;


parameter TIME_500MS=25_000_000;//0.5秒

reg [17:0] cnt0;// 每个音符频率计数器
wire       add_cnt0;
wire       end_cnt0;

reg [9:0] cnt1;// 0.5秒内音符周期重复个数
wire       add_cnt1;
wire       end_cnt1;

reg  [5:0] cnt2;// 计数音符播放顺序
wire       add_cnt2;
wire       end_cnt2;
reg     [15:0] cnt_max;

reg   [17:0]  display;//音符计数器的最大值
//cnt0计数
always @(posedge clk or negedge rst_n)begin 
  if(!rst_n)
    cnt0<=0;
  else if(add_cnt0)begin 
    if(end_cnt0)
      cnt0<=0;
    else
      cnt0<=cnt0+1'b1;
  end
end 
assign add_cnt0=1'b1;
assign end_cnt0=add_cnt0 &&(cnt0==display-1);

//cnt1计数
always @(posedge clk or negedge rst_n)begin 
  if(!rst_n)
    cnt1<=0;
  else if(add_cnt1)begin 
    if(end_cnt1)
      cnt1<=0;
    else
      cnt1<=cnt1+1'b1;
  end
end 
assign add_cnt1=end_cnt0;
assign end_cnt1=add_cnt1 &&(cnt1==(TIME_500MS/display-1));

//cnt2计数
always @(posedge clk or negedge rst_n)begin 
  if(!rst_n)
    cnt2<=0;
  else if(add_cnt2)begin 
    if(end_cnt2)
      cnt2<=0;
    else
      cnt2<=cnt2+1'b1;
  end
end 
assign add_cnt2=end_cnt1;
assign end_cnt2=add_cnt2 &&(cnt2==50-1);

always @(posedge clk or negedge rst_n)begin
  if(!rst_n)
    display <=H1;
  else begin
    case (cnt2)
       0:display <=H1_L;
       1:display <=H1;
       2:display <=H1;
       3:display <=H3;

       4:display <=H5;
       5:display <=H5;
       6:display <=H5;
       7:display <=H5;
       
       8:display <=H6;
       9:display <=H6;
      10:display <=H6;
      11:display <=H1_H;

      12:display <=H5;
      13:display <=H5;
      14:display <=H5;
      15:display <=H5;

      16:display <=H4;
      17:display <=H4;
      18:display <=H4;
      19:display <=H6;

      20:display <=H3;
      21:display <=H3;
      22:display <=H3;
      23:display <=H3;

      24:display <=H2;
      25:display <=H2;
      26:display <=H2;
      27:display <=H2;

      28:display <=H5;
      29:display <=H5;
      30:display <=H5;
      31:display <=H5;

      32:display <=H1;
      33:display <=H1_L;
      34:display <=H1;
      35:display <=H3;

      36:display <=H5;
      37:display <=H5;
      38:display <=H5;
      39:display <=H5;

      40:display <=H6;
      41:display <=H6;
      42:display <=H6;
      43:display <=H1_H;

      44:display <=H5;
      45:display <=H5;
      46:display <=H5;
      47:display <=H5;

      40:display <=H4;
      41:display <=H4;
      42:display <=H4;
      43:display <=H6;

      44:display <=H3;
      45:display <=H3;
      46:display <=H3;
      47:display <=H3;
      40:display <=H3;
      41:display <=H3;

      42:display <=H2;
      43:display <=H2;
      44:display <=H2;
      45:display <=H3;

      46:display <=H1;
      47:display <=H1;
      48:display <=H1;
      49:display <=H1;
      default: display <=H1;
    endcase
  end
end

//pwm输出
//蜂鸣器pwm
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        beep_out <= 1'b1;
    end
    else if(cnt0 == (display>>3))begin//设置占空比
        beep_out <= 1'b1;
    end
    else if(cnt0==0)begin
        beep_out<= 1'b0;
    end
end
endmodule 

4、测试文件的编写

新建beep_tb.v文件,这里出来蜂鸣器输出没有任何激励,所以我们只需要进行时钟和复位进行赋值就行。如下:

//定义时间尺度
`timescale 1ns/1ns
module beep_tb ;

//输入信号定义
reg          clk           ;  
reg          rst_n         ; 
wire         beep_out       ;
//模块例化
beep beep_inst(
  /*input        */ .clk        (clk      )   ,
  /*input        */ .rst_n      (rst_n    )   ,
  /*output       */ .beep_out    (beep_out  )   
);

//激励信号产生
parameter CLK_CYC = 20;
//时钟
initial clk=1;
always #(CLK_CYC/2)clk=~clk;

//复位
initial begin
    rst_n= 1'b0;
    #(CLK_CYC*2);
    #3;//复位结束避开时钟上升沿
    rst_n= 1'b1;
end
endmodule

5、仿真波形图

通过对于波形图的观察,我们可以看到在三个计数器的不断计数之下蜂鸣器的输出波形占空比在不断进行变化 ,并且在经过对于计数器进行检查后没有发现什么问题。(这里方针波形图太长,没有截全),感兴趣的可以去自行进行仿真观察。最后进行下板验证之后,蜂鸣器也进行了正常播放,我们的设计成功。

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

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

相关文章

玩机进阶教程-----手机恢复出厂 误删除照片视频 误刷机后 几种数据恢复操作步骤解析【一】

手机中存储有众多的照片 视频 文件或者电话本这类的数据,虽然目前很多机型都有云存储。可以随时同步手机的存储数据。但万一云存储没有开启同步或者密码忘记。或者恢复出厂等等原因造成以上的数据丢失。或者手机系统问题导致的不开机但需要其中的数据等等。那么如何简单快速的…

【项目日记(五)】梦幻笔耕-测试报告

❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多项目内容 目录 1.项目背景2.测试环境3.测试计划3.1功能测试3.2自动化测试 1.项目背景 个人博客系统…

剪画小程序:自媒体创业者的准备-文案!

作为一个刚刚踏入自媒体领域的新人&#xff0c;我满怀着激情和憧憬&#xff0c;渴望通过视频分享自己的见解和生活点滴。然而&#xff0c;视频文案的创作却成了我面前难以逾越的高山。 在构思旅行视频时&#xff0c;面对美丽的风景和丰富的经历&#xff0c;我却无法用恰当的文字…

嵌入式学习Day19---Linux软件编程

目录 一、标准I/O 1.1.fseek 1.偏移量 2.实例 ​编辑 1.2.ftell 2.实例 ​编辑 二、文件I/O 2.1.打开文件 1.open 2.2.实例 2.2.读写文件 1.write 实例 ​编辑 2.read 实例 2.3.关闭文件 1.close 2.3.lseek 实例 三、标准I/O与文件I/O的区别 3.1.区别 四、其…

2024年有哪些开放式耳机值得入手?精选五大高分品牌

近几年兴起的开放式蓝牙耳机&#xff0c;具有佩戴舒适稳固、不影响使用者判断外界环境等优点&#xff0c;十分适合在户外环境下使用&#xff0c;因此受到了众多健身人士的喜爱。那么该如何挑选到一款适合自己的开放式耳机呢&#xff1f;2024年有哪些开放式耳机值得入手&#xf…

【架构】应用保护

这篇文章总结一下应用保护的手段。如今说到应用保护&#xff0c;更多的会想到阿里的sentinel&#xff0c;手段丰富&#xff0c;应用简单。sentinel的限流、降级、熔断&#xff0c;可以自己去试一下&#xff0c;sentinel主要通过配置实现功能&#xff0c;不难。sentinel的简介放…

Qt如何在工程中使用dll库

DEMO&#xff1a;Test &#xff1b;工程与dll皆为qmake编译&#xff1b; 所需文件&#xff1a;A.dll、A.lib、A.h、A_global.h&#xff1b;B.dll。其中A.dll 依赖 B.dll 1. 环境配置 &#xff08;1&#xff09;确认制作dll的Qt版本和当前工程版本是否一致(Qt6中的一些函数Qt…

SLAM中的概率基础(知识回顾)

今天有些知识点忘记了&#xff0c;特地过来回顾一下&#xff0c;于是就做了这些笔记。 为了方便能够在手机上更直观的看笔记&#xff0c;写下这篇文章&#xff0c;有错误请各位大佬指出。 一、 概率基础概念 1.1. 概率密度函数&#xff08;PDF&#xff09; 概率密度函数用于…

第十九次(安装nginx代理tomcat)

回顾 1.安装nodejs---jdk一样你的软件运行环境 yum -y list install|grep epel $? yum -y install nodejs #版本号 node -v 2.下载对应的nodejs软件npm yum -y install npm npm -v npm set config ...淘宝镜像 3.安装vue/cli command line interface 命令行接口 npm ins…

推荐4个国内可用的AI软件,用上以后都能早点下班

随着技术的发展&#xff0c;越来越多的AI软件出现在人们的视野&#xff0c;应用的领域更多&#xff0c;能力提升也更快&#xff0c;用在工作上能帮不少忙。下面就给大家分享4个国内可以直接使用的AI软件&#xff0c;希望大家啊用上以后都能早点下班~ 1.Kimi 一键直达>>h…

韶音开放式耳机怎么样?韶音、西圣、QCY热门款实测横评

开放式耳机是目前最火爆的的耳机市场细分赛道&#xff0c;开放式耳机的优点包括健康卫生&#xff0c;佩戴舒适性高&#xff0c;方便我们接收外部环境音等等&#xff0c;以上这些优势使得开放式耳机特别适配户外运动场景&#xff0c;在工作、日常生活等场景下使用也是绰绰有余。…

Day81 代码随想录打卡|贪心算法篇---跳跃游戏 II

题目&#xff08;leecode T45&#xff09;&#xff1a;给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j…

亚马逊新产品怎么快速提升销量

经常有卖家吐槽新产品没销量&#xff0c;但卖家们的吐槽并不能把问题解决&#xff0c;南哥和大家分享一下关于测评的好处和一些技巧&#xff0c;以及如何样做才能提高店铺销量&#xff0c;将运营和测评结合起来做 测评的好处: 提升店铺信誉&#xff0c;制造爆款&#xff0c;增…

DjangoRF-12-创建testcases子应用--测试套件模块

models–serializers-permission-views-urls 1、创建models&#xff0c; class TestSuit(BaseModel): name models.CharField(测试套件名称, max_length200, help_text测试套件名称) task models.ForeignKey(Task, verbose_name测试任务, on_deletemodels.PROTECT,help_tex…

揭秘MITM攻击:原理、手法与防范措施

中间人攻击发生时&#xff0c;攻击者会在通讯两端之间插入自己&#xff0c;成为通信链路的一部分。攻击者可以拦截、查看、修改甚至重新定向受害者之间的通信数据&#xff0c;而不被双方察觉。这种攻击常见于未加密的Wi-Fi网络、不安全的HTTP连接或者通过社会工程学手段诱导受害…

C++基础语法:函数探幽(一)内联函数,默认参数,函数重载

前言 "打牢基础,万事不愁" .C的基础语法的学习."学以致用,边学边用",编程是实践性很强的技术,在运用中理解,总结. 引入 <C Prime Plus> 6th Edition(以下称"本书")第8章内容解读 内联函数 1>本书P253--8.1节C内联函数第二…

数据库事务处理技术——故障恢复

1. 数据故障恢复的宏观思路 我们知道DBMS是利用内存&#xff08;主存&#xff09;和外存&#xff08;辅存&#xff09;这样的存储体系进行数据库的管理&#xff0c;其中内存也就是我们常说的缓存是易失的。而事务时DBMS对数据库进行控制的基本单元&#xff0c;宏观上是由程序设…

函数、预解析、参数、参数列表、抛出异常、捕获异常

函数 命名函数 匿名函数 构造函数 纯函数 预解析 关键字var和function开头的语句块提前进行处理 处理过程&#xff1a;当变量和函数的声明处在作用域比较靠后的位置的时候&#xff0c;变量和函数的声明会被提升到作用域的开头。 解释代码和执行代码 因为是在所有代码执行之…

【软件建模与设计】-07-静态建模

目录 1、类之间关系 1.1、关联 1.1.1、关联的多重性 1.1.2、三元关联 1.1.3、一元关联 1.1.4、关联类 2、组合与聚合层次 2.1、组合 2.2、聚合 3、泛化/特化层次 4、约束 5、静态建模和UML 5.1、问题域的静态建模 6、系统上下文的静态建模 7、使用UML构造型对类…

JAVA Spring学习Day1

Maven Maven配置&#xff1a; Maven是Java项目的构建工具&#xff0c;使用pom.xml配置文件管理项目依赖、插件和构建目标。Spring Boot项目搭建&#xff1a; Spring Boot是基于Spring框架的快速开发框架&#xff0c;通过约定大于配置的理念简化了Spring应用的搭建和开发。 …