一、蜂鸣器
1、什么是蜂鸣器
蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型;蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器的内部装有集成电路,不需要音频驱动电路,只需要接通直流电源就能直接发出声响;而无源蜂鸣器只有外加音频驱动信号才能发出声响。
2、无源蜂鸣器原理
无源蜂鸣器与有源蜂鸣器不同,因其内部不带震荡源,所以其无法像有源蜂鸣器那样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。
输入不同频率和占空比的PWM方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。
文章图片
【FPGA学习|15无源蜂鸣器】二、实现
目标:实现七个音调的循环发声,每个音调发声五秒,占空比50%
例如:DO的频率时262Hz,其计数周期为0~19084之间循环计数
文章图片
同理,其余的也是这样,其表格如下,占空比对音量的大小有关系,我们要求的是50%,因此其计数值时音调分频计数值的一半
文章图片
1.波形图
文章图片
2.程序
module beep
#(
parameterCNT_MAX = 25'd24999999,
parameterDO= 18'd190839,//"哆"音调分频计数值(频率262)
parameterRE= 18'd170067,//"来"音调分频计数值(频率294)
parameterMI= 18'd151514,//"咪"音调分频计数值(频率330)
parameterFA= 18'd143265,//"发"音调分频计数值(频率349)
parameterSO= 18'd127550,//"梭"音调分频计数值(频率392)
parameterLA= 18'd113635,//"拉"音调分频计数值(频率440)
parameterSI= 18'd101213 //"西"音调分频计数值(频率494))(
inputwiresys_clk,
inputwiresys_rst_n,outputregbeep
);
reg[24:0]cnt;
//0.5s计数器
reg[2:0]cnt_500ms;
//0.5s个数计数
reg[17:0]fre_cnt;
//音调计数器
reg[17:0]fre_data;
//音调分频计数值
wire[16:0]duty_data;
//占空比计数值//cnt:0.5s循环计数器
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == CNT_MAX)
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
//cnt_500ms:对500ms个数进行计数,每个音阶鸣叫时间0.5s,7个音节一循环
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt_500ms <= 3'd0;
else if ((cnt_500ms == 3'd6)&&(cnt == CNT_MAX))
cnt_500ms <= 3'd0;
else if (cnt == CNT_MAX)
cnt_500ms <= cnt_500ms + 1'b1;
else
cnt_500ms <= cnt_500ms;
/*fre_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数
与下面的方式一样能够实现其功能,此方法比较复杂,只供参考*/
/* always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
fre_cnt <= 18'd0;
elsecase (cnt_500ms)
3'd0:if ((fre_cnt == DO)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd1:if ((fre_cnt == RE)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd2:if ((fre_cnt == MI)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd3:if ((fre_cnt == FA)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd4:if ((fre_cnt == SO)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd5:if ((fre_cnt == LA)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
3'd6:if ((fre_cnt == SI)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +18'd1;
default:fre_cnt <= 18'd0;
endcase */ //fre_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
fre_cnt <= 18'd0;
else if ((fre_cnt == fre_data)||(cnt == CNT_MAX))
fre_cnt <= 18'd0;
else
fre_cnt <= fre_cnt +1'b1;
//不同时间鸣叫不同的音阶
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
fre_data <= DO;
elsecase (cnt_500ms)
3'd0: fre_data <= DO;
3'd1: fre_data <= RE;
3'd2: fre_data <= MI;
3'd3: fre_data <= FA;
3'd4: fre_data <= SO;
3'd5: fre_data <= LA;
3'd6: fre_data <= SI;
default: fre_data <= DO;
endcase//设置50%占空比:音阶分频计数值的一半即为占空比的高电平数
assign duty_data = https://www.it610.com/article/fre_data>> 1;
//beep:输出蜂鸣器波形
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
beep <= 1'b0;
else if (duty_data >= fre_cnt)
beep <= 1'b1;
else if (duty_data < fre_cnt)
beep <= 1'b0;
else
beep <= beep;
endmodule
3、仿真程序
`timescale1ns/1ns
moduletb_beep();
regsys_clk;
//时钟
regsys_rst_n;
//复位//对时钟,复位信号赋初值
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
#100
sys_rst_n<=1'b1;
end//产生时钟信号
always #10 sys_clk =~sys_clk;
beep
#(
.CNT_MAX(25'd24999),//0.5s计数值
.DO(18'd190),//"哆"音调分频计数值(频率262)
.RE(18'd170),//"来"音调分频计数值(频率294)
.MI(18'd151),//"咪"音调分频计数值(频率330)
.FA(18'd143),//"发"音调分频计数值(频率349)
.SO(18'd127),//"梭"音调分频计数值(频率392)
.LA(18'd113),//"拉"音调分频计数值(频率440)
.SI(18'd101)//"西"音调分频计数值(频率494)
)
beep_inst
(
.sys_clk(sys_clk),//系统时钟,频率50MHz
.sys_rst_n(sys_rst_n ),//系统复位,低有效.beep(beep)//输出蜂鸣器控制信号
);
endmodule
推荐阅读
- 电子设计大赛|2021年全国大学生电子设计大赛F题——智能送药小车,全方位解决方案+程序代码(详细注释)山东赛区国奖
- 硬件|硬件篇(教你做STM32蓝牙小车(基于STM32F103ZET6))
- K210|亚博智能K210开发板学习笔记(二)——GPIO
- 单片机|c语言回调函数的使用及实际作用详解
- stm32|基于STM32的智能门禁卡片(开题报告)
- K210|亚博智能K210开发板学习笔记
- 单片机|STM32CUBEMX生成freeRTOS代码的时候出现警告
- 单片机|STM32CUBEMX(3)--ADC通过DMA方式采样,USART打印
- #应广单片机|应广PMS154C(1)--11位PWM输出