无源蜂鸣器驱动实验

知识点

        蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型;蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器。

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

        无源蜂鸣器与有源蜂鸣器不同,因其内部不带震荡源,所以其无法像有源蜂鸣器那样直接用直流信号驱动,这里需要使用PWM方波才能驱动其发声。输入不同频率和占空比的PWM方波发出的声音是不同的,其中频率对音调有影响,占空比对音量大小有影响。

实验内容

        驱动FPGA开发板上的无源蜂鸣器,使蜂鸣器依次输出Do、Re、Mi、Fa、So、La、Si七个音调,每个音调持续时间为0.5s,占空比为50%。

 波形分析

        输入信号有时钟,复位信号,输出不同频率信号beep。

        中间变量有计数器cnt,初值为0,计数最大值为50_000_000/2-1=2.5*10^7-1=24_999_999。计数到最大值就归零,然后开始下一个周期的计数。

        另外声明一个中间变量cnt_500ms,初值为0,实现对0.5s的计数,当cnt完成一个0.5s计数时,即cnt等于24_999_999,cnt_500ms就自加1,cnt_500ms最大值为6,完成7个周期的计数后,就归零。

        由于不同音调对应的频率不同,所以这里要用到分频计数器,中间变量分频计数器freq_cnt,初值为0,音调1(Do)对应频率为262Hz,而系统时钟对应的是50MHz,50_000_000 / 262 = 190840,所以262Hz对应的计数器的最大值为190840-1=190839,所以freq_cnt最大值为190839,其余音调所对应的频率最大值如下表所示:

在这里插入图片描述

        为了控制清零条件,需要利用中间变量freq_data,当freq_cnt计数到190839过程,让freq_data 保持190839,从而实现了0.5s的1(Do)音调,当freq_cnt计数到170067过程,让freq_data保持170067,从而实现了0.5s的2(Re)音调,当freq_cnt计数到151514过程,让freq_data保持151514,从而实现了0.5s的3(Mi)音调,当freq_cnt计数到143265过程,让freq_data保持1143265,从而实现了0.5s的4(Fa)音调,当freq_cnt计数到127550过程,让freq_data保持127550,从而实现了0.5s的5(So)音调,当freq_cnt计数到113635过程,让freq_data保持113635,从而实现了0.5s的6(La)音调,当freq_cnt计数到101213过程,让freq_data保持101213,从而实现了0.5s的7(Si)音调。

        再申明一个占空比计数值,使用该变量来控制占空比duty_data,其数值等于freq_data的一半。当freq_data计数值大于duty_data计数值时,输出信号beep拉高,保持高电平,如下图所示:

 代码

module beep
#(
	parameter CNT_MAX =  25'd24_999_999,
	parameter	DO	=	18'd190839,
	parameter	RE  =	18'd170076,
	parameter	MI  =	18'd151514,
	parameter	FA  =	18'd143265,
	parameter	SO  =	18'd127550,
	parameter	LA  =	18'd113635,
	parameter	XI  =	18'd101213
) 
(
	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_data;
reg [17:0] freq_cnt;
wire [16:0] duty_data;

always @(posedge sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		cnt <= 25'd0;
	else if(cnt == CNT_MAX)
		cnt <= 25'd0;
	else
		cnt <= cnt + 1'b1;
end

always @(posedge sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		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 + 1'b1;
	else 
		cnt_500ms <= cnt_500ms;
end

always @(posedge sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		freq_cnt <= 18'd0;
	else if((freq_cnt == freq_data)||(cnt == CNT_MAX))
		freq_cnt <= 18'd0;
	else 
		freq_cnt <= freq_cnt + 1'b1;
end

always @(posedge sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		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
end

assign duty_data = freq_data >> 1;

always @(posedge sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		beep <= 1'b0;
	else if(freq_data >= duty_data)
		beep <= 1'b1;
	else 
		beep <= 1'b0;
end
		
endmodule
`timescale 1ns/1ns
module tb_beep();

reg sys_clk;
reg sys_rst_n;
wire beep;

initial 
	begin
		sys_clk = 1'b1;
		sys_rst_n <= 1'b0;
		#20
		sys_rst_n <= 1'b1;
	end
always #10 sys_clk <= ~sys_clk;

beep
#(
	.CNT_MAX (25'd24_99_999),
	.DO		 (18'd19083),
	.RE  	 (18'd17007),
	.MI  	 (18'd15151),
	.FA 	 (18'd14326),
	.SO 	 (18'd12755),
	.LA 	 (18'd11363),
	.XI 	 (18'd10121)
) 
beep_inst
(
	.sys_clk	(sys_clk),
	.sys_rst_n	(sys_rst_n),
	.beep       (beep)
);
endmodule

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发光中请勿扰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值