FPGA入门-无源蜂鸣器驱动

发布时间:2026/9/17 8:47:00
FPGA入门-无源蜂鸣器驱动 18. 无源蜂鸣器驱动实验蜂鸣器是一种一体化结构的电子讯响器因其体积小、重量轻、价格低、结构牢靠而广泛应用于报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。本章节将详细介绍如何使用按键去控制蜂鸣器发声相信大家通过本章的学习将会对蜂鸣器以及生活中带有蜂鸣器的电子器件的发声原理会有更深层次的了解。18.1. 理论学习18.1.1. 蜂鸣器简介蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型。电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳组成。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器以及共鸣箱、外壳等组成。压电式蜂鸣器是以压电陶瓷的压电效应来带动金属片的振动而发声而电磁式蜂鸣器则是用电磁的原理通电时将金属振动 膜吸下不通电时以振动膜的弹力弹回。由于两种蜂鸣器发声原理不同电压式结构简单耐用但音调单一、音色差适用于报警器等设备而电磁式由于音色好所以多用于语音、音乐等设备。蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器的内部装有集成电路不需要音频驱动电路只需要接通直流电源就能直接发出声响。而无源蜂鸣器只有外加音频驱动信号才能发出声响。图 24‑1 蜂鸣器左为有源蜂鸣器右为无源蜂鸣器表格 24‑1 有源和无源蜂鸣器的区别区别有源蜂鸣器无源蜂鸣器外形高度高低引脚部位黑胶封闭绿色电路板电压高低响声连续发声响一次停一次由图 24‑1和表格 24‑1所示我们能比较清晰的认识到有源蜂鸣器和无源蜂鸣器的差别同时能具有判断其为有源或是无源蜂鸣器的能力。相对于有源蜂鸣器无源蜂鸣器的成本更低声音频率可控。而有源蜂鸣器因其内部自带振荡源只要加上适当的直流电源即可发声程序控制较为方便。我们征途FPGA开发板上使用的是无源蜂鸣器所以这里为大家介绍无源蜂鸣器的驱动方式。18.1.2. 无源蜂鸣器驱动原理无源蜂鸣器与有缘蜂鸣器不同因其内部不带震荡源所以其无法向有缘蜂鸣器那样直接用直流信号驱动这里需要使用PWM方波才能驱动其发声。如何发出不同的声音呢上面说到需要使用PWM方波才能驱动其发声所以这里我们只要控制输入的PWM方波输入不同的PWM方波发出的声音就不一样了。而不同频率和占空比的方波发出的声音是不同的其中频率对音调有影响占空比对音量大小有影响。所以我们只需产生不同频率和占空比的PWM方波去驱动无源蜂鸣器就能让 无源蜂鸣器发出不同的音调了。图 24‑2 频率、占空比示意图如图 24‑2为不同频率不同占空比的PWM波形图。从图中可以看到不同频率的波形其单位波形所占时间不同不同占空比的波形其高电平在单位波形的的占用比例不同。所以我们以此为根据就能很容易的产生不同频率以及占空比的PWM波了具体的产生方法将在实战演练为大家讲解。18.2. 实战演练在上一小节中我们对蜂鸣器以及如何驱动无源蜂鸣器做了相关的介绍这一小节我们将从模块设计、绘制波形图、逻辑关系、代码编写、仿真以及测试一步一步的完成这个实验。18.2.1. 实验目标实验目标本次实验我们驱动无源蜂鸣器进行七个基本音调“哆来咪发梭拉西”的循环鸣叫每个音阶持续鸣叫0.5s后鸣叫下一个音阶。18.2.2. 硬件资源我们使用开发板上的无源蜂鸣器去进行该实验的验证如图 24‑3所示。图 24‑3 硬件资源由原理图可知我们只要在BEEP端输入PWM波即可驱动无源蜂鸣器进行鸣叫了。如图 24‑4所示。图 24‑4 无源蜂鸣器原理图18.2.3. 程序设计硬件资源介绍完毕我们开始实验工程的程序设计。在本小节我们将从模块框图波形图设计等进行讲解。18.2.3.1. 模块框图从实验目标我们知道我们需鸣叫七个音调而音调是受频率影响的不同的频率产生的音调即不同所以这里我们需产生七个不同的频率以发出七个音调而占空比主要是对音调的音量有影响这里占空比我们保持为50%即可。七个音调所对应的频率如表格 24‑2所示。表格 24‑2 七个基本音调对应频率表音调1Do2Re3Mi4Fa5So6La7Si频率262294330349392440494所以该实验我们只要循环产生占空比为50的七个音调频率即可这里我们使用一个模块即可实现模块框图如图 24‑5所示。图 24‑5 蜂鸣器模块框图在输入端我们只需要接入时钟和复位即可输出端我们输出命名为beep的PWM波进行对无源蜂鸣器的驱动模块各信号描述如表格 24‑3所示。表格 24‑3 蜂鸣器输入输出信号描述信号位宽类型功能描述sys_clk1bitInput工作时钟频率50MHzsys_rst_n1bitInput复位信号低电平有效beep1bitOutput输出控制蜂鸣器18.2.3.2. 波形图绘制通过前面讲解我们知道我们需要循环产生七个不同的频率所以这里我们使用一个计数器对不同频率进行计数每个频率计一个值。这样我们就能根据计数值来判断我们该产生什么频率的波形了。波形图如图 24‑6所示图 24‑6 蜂鸣器鸣叫波形图设计由图 24‑6所示cnt_500ms该信号我们定义为蜂鸣器的鸣叫状态计数。由于我们需鸣叫七个音调所以我们需要计7个数0~6而每个音调的鸣叫时间即计数值的持续时间。所以这里我们需要用一个鸣叫持续时间计数器去控制蜂鸣器各音调的鸣叫持续时间。cnt蜂鸣器各音调鸣叫持续时间计数器。在“计数器”章节我们详细的介绍了该如何用计数器进行时间计数这里就不详细的介绍了。本次实验我们设计让每个音调持续鸣叫0.5s故这里我们计数到249999990.5s时让鸣叫状态计数器加1。当最后一个音调cnt_500ms 3’d6鸣叫了0.5s时我们让状态计数器跳转回第一个音调鸣叫状态cnt_500ms 3’d0以此循环我们就能实现蜂鸣器七个基本音调的循环鸣叫了。上面我们讲述了蜂鸣器七个音调的循环鸣叫控制那每一个音调是如何控制他发出我们所需要的的声音的呢下面根据波形图为大家详细讲解如图 24‑7所示图 24‑7 “Do”音调PWM波产生波形图由实验目标可知刚开始我们是鸣叫音调“Do”该音调的频率为262所以这里我们需输出频率为262占空比为50%的PWM方波。首先是音调的频率我们该如何产生我们先计算该频率单个方波的时间1 / 262 ≈ 0.003816794s3816794ns而我们单个系统时钟50MHz的时间为1 / 50000000 0.00000002s 20ns所以我们需用3816794 / 20 ≈ 190840个系统时钟去产生一个PWM波该PWM波形的频率即为262。故我们需先对190840个系统时钟进行计数这里我们声明freq_cnt信号进行计数。freq_cnt音调计数器。我们使用该计数器进行计数当要鸣叫什么频率的音调我们就让计数器计到该音调所对应的音调分频计数器值即可。这里计数0~190839即为190840个系统时钟该计数范围内即为一个262频率波形。freq_data音调分频计数值。该信号我们用于定义各音调频率的计数值当我们需要鸣叫什么频率的值时我们就让该信号的值定义为该频率的计数值。如上图所示我们此时需要输出的PWM波形频率为262按上面所述的计算方法计数值即为190839。duty_data占空比计数值。通过改变该值我们可改变PWM波的占空比。前面说到我们是产生占空比为50%的波形即高电平时间所占信号周期的百分比为50%。信号周期为190840话50%占空比的高电平持续时间即为信号周期的一半即为95420。beep输出控制蜂鸣器信号该信号即为我们前面说的PWM方波。当我们需要输出频率为262时我们需要产生波形的一个方波时间为190840个系统时钟而高电平的持续时间即为95420,所以如上波形图所示当音阶计数器freq_cnt中的值大于等于占空比计数值时我们将beep信号输出高电平小 于时输出低电平这样我们输出的信号即为频率为262占空比为50%的PWM波了我们将该信号接入到驱动蜂鸣器的I/O引脚即能驱动蜂鸣器发出“Do”的音调。以上就是“Do”音调的输出PWM波产生方式其余音调的产生方式是一样的我们只要改变freq_data与duty_data的值就能产生不同频率的PWM波了本次实验所需产生的频率相对应的freq_data和duty_data的值如表格 24‑4所示表格 24‑4 频率对应表频率/Hz音调分频计数值freq_data占空比计数值duty_data26219084095420294170068850343301515157575734914326671633392127551637754401136365681849410121450607我们根据上面的频率对照表我们可画出“Re”音调的波形图如图 24‑8所示图 24‑8 “Re”音调PWM波产生波形图如上图所示我们只需改变“freq_data”与“duty_data”的值就能产生相应的频率的PWM波形后面音调的波形产生也是如此这里就不再一一讲解了下面我们看看代码需如何实现的吧。18.2.3.3. 代码编写当波形图绘制完成之后参照绘制波形图的时序逻辑关系我们可以较快的编写完模块代码。各模块的代码如下所示代码清单 24‑1 无源蜂鸣器驱动模块beep.vmodule beep #( parameter TIME_500MS 25d24999999, //0.5s计数值 parameter DO 18d190839 , //哆音调分频计数值频率262 parameter RE 18d170067 , //来音调分频计数值频率294 parameter MI 18d151514 , //咪音调分频计数值频率330 parameter FA 18d143265 , //发音调分频计数值频率349 parameter SO 18d127550 , //梭音调分频计数值频率392 parameter LA 18d113635 , //拉音调分频计数值频率440 parameter XI 18d101214 //西音调分频计数值频率494 ) ( input wire sys_clk , //系统时钟,频率50MHz input wire sys_rst_n , //系统复位低有效 output reg beep //输出蜂鸣器控制信号 ); //// //\* Parameter and Internal Signal \// //// //reg define reg [24:0] cnt ; //0.5s计数器 reg [17:0] freq_cnt ; //音调计数器 reg [2:0] cnt_500ms ; //0.5s个数计数 reg [17:0] freq_data ; //音调分频计数值 //wire define wire [16:0] duty_data ; //占空比计数值 //// //\* Main Code \// //// //设置50占空比音阶分频计数值的一半即为占空比的高电平数 assign duty_data freq_data 1b1; //cnt:0.5s循环计数器 always(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n 1b0) cnt 25d0; else if(cnt TIME_500MS ) cnt 25d0; else cnt cnt 1b1; //cnt_500ms对500ms个数进行计数每个音阶鸣叫时间0.5s7个音节一循环 always(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n 1b0) cnt_500ms 3d0; else if(cnt TIME_500MS cnt_500ms 6) cnt_500ms 3d0; else if(cnt TIME_500MS) cnt_500ms cnt_500ms 1b1; //不同时间鸣叫不同的音阶 always(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n 1b0) freq_data DO; else case(cnt_500ms) 0: freq_data DO; 1: freq_data RE; 2: freq_data MI; 3: freq_data FA; 4: freq_data SO; 5: freq_data LA; 6: freq_data XI; default: freq_data DO; endcase //freq_cnt当计数到音阶计数值或跳转到下一音阶时开始重新计数 always(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n 1b0) freq_cnt 18d0; else if(freq_cnt freq_data \|\| cnt TIME_500MS) freq_cnt 18d0; else freq_cnt freq_cnt 1b1; //beep输出蜂鸣器波形 always(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n 1b0) beep 1b0; else if(freq_cnt duty_data) beep 1b1; else beep 1b0; endmodule代码是根据波形图设计进行编写的这里我们只对部分代码做个简单的说明。代码4~10行定义了各音调分频的计数值。代码38行是对占空比计数值duty_data的赋值前面我们说到实现的是50%的占空比所以数值是freq_data的一半这里我们将freq_data向右移动一位以实现freq_data/2的计算18.2.3.4. 仿真验证仿真代码编写当我们代码都写完了之后我们可以编写仿真代码对其进行仿真可以验证我们的代码是否能实现我们的功能。代码清单 24‑2 无源蜂鸣器驱动仿真文件tb_beep.v\timescale 1ns/1ns module tb_beep(); //// //\* Parameter and Internal Signal \// //// //reg define reg sys_clk ; //时钟 reg sys_rst_n ; //复位 //// //\* Main Code \// //// //对时钟复位信号赋初值 initial begin sys_clk 1b1; sys_rst_n 1b0; #100 sys_rst_n 1b1; end //产生时钟信号 always #10 sys_clk ~sys_clk; //// //\* Instantiation \// //// beep #( .TIME_500MS(25d24999), //0.5s计数值 .DO (18d190 ), //哆音调分频计数值频率262 .RE (18d170 ), //来音调分频计数值频率294 .MI (18d151 ), //咪音调分频计数值频率330 .FA (18d143 ), //发音调分频计数值频率349 .SO (18d127 ), //梭音调分频计数值频率392 .LA (18d113 ), //拉音调分频计数值频率440 .XI (18d101 ) //西音调分频计数值频率494 ) beep_inst ( .sys_clk (sys_clk ), //系统时钟,频率50MHz .sys_rst_n (sys_rst_n ), //系统复位低有效 .beep (beep ) //输出蜂鸣器控制信号 ); endmodule仿真文件第34~41行我们对各参数重新定义了数值这样可缩短仿真时间。仿真波形分析配置好仿真文件使用ModelSim对参考代码进行仿真仿真结果如下。图 24‑9 无源蜂鸣器仿真波形图如图 24‑9所示我们抓取的是“Do”音调和“Re”音调的波形图由于我们仿真时把各参数缩小了约1000倍所以其单位波形的时间也缩小了约1000倍而前面说到“Do”音调的单位方波持续时间为3816794ns这里将时间缩小1000倍为3816ns与上述抓取的单位波形持续时间几乎一致说明我们 的设计正确。18.3. 上板调试18.3.1. 引脚约束仿真验证通过后准备上板验证上板验证之前先要进行引脚约束。工程中各输入输出信号与开发板引脚对应关系如表格 24‑5所示。表格 24‑5 引脚分配表信号名信号类型对应引脚备注sys_clkinputE1时钟sys_rst_ninputM15复位beepoutputJ11蜂鸣器下面进行管脚分配管脚的分配方法在前面章节已有所讲解在此就不再过多叙述管脚的分配如下图 24‑10所示。图 24‑10 管脚分配18.3.1.1. 结果验证管脚配置完成之后重新进行编译编译完之后就可以进行下载验证了在下载之前首先将电源与下载线与开发板连接好连接好之后上电如图 24‑11所示。图 24‑11 下载连线图打开下载界面后当检测到下载器USB-Blaster已连接之后即可点击“Add File…”添加sof文件添加好后点击“start”开始下载随后界面会显示下载成功如图 24‑12所示。图 24‑12 下载成功界面下载成功后蜂鸣器会循环鸣叫“哆来咪发梭拉西”音调。18.4. 章末总结到这里本章节讲解完毕通过本章节的学习相信读者对于蜂鸣器以及控制无源蜂鸣器都能较为熟练的掌握。18.5. 拓展训练实验要求我们加个按键控制模块用按键进行对无源蜂鸣器的鸣叫状态。