2025年FPGA入门学习——无源蜂鸣器

FPGA入门学习——无源蜂鸣器无源蜂鸣器 理论学习 蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型 电磁式蜂鸣器由振荡器 电磁线圈 磁铁 振动膜片及外壳组成 压电式蜂鸣器主要由多谐振荡器 压电蜂鸣片 阻抗匹配器以及共鸣箱 外壳等组成 压电式蜂鸣器是以压电陶瓷的压电效应 来带动金属片的振动而发声 而电磁式蜂鸣器则是用电磁的原理 通电时将金属振动 膜吸下

大家好,我是讯享网,很高兴认识大家。

无源蜂鸣器

理论学习

蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型。电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳组成。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器以及共鸣箱、外壳等组成。压电式蜂鸣器是以压电陶瓷的压电效应,来带动金属片的振动而发声;而电磁式蜂鸣器则是用电磁的原理,通电时将金属振动 膜吸下,不通电时以振动膜的弹力弹回。由于两种蜂鸣器发声原理不同,电压式结构简单耐用但音调单一、音色差,适用于报警器等设备;而电磁式由于音色好,所以多用于语音、音乐等设备。

蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器的内部装有集成电路,不需要音频驱动电路,只需要接通直流电源就能直接发出声响。而无源蜂鸣器只有外加音频驱动信号才能发出声响。

无源蜂鸣器驱动原理

无源蜂鸣器与有缘蜂鸣器不同,因其内部不带震荡源,所以其无法向有缘蜂鸣器那样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。

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

实战演练

本次实验我们驱动无源蜂鸣器进行七个基本音调“哆来咪发梭拉西”的循环鸣叫,每个音阶持续鸣叫0.5s后鸣叫下一个音阶。


讯享网

程序框图

从实验目标我们知道,我们需鸣叫七个音调,而音调是受频率影响的,不同的频率产生的音调即不同,所以这里我们需产生七个不同的频率以发出七个音调,而占空比主要是对音调的音量有影响,这里占空比我们保持为50%即可。
在这里插入图片描述

波形图绘制

在这里插入图片描述
cnt:每个鸣叫保持0.5s,用来计数
cnt_500ms:当cnt计数到最大值时,cnt_500ms加1,用来控制蜂鸣器鸣叫状态
在这里插入图片描述
freq_cnt:音调计数器,用来控制每个鸣叫的频率

freq_data:音调分频计数值,该信号用于定义各音调频率的计数值,当我们需要鸣叫什么频率的值时,我们就让该信号的值定义为该频率的计数值。

duty_data:占空比计数值。通过改变该值可改变PWM波的占空比。

beep:输出控制蜂鸣器信号,该信号即为PWM方波。当我们需要输出频率为262时,我们需要产生波形的一个方波时间为个系统时钟,而高电平的持续时间即为95420,,所以如上波形图所示,当音阶计数器(freq_cnt)中的值大于等于占空比计数值时,我们将beep信号输出高电平,小于时输出低电平,这样我们输出的信号即为频率为262,占空比为50%的PWM波了,我们将该信号接入到驱动蜂鸣器的I/O引脚即能驱动蜂鸣器发出“Do”的音调。

代码编写

module beep #( parameter CNT_MAX = 25'd24_999_999, parameter DO = 18'd , //"哆"音调分频计数值(频率262) parameter RE = 18'd , //"来"音调分频计数值(频率294) parameter MI = 18'd , //"咪"音调分频计数值(频率330) parameter FA = 18'd , //"发"音调分频计数值(频率349) parameter SO = 18'd , //"梭"音调分频计数值(频率392) parameter LA = 18'd , //"拉"音调分频计数值(频率440) parameter XI = 18'd //"西"音调分频计数值(频率494) ) ( input clk,reset, output reg beep ); reg[24:0] cnt; reg[2:0] cnt_500ms; reg[17:0] freq_cnt; reg[17:0] freq_data; wire[16:0] duty_data; // cnt赋值 always @(posedge clk or negedge reset) if(reset == 1'b0) cnt <= 25'd0; else if(cnt == CNT_MAX) cnt <= 25'd0; else cnt <= cnt + 25'd1; // cnt_500ms赋值 always @(posedge clk or negedge reset) if(reset == 1'b0) cnt_500ms <= 3'd0; else if(cnt == CNT_MAX && cnt_500ms == 3'd6) cnt_500ms <= 3'd0; else if(cnt == CNT_MAX) cnt_500ms <= cnt_500ms + 3'd1; else cnt_500ms <= cnt_500ms; //freq_cnt赋值 always @(posedge clk or negedge reset) if(reset == 1'b0) freq_cnt <= 18'd0; else if(freq_cnt == freq_data || cnt == CNT_MAX) freq_cnt <= 18'd0; else freq_cnt <= freq_cnt + 18'd1; //freq_data赋值 always @(posedge clk or negedge reset) if(reset == 1'b0) freq_data <= DO; else case(cnt_500ms) 3'd0:freq_data <= DO; 3'd1:freq_data <= RE; 3'd2:freq_data <= MI; 3'd3:freq_data <= FA; 3'd4:freq_data <= SO; 3'd5:freq_data <= LA; 3'd6:freq_data <= XI; default:freq_data <= DO; endcase assign duty_data = freq_data >> 1; // 输出信号 always @(posedge clk or negedge reset) if(reset == 1'b0) beep <= 1'b0; else if(freq_cnt >= duty_data) beep <= 1'b1; else beep <= 1'b0; endmodule 

讯享网

仿真测试

讯享网`timescale 1 ns/ 1 ns module beep_vlg_tst(); // test vector input registers reg clk; reg reset; // wires wire beep; beep #( .CNT_MAX(25'd24_999_99), .DO(18'd19083) , .RE(18'd17006) , .MI(18'd15151) , .FA(18'd14326) , .SO(18'd12755) , .LA(18'd11363) , .XI(18'd10121) ) i1 ( .beep(beep), .clk(clk), .reset(reset) ); initial begin clk = 1'b1; reset <= 1'b0; #20 reset <= 1'b1; end always #10 clk = ~clk; endmodule 
小讯
上一篇 2025-02-26 13:44
下一篇 2025-02-25 17:13

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/71830.html