FPGA学习——蜂鸣器实现音乐播放器并播放两只老虎

news2024/10/6 22:21:27

文章目录

  • 一、蜂鸣器简介
    • 1.1 蜂鸣器分类
    • 1.2 PWM
  • 二、C4开发板原理图
  • 三、如何产生不同的音调
  • 四、代码实现及分析
  • 五、总结

一、蜂鸣器简介

1.1 蜂鸣器分类

蜂鸣器一般分为有源蜂鸣器和无源蜂鸣器。二者的区别在于,有源蜂鸣器内部含有振动源和功放电路,只需上电便可发出鸣叫。而无源蜂鸣器内部不含振动源和功放电路,因此我们需要给予其PWM方波,才能驱动无源蜂鸣器正常工作。

1.2 PWM

PWM即脉冲脉宽调制,PWM的占空比是指在一个完整的时钟周期内,高电平所占时间占整个时钟周期的比例(50%占空比即高低电平各占一半时钟周期),为方便代码编写,本项目产生的PWM均为50%占空比。

二、C4开发板原理图

在这里插入图片描述

博主所用开发板为Cyclone Ⅳ开发板,开发板芯片为:EP4CE6F17C8,由开发板原理图可以看出,本开发板蜂鸣器低电平有效。

三、如何产生不同的音调

我们可以通过给予无源蜂鸣器不同频率的PWM方波信号从而实现不同的音调音符。
相关数据参考可见下图:
在这里插入图片描述
举个例子:博主所用开发板晶振为50MHz,而低音Do的频率为262,因此我们需要在一秒内产生50MHz/262次PWM方波信号,此时蜂鸣器变会发出低音Do(如有错误请指正,博主是这样理解的,乐理知识匮乏,请见谅)。

两只老虎的乐谱如下:

在这里插入图片描述

四、代码实现及分析

本次项目较为简单,仅有一个蜂鸣器模块。

源码分析:

  • 本次项目首先需要一个音符计数器,用来存放歌曲中的音符数目,由乐谱可知两只老虎共含有34个音符,因此我们需要一个6位宽的计数器用来计数到34(后续发现好像乐谱中间隔比较大的是空拍?各位可以自行调整)
  • 除此之外,本次项目需要一个节拍计数器,不过这方面也是乐理知识,博主不太懂,两只老虎好像是一秒四拍,所以我们需要设计一个250ms计数器用来记一拍(也就是一个音符播放的时间)
  • 同时我们自然需要一个计数音符频率的计数器。由于不同音符的频率不尽相同,因此我们可以很自然地想到需要引入一个中间信号,通过case第几个音符,给予中间信号不同的频率值。
  • 另外由于本项目生成的PWM均为50%占空比,因此需要一个中间信号duty,duty为音符频率的一半,音符频率计数器小于duty时蜂鸣器输出0,否则输出1.
module beep (
    input       wire        clk     ,
    input       wire        rst_n   ,
    input       wire        beep_en ,

    output      reg         beep     //输出蜂鸣器
);

//内部参数定义
parameter   CYCLE = 26'd50_000_000  ;
parameter   TIME  = 24'd12_500_000  ;
parameter   NUM   = 6'd34           ;
parameter   DOL   = CYCLE/262       ,
            REL   = CYCLE/294       ,
            MIL   = CYCLE/330       ,
            FAL   = CYCLE/349       ,
            SOL   = CYCLE/392       ,
            LAL   = CYCLE/440       ,
            XIL   = CYCLE/494       ,
            DOM   = CYCLE/523       ,
            REM   = CYCLE/587       ,
            MIM   = CYCLE/659       ,
            FAM   = CYCLE/698       ,
            SOM   = CYCLE/784       ,
            LAM   = CYCLE/880       ,
            XIM   = CYCLE/988       ,
            DOH   = CYCLE/1047      ,
            REH   = CYCLE/1175      ,
            MIH   = CYCLE/1319      ,
            FAH   = CYCLE/1397      ,
            SOH   = CYCLE/1568      ,
            LAH   = CYCLE/1760      ,
            XIH   = CYCLE/1967      ;


//内部信号定义
reg    [5:0]        cnt_num     ;//音符个数寄存器
wire                add_cnt_num ;
wire                end_cnt_num ;

reg    [23:0]       cnt_250     ;//一拍时间寄存器
wire                add_cnt_250 ;
wire                end_cnt_250 ;

reg     [17:0]      cnt_frq     ;//音符频率寄存器
wire                add_cnt_frq ;
wire                end_cnt_frq ;


reg     [17:0]      frq         ;//中间信号,存储音符频率
wire    [16:0]      duty        ;//中间信号,用于比较产生50%PWM

//250ms计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_250 <= 1'b0;
    end
    else if(add_cnt_250)begin
        if(end_cnt_250)begin
            cnt_250 <= 1'b0;
        end
        else begin
            cnt_250 <= cnt_250 + 1'b1;
        end
    end
    else begin
        cnt_250 <= cnt_250;
    end
end

assign add_cnt_250 = beep_en;
assign end_cnt_250 = add_cnt_250 && cnt_250 == TIME - 1'b1;

//音符个数寄存器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_num <= 1'b0;
    end
    else if(add_cnt_num)begin
        if(end_cnt_num)begin
            cnt_num <= 1'b0;
        end
        else begin
            cnt_num <= cnt_num + 1'b1;
        end
    end
    else begin
        cnt_num <= cnt_num;
    end
end

assign add_cnt_num = end_cnt_250;
assign end_cnt_num = add_cnt_num && cnt_num == NUM - 1'b1;


//音符频率计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_frq <= 1'b0;
    end
    else if(add_cnt_frq)begin
        if(end_cnt_frq || end_cnt_250)begin
            cnt_frq <= 1'b0;
        end
        else begin
            cnt_frq <= cnt_frq + 1'b1;
        end
    end
    else begin
        cnt_frq <= cnt_frq;
    end
end

assign add_cnt_frq = beep_en;
assign end_cnt_frq = add_cnt_frq && cnt_frq == frq - 1'b1;

//音频赋值
always@(*)begin
    case(cnt_num)
    6'd0     :   frq = DOM;
    6'd1     :   frq = REM;
    6'd2     :   frq = MIM;
    6'd3     :   frq = DOM;
    6'd4     :   frq = DOM;
    6'd5     :   frq = REM;
    6'd6     :   frq = MIM;
    6'd7     :   frq = DOM;
    6'd8     :   frq = MIM;
    6'd9     :   frq = FAM;
    6'd10    :   frq = SOM;
    6'd11    :   frq = MIM;
    6'd12    :   frq = FAM;
    6'd13    :   frq = SOM;
    6'd14    :   frq = SOM;
    6'd15    :   frq = LAM;
    6'd16    :   frq = SOM;
    6'd17    :   frq = FAM;
    6'd18    :   frq = MIM;
    6'd19    :   frq = DOM;
    6'd20    :   frq = SOM;
    6'd21    :   frq = LAM;
    6'd22    :   frq = SOM;
    6'd23    :   frq = FAM;
    6'd24    :   frq = MIM;
    6'd25    :   frq = DOM;
    6'd26    :   frq = REM;
    6'd27    :   frq = SOL;
    6'd28    :   frq = DOM;
    6'd29    :   frq = 0  ;
    6'd30    :   frq = REM;
    6'd31    :   frq = SOL;
    6'd32    :   frq = DOM;
    6'd33    :   frq = 0  ;
    default  :   frq = 0  ;
    endcase
end

//beep输出赋值
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        beep <= 1'b1;
    end
    else if(cnt_frq < duty && beep_en)begin
        beep <= 1'b0;
    end
    else begin
        beep <= 1'b1;
    end
end

//生成占空比为50%的音频PWM方波的比较信号
assign duty = frq >> 1;

endmodule

五、总结

本项目较为简单,基本是在做计数器的练习和PWM方波信号产生练习,希望大家能够掌握。

如有没有讲清楚的地方还请大家指正。

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

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

相关文章

【雕爷学编程】 MicroPython动手做(35)——体验小游戏3

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

计算机和汇编语言

1.用电表示数字 我们已经学习过二进制来表示数字 二进制计数采用0和1组合表示数字 0和1很适合使用开关闭合&#xff0c;导线上有电流是1&#xff0c;无电流是 我们还可以加上小灯泡&#xff0c;来表示数 2.二进制加法机 上述这个加法机器是接受左边和下面的输入&#xff0c;把…

【沁恒蓝牙mesh】CH58x系统时钟配置与计算

本文主要记录了【沁恒蓝牙mesh】CH58x系统时钟配置与计算 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是喜欢记录零碎知识点的小菜鸟。&#x1f60e;&#x1f4dd; 个人主页&#xff1a;欢迎访问我的 Ethernet_Comm 博客主页&#x1f525;&#x1f389; 支持我&am…

侧边栏的打开与收起

侧边栏的打开与收起 <template><div class"box"><div class"sideBar" :class"showBox ? : controller-box-hide"><div class"showBnt" click"showBox!showBox"><i class"el-icon-arrow-r…

云渲染:为你的设计作品增添细节与逼真感!

在设计作品中&#xff0c;细节和逼真感是展现作品品质和吸引观众眼球的关键要素。而云渲染技术则是让我们能够以更高的水平来增添细节和逼真感的利器。让我们一起深入了解云渲染&#xff0c;探索它如何为我们的设计作品带来更出色的效果。 云渲染技术利用云计算的强大能力&…

webshell详解

Webshell详解 一、 Webshell 介绍二 、 基础常见webshell案例 一、 Webshell 介绍 概念 webshell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境&#xff0c;也可以将其称做为一种网页后门。黑客在入侵了一个网站后&#xff0c;通常会将asp或php后门文件与…

千元左右初学者性价比吉他推荐,VEAZEN费森VZ90和布鲁克S25怎么样?各方面评测对比,哪一款更出众!

在1500元左右价位里的吉他品牌来说&#xff0c;可谓群雄割据&#xff0c;根本无法判断到底是谁更出众。那么今天就用这个价位里我们觉得比较受欢迎的两款产品&#xff0c;VEAZEN费森VZ90系列和BROOK布鲁克S25系列详细对比评测&#xff0c;希望能给琴友一个很好的选择参考。 15…

批量创建可配置物料参数文件

启用可配置物料之后&#xff0c;每次创建新的物料需要通过CU41创建可配置物料&#xff0c;没找大批量创建的程序&#xff0c;所以SHDB录屏搞了一个代码。 前提&#xff1a;物料主数据初始化通过程序导入时&#xff0c;可配置物料参数文件已按照物料代码赋值。 ​效果&#xf…

同比环比使用方法

一、解释&#xff1a; 1.同比&#xff1a;本期与去年同期相比 &#xff0c;如2023年8月 比 2022年8月 2.环比&#xff1a;本期与上期相比 &#xff0c;如2023年8月 比 2023年7月 二、应用&#xff1a; 1.场景&#xff1a;统计日报、周报、月报、年报下进店客流的同比和环…

Stable Diffusion教程(6) - 图片高清放大

放大后细节 修复图片损坏 显存占用 速度 批量放大 文生图放大 好 是 高 慢 否 附加功能放大 一般 否 中 快 是 图生图放大 好 是 低 慢 是 tile模型放大 非常好 是 高 快 是 通过文生图页面的高清修复 优点&#xff1a;放大时能添加更多细节&am…

LeetCode--HOT100题(18)

目录 题目描述&#xff1a;73. 矩阵置零&#xff08;中等&#xff09;题目接口解题思路1代码解题思路2代码 PS: 题目描述&#xff1a;73. 矩阵置零&#xff08;中等&#xff09; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都…

【Linux】网络基础之IP协议

目录 &#x1f338;1、基本概念&#x1f33a;2、IP协议报文结构&#x1f368;2.1、4位版本号&#x1f369;2.2、4位首部长度和16位总长度&#x1f36a;2.3、8位生存时间&#xff08;TTL&#xff09;&#x1f36b;2.4、8位协议&#x1f36c;2.5、16位首部校验和&#x1f36d;2.6…

Manim(一款强大的数学可视化动画引擎)学习历程

相逢情便深&#xff0c;恨不相逢早 第一眼看见上面这种类型的视频我就深深被它的简约清楚所折服&#xff0c;我觉得它完全符合我的审美&#xff0c;我也相信只要了解过制作这种视频的软件的人都会喜欢上它。运用这种风格比较有名的是b站里的一位up主名叫3Blue1Brown&#xff0…

vue卡片轮播图

我的项目是vue3的&#xff0c;用的swiper8 <template><div class"tab-all"><div class"tab-four"><swiper:loop"true":autoplay"{disableOnInteraction:false,delay:3000}":slides-per-view"3":center…

快速上手字符串函数

文章目录 前言一、求字符串的长度strlen函数strlen函数学习使用strlen函数模拟实现strlen函数模拟实现方法1&#xff1a;计数器法strlen函数模拟实现方法2&#xff1a;指针减指针法strlen函数模拟实现方法3&#xff1a;递归方法 二、字符串的拷贝&#xff0c;拼接和比较strcpy函…

某科技公司提前批测试岗

文章目录 题目 今天给大家带来一家提前批测试岗的真题&#xff0c;目前已经发offer 题目 1.自我介绍 2.登录页面测试用例设计 3.如何模拟多用户登录 可以使用Jmeter,loadRunner性能测试工具来模拟大量用户登录操作去观察一些参数变化 4.有使用过Jmeter,loadRunner做过性能压…

为什么 CSS 这么难学?

前言 CSS难其实就难在其内容的多变上&#xff0c;我觉得这些其实都可以通过大量的练习来解决&#xff0c;去记再多的东西不如写几个demo或者小项目来的收获大&#xff0c;当然练完项目所需要的总结是必需的&#xff01;下面我推荐整理了一些学习css相关的网站和项目&#xff0…

谁会拒绝一篇关于【python装饰器】的友情分享呢~

一、什么是装饰器 1. python装饰器是用于拓展原来函数功能的一种函数&#xff0c;目的是在不改变原函数的情况下&#xff0c;给函数增加功能。2. 装饰器是通过闭包实现&#xff0c;所以讲装饰器首先得知道什么是闭包。 二、什么是闭包 1、什么是闭包 1. 一个定义在函数内部的…

【Jmeter】配置不同业务请求比例,应对综合场景压测

目录 背景 Jmeter实现&#xff08;Random&#xff09; 在测试计划下&#xff0c;我们右键“添加”——配置原件——Random Variable 设置随机数的变量名称为num&#xff0c;设置取值范围0到100 右键线程组添加“逻辑控制器”——如果&#xff08;if&#xff09;控制器 当…

Win11系统优化

当你看到这篇文章&#xff0c;我相信你电脑卡的已经不行不行的了&#xff0c;执行完快抢救一下。 一、设置win11系统显示效果&#xff08;减轻系统运行压力&#xff09; &#xff08;1&#xff09;.点击桌面的&#x1f50d;按钮&#xff0c;然后在输入框内输入“查看高级系统设…