当前位置: 首页 > article >正文

跟着逻辑先生学习FPGA-第六课 无源蜂鸣器发声实验

硬件平台:征战Pro开发板
软件平台:Vivado2018.3
仿真软件:Modelsim10.6d
文本编译器:Notepad++

征战Pro开发板资料
链接:https://pan.baidu.com/s/1AIcnaGBpNLgFT8GG1yC-cA?pwd=x3u8
提取码:x3u8

1 知识背景

1.1 蜂鸣器简介

蜂鸣器按照结构原理不同可分为压电式蜂鸣器和电磁式蜂鸣器。 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、 阻抗匹配器及共鸣箱、外壳等组成; 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。压电式蜂鸣器是利用压电效应原理工作的,当对其施加交变电压时它会产生机械振动发声; 电磁式蜂鸣器是接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场, 振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
压电式蜂鸣器和电磁式蜂鸣器由于发音原理不同, 产生的声音信号也不一样。 压电式结构简单耐用但音调单一,适用于报警器等设备; 而电磁式由于音质好,所以多用于语音、音乐等设备。 本次实验使用的蜂鸣器为电磁式蜂鸣器。
蜂鸣器按照驱动方式不同又可分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声,因此如果用直流信号无法令其鸣叫,这就需要用 2K~5K 的方波(声音频率)去驱动。
在这里插入图片描述
图6-6- 1有源蜂鸣器(左)和无源蜂鸣器(右)

如上图所示,从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置, 能看到绿色电路板的是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。

1.2 无源蜂鸣器驱动原理

无源蜂鸣器与有缘蜂鸣器不同,因其内部不带震荡源, 所以其无法向有源蜂鸣器那样直接用直流信号驱动, 这里需要使用 PWM 方波才能驱动其发声。
如何发出不同的声音呢? 上面说到需要使用 PWM 方波才能驱动其发声,所以这里我们只要控制输入的 PWM 方波, 输入不同的 PWM 方波发出的声音就不一样了。而不同频率和占空比的方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。所以我们只需产生不同频率和占空比的 PWM 方波去驱动无源蜂鸣器就能让无源蜂鸣器发出不同的音调了。

1.3 PWM简介

PWM 波即脉冲宽度调制,英文全称 Pulse Width Modulation。 PWM 控制技术广泛应用在测量、通信、功率控制与变换的等众多领域中,应用的逆变电路绝大部分是 PWM 型。 以下为周期为 1KHz,500Hz,高电平宽度占比(占空比)分别为 50%、60%、50%的波形图:在这里插入图片描述图6-6- 2频率占空比示意图
由上图可知,当信号周期一定,信号高电平时间所占信号周期的百分比不一样,即为不同占空比的 PWM 波。在逆变电路中,当使用这样的波形去驱动 MOS 管的导通时,由于一个周期内不同占空比的 PWM 信号其高电平持续长度不一样,因此使得 MOS 管的开通时间也不一样,从而使得电路中的平均电流也不一样。 因此,通过调整 PWM 波的占空比即可调整被控制电路中的平均电流。
而除了调整 PWM 信号的占空比, PWM 信号的周期也是可以调整的,例如,在逆变电路中,使用 IGBT 作为开关器件,常见开关频率为几 K 到几十 K,而使用 MOS 管作为开关器件,其开关频率则可高达几百 K。因此,对于不同的器件,对驱动信号的频率要求也不一样,还需要能够对 PWM 波的频率进行调整。
通过以上分析,可以看出,要设计一个 PWM 波形,需要能够实现对信号的频率和占空比的调节。

1.4 音调与频率对应关系

首先对“哆来咪发梭拉西”7 个音调的频率找到对应值,具体见下表(分别为低音、中音和高音),频率的单位是Hz
表6-6- 1 音调与频率对应关系表
在这里插入图片描述

2 实验任务

本章将使用的蜂鸣器电路,并使用 FPGA 来实现驱动无源蜂鸣器按照“哆来咪发梭拉西”7 个音调发声,每个音调保持 0.5s 自动跳到下一个音调。

3 硬件设计

3.1 原理图分析

在这里插入图片描述
图6-6- 3蜂鸣器控制电路原理图

在上述电路中,D9 起保护三极管的作用,当三极管突然截止时,无源蜂鸣器两端产生的瞬时感应电动势可以通过 D9 迅速释放掉,避免叠加到三极管集电极上从而击穿三极管; BEEP 端口接 FPGA 输出管脚,使用时只需要在 BEEP信号上输入 2~5KHz 的 PWM 波,就能驱动蜂鸣器按照既定的频率产生振动信号。

3.2 管脚映射表

表6-6- 2 管脚映射表
在这里插入图片描述

3.3 编写XDC约束文件

在这里插入图片描述

4 程序设计

为了让我们的代码能更好的重复利用,我们尽可能将代码按功能模块来进行划分,比如我们现在这个实验,可以划分成三个部份。

    1. 顶层模块(beep_top),用于例化各个功能模块
    1. 高低电平计数器产生模块(pwm_num_gen),用于每0.5s生成对应频率的高低电平计数,将该计数值输出给pwm模块
    1. PWM方波生成模块(pwm),根据高低电平计数值生成pwm波,驱动无源蜂鸣器。

4.1 顶层模块(beep_top)

4.1.1 模块框图

在这里插入图片描述
图6-6- 4 顶层模块框图
pwm_num_gen 模块生成 PWM 波的高电平计数值和低电平计数值以及计数值有效标志,传给 PWM 波生成模块(pwm)。

4.1.2 设计思路

在本实验中,顶层模块只用于例化各个功能模块,比较简单,此处不做讲解。

4.1.3 代码编写

限于篇幅,仅贴出部份代码(详见 Source 文件夹下 beep_top.v 文件)
定义模块端口,代码如下所示:
在这里插入图片描述

4.2高低电平计数器产生模块(pwm_num_gen)

4.2.1模块框图

在这里插入图片描述
图6-6- 5 高低电平计数器产生模块

  • 输入端口:
    clk:时钟信号,50Mhz,来源于晶振
    rst_n:复位信号,低电平复位,来源于按键
  • 输出端口:
    pwm_h_num:PWM波高电平计数值,传给PWM模块
    pwm_l_num:PWM波低电平计数值,传给PWM模块
    pwm_num_vld:PWM波计数值有效标志,高脉冲有效,传给PWM模块

4.2.2 设计思路

通过前面的学习,我们知道音调是受频率影响的,不同的频率产生的不同的音调,所以这里我们需产生七个不同的频率以发出七个音调,而占空比主要是对音调的音量有影响,这里占空比我们保持为 50% 即可。我们以中音D调为例,七个音调所对应的频率,如下表所示
表6-6- 3 音频与频率关系对应表
在这里插入图片描述
所以该实验我们只要循环产生占空比为 50%的七个音调频率即可。该模块产生对应频率的高低电平计数值。
我们以音调“Do”为例,该音调的频率为 294, 所以这里我们需输出频率为 294hz, 占空比为 50% 的 PWM 方波。
首先是音调的频率我们该如何产生?我们先计算该频率单个方波的时间: 1 / 294 ≈0.003401361s= 3401360ns; 而我们单个系统时钟(50MHz) 的时间为:1 / 50000000 =0.00000002s = 20ns; 所以我们需用:3401360/ 20 ≈ 170068 个系统时钟去产生一个 PWM波,该 PWM 波形的频率即为 294。占空比为 50% 的 PWM 方波,那么高电平和低电平的时间是一样的,即为 170068 / 2 = 85034 个系统时钟。
根据实验任务,每 0.5s 我们更新高低电平的计数值,同时产生一个高低电平计数值的有效标志。第一个 0.5s 我们将频率 294Hz 对应的高低电平计数值赋值给输出端口;第二个 0.5s 我们将频率 330Hz 对应的高低电平计数值赋值给输出端口…第六个 0.5s 我们将频率 556Hz 对应的高低电平计数值赋值给输出端口;依次循环,我们可以画出一个大概的波形图,如下所示:
在这里插入图片描述
图6-6- 6 高低电平计数器模块波形图

4.2.3 代码编写

限于篇幅,仅贴出部份代码(详见 Source 文件夹下 pwm_num_gen.v 文件)
定义模块端口,代码如下所示:
在这里插入图片描述
通过 parameter 语句,定义了 0.5s 所包含的时钟个数,同时还定义了不同频率的 PWM 方波一个周期的时钟个数,代码如下所示:
在这里插入图片描述
定义了一个 switch_cnt 寄存器,用于表示 7 个音调,每 0.5 秒 switch_cnt 进行加 1,加到 6 后再置为 0,在 0~6 之间循环。代码如下所示:在这里插入图片描述
定义一个 pwm_num 表示 PWM 方波一个周期包含的时钟个数,再根据 switch_cnt 的值,给 pwm_num 赋值,注意代码第 68 行,为了保证 case 语句的完整,一定要加上 default ,即使 default 这个语句在目前代码没有任务功能,也需要加上。代码如下所示:在这里插入图片描述
由于这个模块是需要输出高电平和低电平所包含的时钟个数,所以我们还需要用一个除以 2 的运算来得到这两个值。
在 Verilog 中,我们可以有很多办法来实现除以 2 操作。但是笔者认为用移位拼接的方式是最贴近 FPGA 的方式,代码如下:
在这里插入图片描述

4.3 PWM方波生成模块(pwm)

4.3.1 模块框图


图6-6- 7 PWM方波生成模块

4.3.2 设计思路

该模块定义了两个端口,高电包含时钟个数 pwm_h_num 和低电平包含时钟个pwm_l_num,根据这两个端口,我们知道一个PWM周期所包含的时钟个数为pwm_h_num + pwm_l_num。然后通过一个计数器 pwm_cnt,该计数器在0~pwm_h_num + pwm_l_num - 1之间一直循环,pwm方波就是判断 pwm_cnt 的值,当小于pmw_h_num -1 时置为高电平,否则置为低电平,如此就生成了一个我们想要的PWM方波。

4.3.3 代码编写

限于篇幅,仅贴出部份代码(详见 Source 文件夹下 pwm.v 文件)
定义模块端口,代码如下所示:
在这里插入图片描述
定义了一个pwm_cnt计数器,该计数器在0~pwm_h_num + pwm_l_num - 1之间一直循环。为什么要减 1 呢?这是因为我们是从 0 开始计数的。
同时还要在时钟个数有效标志(pwm_num_vld)等于1时,将 pwm_cnt 清零,此处为什么要这样处理呢?大家想一下,因为我们的 pwm_cnt 是一直在计数,同时pwm_h_num,pwm_l_num的值也在随着每个0.5秒在变化。那么有没有一种可能,当switch_cnt等于1时,pwm_cnt的计数值已经超过了它本应计数的最大值(151515),这样pwm_cnt就会一直计数,直到溢出,再重新从0开始,波形如图所示,虽然在我们这个实验,这个问题不会对我们的实际效果产生影响,但是这的确是一个容易出问题的点,笔者仅仅抛砖引玉,希望大家在做项目的时候做一个有心人。
在这里插入图片描述
图6-6- 8 PWM波生成模块波形图
代码如下所示:
在这里插入图片描述
接下来通过判断计数器pwm_cnt的值,给pwm_out信号赋值,生成一个pwm方波,代码如下所示:
在这里插入图片描述

5 仿真验证

5.1 顶层模块(beep_top)模块仿真验证

5.1.1 仿真激励代码编写

由于在前面章节我们已经把仿真脚本写好了,这一章我们只用将 Sim 这个文件夹拷贝到我们当前课程文件夹中,文件结构如下所示:
在这里插入图片描述
图6-6- 9 文件结构

打开Sim文件夹,将“tb_led_shark.v”文件改为“tb_beep_top.v”,然后使用“Notepad++”工具打开“tb_beep_top.v”文件,就可以开始编写仿真代码了。限于篇幅,仅贴出部份代码,详见(Sim文件夹tb_beep_top.v文件)
在这里插入图片描述
为了节约仿真时间,我们在仿真文件中重新定义了 pwm_num_gen 模块中的参数,同比缩小 100 倍,代码如下所示:
在这里插入图片描述

5.1.2 批处理仿真

仿真代码编写好,就可以使用批处理仿真了,在该章节我们可以不用再更改 modelsim.bat文件。sim.do 文件也仅仅只用修改一处地方,如下图所示:
在这里插入图片描述
此处改为我们当前的仿真代码模块名:tb_beep_top,改好以后,保存。
双击 modelsim.bat,我们就不管了,先喝茶,等软件自已跑(具体步骤参考前一章节)

5.1.3 仿真波形分析

我们先看pwm_num_gen模块,不同的switch_cnt值对应不同的pwm_num,pwm_h_cnt 和pwm_l_cnt 等于pwm_num的一半,与设计相符,仿真波形如下所示:
在这里插入图片描述
图6-6- 10 仿真波形1
接着我们观察pwm模块的仿真,小于等于 pwm_h_num -1 (849)时 pwm 输出高电平,大于 849 时输出低电平,与设计相符。仿真波形如下:
在这里插入图片描述
图6-6- 11仿真波形2
再看看 PWM 整体仿真,可以看到 pwm_out 输出的是占空比 50% 的方波,与设计相符,仿真波形如下:
在这里插入图片描述
图6-6- 12 仿真波形3

6 综合编译

在前面我们已经将Source里面的源码(xx.v)和约束文件(pin.xdc)通过notepad++ 软件编辑好了,并且通过Modelsim进行了功能仿真,接下来我们新建Vivado工程并生成bit文件。具体步骤见《6-1 LED灯闪烁实验》,此处不再赘述。

7 下载验证

程序下载进去后,可以听到“哆来咪发梭拉西”7 个音调发声,每个音调保持0.5s自动跳到下一个音调。


http://www.kler.cn/a/488618.html

相关文章:

  • 深入理解 Python 的多进程编程 (Multiprocessing)
  • 预训练语言模型——BERT
  • android源码编译后,为什么emulator一直黑屏或者停止android界面
  • 【面试题】技术场景 4、负责项目时遇到的棘手问题及解决方法
  • 详解Sonar与Jenkins 的集成使用!
  • web服务器快速目录搜索遍历工具推荐:Dirsearch
  • 解释器模式详解
  • 力扣面试题 08.09. 括号 C语言解法 回溯递归动态规划字符串
  • 当Elasticsearch索引数据量过多时,可以采取以下措施进行优化和部署
  • Django后端相应类设计
  • Flask----前后端不分离-登录
  • mysql实现对字符列第一个汉字首字母拼音进行A-Z顺序排序,使用gbk编码
  • 计算机网络之---静态路由与动态路由
  • 图像分类、目标定位与目标检测的区别详解:定义、工作原理、应用场景
  • 车联网安全--TLS握手过程详解
  • php命名空间
  • 运维安全中心(堡垒机)
  • Ubuntu 22.04 桥接配置
  • Clisoft SOS设置Server和Project
  • 【JAVA面试】自动装箱和自动拆箱
  • c++程序设计(第3版)系列教程
  • rk3568平台Buildroot编译实践:内核rootfs定制 及常见编译问题
  • 【模型训练】在AutoDL上使用LLamaFactory进行模型训练
  • 思维转换:突破思维桎梏,创造更高效的工作与生活
  • MPI 在深度学习中的应用与分布式训练优化
  • VS2015 + OpenCV + OnnxRuntime-Cpp + YOLOv8 部署