无源蜂鸣器beep
有源/无源蜂鸣器
无源这里的“源”不是指电源,而是指震荡源。也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。
无源蜂鸣器的优点是:1、便宜;2、声音频率可控,可以做出“多来米发索拉西”的效果;3、在一些特例中,可以和LED复用一个控制口。
有源蜂鸣器的优点是:程序控制方便。
无源蜂鸣器的驱动原理
无源蜂鸣器因其内部不带震荡源,所以无法像有源蜂鸣器一样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。输入不同频率和占空比的PWM方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。
实验原理
实验目的:每隔0.5s实现音阶的循环发声
使用PWM的方式发出特定频率和占空比的信号,每隔0.5s转换音阶,也就是说在0.5s内产生同一个信号的固定频率和固定占空比信号。(实验仅实现占空比50%)
以音阶Do为例:262hz 一个时钟周期为1/262=3816794ns,系统时钟50Mhz,20ns。即一个时钟周期计数190840个,为实现50%占空比,计数将为一半即95420个。
实验框图与波形
首先由于实验目的为0.5s循环,所以计数器cnt计数最大值为24_999_999,并且设定计数器cnt_500ms进行7个音阶的计数实现循环并且控制计数器进行相应计数,在每个0.5s计数周期内设定计数器freq_cnt实现每个0.5s内的不同频率计数,再根据duty_data实现占空比的控制。
上述波形图的输出beep,不方便绘制全部音阶输出,以音阶Do为例具体分析:
其他音阶同理。
实验代码
module beep
#(
parameter CNT_MAX=25'd24_999_999,
DO =18'd190839,
RE =18'd170067,
MI =18'd151514,
FA =18'd143265,
SO =18'd127550,
LA =18'd113635,
XI =18'd101365
)
(
input wire sys_clk,
input wire sys_rst_n,
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 ;
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+25'd1;
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+3'd1;
else cnt_500ms<=cnt_500ms;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==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;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==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;//左移一位相当于x2,右移一位相当于/2
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
beep <=1'b0;
else if(freq_cnt>=duty_data)
beep<=1'b1;
else
beep<=1'b0;
endmodule
对于参数进行统一参数设定,无论是0.5s还是音阶都方便后期模块的更改和调用。
仿真代码
`timescale 1ns/1ns
module tb_beep();
reg sys_clk;
reg sys_rst_n;
initial
begin
sys_clk=1'b0;
sys_rst_n<=1'b0;
#20
sys_rst_n<=1'b1;
end
always #10 sys_clk=~sys_clk;
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'd10136)
)
beep_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.beep(beep)
);
endmodule