1.产生pwm模块,通过音乐乐谱,产生pwm
module gen_pwm(
input wire clk,//时钟信号
input wire rst_n,
output wire pwm //脉宽调制信号
);
parameter CNT300MS=24'd14_999_999;//300ms最大数
parameter NOTES =6'd33;//音符最大数
//************音符参数定义*********//
parameter DO=16'd47749,
RE=16'd42549,
MI=16'd37899,
FA=16'd37549,
SO=16'd31849,
LA=16'd28399,
XI=16'd25399;
reg [15:0] cnt_freq;//音频计数寄存器
reg [15:0] X;
wire[15:0] duty_data;//占空比数据
wire start_cnt_freq;//开始音频计数条件
wire end_cnt_freq;//结束音频计数条件
//*************************************//
//******音符计数*************//
reg [5:0] cnt_note;//音符计数寄存器
wire start_cnt_note;//音符开始计数条件
wire end_cnt_note;//音符结束条件条件
//*****300ms计数*******************//
reg [23:0] cnt_300ms;//300ms计数寄存器
wire start_cnt_300ms;//300ms开始计数条件
wire end_cnt_300ms;//300ms结束计数条件
//300ms计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin//初始化
cnt_300ms <= 24'd0;//计数寄存器值置零
end
else if (start_cnt_300ms)begin//开启计数
if(end_cnt_300ms)begin//满足记到最大数
cnt_300ms<=24'd0;//计数寄存器清零
end
else begin
cnt_300ms<=cnt_300ms+24'd1;//不满足,每次加一
end
end
else begin
cnt_300ms<=cnt_300ms;//保持
end
end
assign start_cnt_300ms=1'b1;
assign end_cnt_300ms=(start_cnt_300ms && cnt_300ms==CNT300MS);//结束条件
//34个音符计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_note <= 6'd0;
end
else if(start_cnt_note)begin
if(end_cnt_note)begin
cnt_note<=6'd0;
end
else begin
cnt_note <= cnt_note +6'd1;
end
end
else begin
cnt_note<=cnt_note;
end
end
assign start_cnt_note=end_cnt_300ms;//****重点*****//
assign end_cnt_note=(start_cnt_note && cnt_note==NOTES);
//音频计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_freq <= 16'd0;
end
else if(start_cnt_freq)begin
if(end_cnt_freq)begin
cnt_freq <= 16'd0;
end
else begin
cnt_freq <= cnt_freq + 1'd1;
end
end
else begin
cnt_freq <= cnt_freq;
end
end
assign start_cnt_freq = 1'b1;
assign end_cnt_freq=(start_cnt_freq && cnt_freq==X);
//音频查找表
always @(*)begin
case(cnt_note)
6'd0: X=DO;//1
6'd1: X=RE;//2
6'd2: X=MI;//3
6'd3: X=DO;//4
6'd4: X=DO;//1
6'd5: X=RE;//2
6'd6: X=MI;//3
6'd7: X=DO;//4
6'd8: X=MI;//3
6'd9: X=FA;//4
6'd10:X=SO;//5
6'd11:X=MI;//3
6'd12:X=FA;//4
6'd13:X=SO;//5
6'd14:X=SO;//5
6'd15:X=LA;//6
6'd16:X=SO;//5
6'd17:X=FA;//4
6'd18:X=MI;//3
6'd19:X=DO;//1
6'd20:X=SO;//5
6'd21:X=LA;//6
6'd22:X=SO;//5
6'd23:X=FA;//4
6'd24:X=MI;//3
6'd25:X=DO;//1
6'd26:X=RE;//2
6'd27:X=SO;//5
6'd28:X=DO;//1
6'd29:X=DO;//1
6'd30:X=RE;//2
6'd31:X=SO;//5
6'd32:X=DO;//1
6'd33:X=DO;//1
default:X=DO ;
endcase
end
assign duty_data=X >>1;//50%的占空比
assign pwm=(cnt_freq > duty_data) ? 1'b1:1'b0;
endmodule
2.蜂鸣器控制模块,用于开启蜂鸣器,并播放音乐
module beep_ctrl
(
input wire clk,
input wire rst_n,
input wire pwm,
output reg beep
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
beep <= 1'b1;
end
else if(pwm)begin//根据pwm信号开启蜂鸣器
beep <= 1'b0;
end
else begin
beep <= 1'b1;
end
end
endmodule
3.顶层模块
module music_top
(
input wire clk,
input wire rst_n,
output wire beep
);
wire pwm;
gen_pwm gen_pwm_inst
(
. clk (clk),//时钟信号
. rst_n(rst_n),
. pwm (pwm)//脉宽调制信号
);
beep_ctrl beep_ctrl
(
.clk (clk),
.rst_n (rst_n),
.pwm (pwm),
. beep (beep)
);
endmodule
通过这篇文章,从中获得学习灵感:蜂鸣器播放《两只老虎》_FPGA中国创新中心的博客-CSDN博客