Verilog实现无源蜂鸣器发声

要求:顺序循环发声(Do、Re、Mi、Fa....),时间间隔为0.5s。

若输入为262Hz的方波,则蜂鸣器发Do的声音,以此类推。

那如何向蜂鸣器输入262Hz的方波?假设系统时钟周期为50MHz。

50MHz对应的一个周期为20ns,若占空比为50%,则每10ns电平反转一次。

则50MHz实现0.5s需要从0开始计数到24_999_999。

由于50MHz计数器是上升沿记一次数,262Hz对应的一个周期为3816794ns,则其计数周期为3816794ns/20ns=190840ns,若占空比为50%,则每95420ns电平反转一次。如下表格所示

关于系统的输入输出如下图所示

 

根据输入输出可以判断:

第一,需要一个计数器cnt,实现0.5s的功能,从0开始计数到24_999_999;

第二,因为每0.5s发出的声音需要变换一次,总共7个音,即cnt每次计数满0.5s需要自加一,并且记满7个音从0开始计数。

第三,每个音频(Do、Re、Mi、Fa....)有一个一个确定的值freq_data,还需要freq_cnt,从0开始计数到freq_data。

第四,占空比为50%,则当计数机器freq_cnt计数到(freq_data/2)时,电平需要反转一次。

另外,在每0.5s内,需要不断地发出Do的声音,波形图如下:

所以通过上述整体的分析可以整体波形图如下

 

Verilog代码如下:

module beep
#(
	parameter CNT_MAX=25'd24_999_999,
	parameter DO=18'd190839,
	parameter RE=18'd170067,
	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_cnt;
	reg [17:0]freq_data;
	wire [16:0]duty_data;
	
always@(posedge sys_clk or negedge sys_rst_n)//0.5s的计数器
	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)//每经过0.5s自加1
	if(sys_rst_n==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;
		
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
	
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;

assign duty_data=freq_data>>1;//右移一位相当于除以2
		
always@(posedge sys_clk or negedge sys_rst_n)//经过一个duty_data电平反转一次
	if(sys_rst_n==1'b0)
		beep<=1'b0;
	else if(freq_cnt<duty_data)
		beep<=1'b0;
	else
		beep<=1'b1;
		
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_999),//仿真数值都缩小了1000倍进行仿真
.DO(18'd190),
.RE(18'd170),
.MI(18'd151),
.FA(18'd143),
.SO(18'd127),
.LA(18'd113),
.XI(18'd101)
    )
beep_inst	
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.beep(beep)
);

endmodule

 vivado仿真波形

第一个音DO,50%占空比。

计数到24999时转换为下一个音,且下一个音占空比为50%

 

 

 当第六个音记满,开始循环发声

 

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值