FPGA学习第2天--蜂鸣器实现歌曲《两只老虎》

蜂鸣器简介

蜂鸣器分类:
按照工作原理可分为:压电式蜂鸣器和电磁式蜂鸣器;
按照音源可分为:有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器:内部有振荡源,直接通以直流电即可发出声音;
无源蜂鸣器:内部无振荡源,需要通以方波、PWM信号才能发出声音。
无源蜂鸣器需要输入一定频率的方波或者PWM信号,蜂鸣器就可以发出声音。输入不同频率的信号,蜂鸣器可以发出不同音色的声音。
PWM:Pulse Width Modulation,脉冲宽度调制。
FPGA学习第2天--蜂鸣器实现歌曲《两只老虎》_第1张图片
FPGA学习第2天--蜂鸣器实现歌曲《两只老虎》_第2张图片
FPGA学习第2天--蜂鸣器实现歌曲《两只老虎》_第3张图片

module beep_tiger(
	input	wire	clk,
	input	wire	rst_n,
	
	output	reg		beep
);
//每个音符震动一次所占用的时钟周期
//1秒 / 频率 = 震动1次所用的时间
//震动1次所用的时间 / 20ns = 震动1次所用的周期
parameter	DO = 16'd47755,//(50_000_000 / 1047)
			RE = 16'd42553,
			MI = 16'd37907,
			FA = 16'd35790,
			SO = 16'd31887,
			LA = 16'd28409,
			SI = 16'd25419;
			
//单个音符持续最大时间的参数			
parameter	TIME_MAX = 26'd25_000_000 - 1;
			
//单个音符持续最大时间的寄存器,以1秒钟举例,50_000_000次的时钟周期
reg	[25:0]	note_cnt;	 //34个音符的寄存器
reg	[5:0]	music_data;  //音符的频率计数器(DO.RE.MI的频率计数器)frequency counter
reg	[15:0]	freq_cnt;	//至少要16个位宽 
						//所有音符频率的数据,存放整个乐谱
reg	[15:0]	freq_data;


//单个音符持续最大时间的计数器			
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		note_cnt <= 0;
	else if(note_cnt == TIME_MAX )
		note_cnt <= 0;
	else
		note_cnt <= note_cnt + 1;
end
					

//34个音符切换的计数器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		music_data <= 0;
	else if((music_data == 6'd33) && (note_cnt == TIME_MAX))
		music_data <= 0;
	else if(note_cnt == TIME_MAX)
		music_data <= music_data + 1;
	else
		music_data <= music_data;
end


//频率计数器						
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		freq_cnt <= 0;
	else if(freq_cnt == freq_data)
		freq_cnt <= 0;
	else
		freq_cnt <= freq_cnt + 1;
end

//所有音符频率的数据,按顺序排开,存放整个乐谱
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		freq_data <= DO;
	else
		case(music_data)
			6'd0  : freq_data <= DO;//1
			6'd1  : freq_data <= RE;//2
			6'd2  : freq_data <= MI;//3
			6'd3  : freq_data <= DO;//1
			6'd4  : freq_data <= DO;//1
			6'd5  : freq_data <= RE;//2
			6'd6  : freq_data <= MI;//3
			6'd7  : freq_data <= DO;//1
			6'd8  : freq_data <= MI;//3
			6'd9  : freq_data <= FA;//4
			6'd10 : freq_data <= SO;//5
			6'd11 : freq_data <= MI;//3
			6'd12 : freq_data <= FA;//4
			6'd13 : freq_data <= SO;//5
			6'd14 : freq_data <= SO;//5
			6'd15 : freq_data <= LA;//6
			6'd16 : freq_data <= SO;//5
			6'd17 : freq_data <= FA;//4
			6'd18 : freq_data <= MI;//3
			6'd19 : freq_data <= DO;//1
			6'd20 : freq_data <= SO;//5
			6'd21 : freq_data <= LA;//6
			6'd22 : freq_data <= SO;//5
			6'd23 : freq_data <= FA;//4
			6'd24 : freq_data <= MI;//3
			6'd25 : freq_data <= DO;//1
			6'd26 : freq_data <= RE;//2
			6'd27 : freq_data <= SO;//5
			6'd28 : freq_data <= DO;//1
			6'd29 : freq_data <= DO;//0/1
			6'd30 : freq_data <= RE;//2
			6'd31 : freq_data <= SO;//5
			6'd32 : freq_data <= DO;//1
			6'd33 : freq_data <= DO;//0/1
			default : freq_data <= DO;		
		endcase
end

//定义占空比
wire [14:0]	duty_data;

//assign duty_data = freq_data >> 1;//占空比50%
assign duty_data = freq_data >> 2;//占空比25%
//占空比小一点,蜂鸣器发出的声音会清晰一点

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		beep <= 0;
	else if(freq_cnt >= duty_data)
		beep <= 1;
	else
		beep <= 0;
end

endmodule

你可能感兴趣的:(学不可以已,fpga开发,学习,单片机)