蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
简谱是一种比较简单易学的音乐记谱法。据说简谱是由法国思想家卢梭于1742年发明的。而最早把简谱引进我国的是我国近代音乐教育家沈心工。简谱应该说是一种比较简单易学的音乐记谱法。它的最大好处是仅用7个阿拉伯数字----1234567,就能将万千变化的音乐曲子记录并表示出来.
在简谱中,用以表示音的高低及相互关系的基本符号为七个阿拉伯数字,即1、2、3、4、5、6、7,唱作do、re、mi、fa、sol、la、si,称为唱名。
音符:1234567
唱名:do re mi fa sol la si
汉字:哆来米发梭拉西
显然,单用以上七个音是无法表现众多的音乐形象的。在实际作品中,还有一些更高或更低的音,如在基本音符上方加记一个"·",表示该音升高一个八度,称为高音;加记两个" :",则表示该音升高两个八度,称为倍高音。在基本音符下方加记一个"·",表示该音降低一个八度,称为低音;加记两个" :",则表示该音降低两个八度,称为倍低音。
在一般歌曲中,无论是在基本音符上方或下方加记两个以上的"·"的音符都是很少见的。
在简谱中,1、2、3、4、5、6、7这七个基本音符,不仅表示音的高低,而且还是表示时值长短的基本单位,称为四分音符,其他音符均是在四分音符的基础上,用加记短横线"-"和附点"·"表示。
在基本音符右侧加记一条短横线,表示增长一个四分音符的时值。这类加记在音符右侧、使音符时值增长的短横线,称为增时线。增时线越多,音符的时值越长。
在基本音符下方加记一条短横线,表示缩短原音符时值的一半。这类加记在音符下方、使音符时值缩短的短横线,称为减时线。减时线越多,音符的时值越短。
在简谱中,加记在单纯音符的右侧的、使音符时值增长的小圆点"·",称为附点。加记附点的音符称为附点音符。附点本身并无一定的长短,其长短由前面的单纯音符来决定。附点的意义在于增长原音符时值的一半,常用于四分音符和小于四分音符的各种音符之后。
在《世上只有妈妈好》的简谱中,每两个竖线之间为2秒钟的时长。每两个竖线之间有4个音符时长,但是其中有较多半个音符的长,本设计采用1/4秒为基本单位。
蜂鸣器给予不同的频率是可以发出近似1、2、3、4、5、6、7这七个基本音符。
此模块命名为music_beep,clk为50MHz的时钟,rst_n为低电平有效的复位,beep为蜂鸣器的驱动信号。
在设计时,首先将简谱中的音符存起来;利用计数器产生1/4秒为周期的脉冲,在此脉冲驱动下,将事先存好的音符一个个输出;根据音符的值,计算出分频比;根据分频比,产生对应频率的波形。将此波形输出即可。
在进行多模块设计时,可以对每个模块只设计端口,将架构完成后。再分别设计每个模块。
《世上只有妈妈好》的简谱中共有8个四拍,每个四拍我们用8个音符来表示,合计共64个音符。在speed_ctrl中,输出的cnt为6位,正好可以表示64个状态。
在speed_ctrl中,每1/8秒让cnt增加1即可。
speed_ctrl 模块的设计代码如下:
module speed_ctrl (
input wire clk,
input wire rst_n,
output reg [5:0] cnt
);
parameter T_250ms = 12_500_000;
reg [25:0] count;
wire flag_250ms;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
count <= 26'd0;
else
if (count < T_250ms - 1'b1)
count <= count + 1'b1;
else
count <= 26'd0;
end
assign flag_250ms = (count == T_250ms - 1'b1) ? 1'b1 : 1'b0;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
cnt <= 6'd0;
else
if (flag_250ms == 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= cnt;
end
endmodule
在music_mem中存储音符,存储方式为低音用1到7表示,中音用8到14表示,高音用15到21表示,music为5bit位宽。
music_mem模块的设计代码如下:
module music_mem (
input wire clk,
input wire rst_n,
input wire [5:0] cnt,
output reg [4:0] music
);
// 1 2 3 4 5 6 7
// 8 9 10 11 12 13 14
// 15 16 17 18 19 20 21
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
music <= 5'd0;
else
case (cnt)
6'd0 : music <= 5'd13;
6'd1 : music <= 5'd13;
6'd2 : music <= 5'd13;
6'd3 : music <= 5'd12;
6'd4 : music <= 5'd10;
6'd5 : music <= 5'd10;
6'd6 : music <= 5'd12;
6'd7 : music <= 5'd12;
6'd8 : music <= 5'd15;
6'd9 : music <= 5'd15;
6'd10 : music <= 5'd13;
6'd11 : music <= 5'd12;
6'd12 : music <= 5'd13;
6'd13 : music <= 5'd13;
6'd14 : music <= 5'd13;
6'd15 : music <= 5'd13;
6'd16 : music <= 5'd10;
6'd17 : music <= 5'd10;
6'd18 : music <= 5'd12;
6'd19 : music <= 5'd13;
6'd20 : music <= 5'd12;
6'd21 : music <= 5'd12;
6'd22 : music <= 5'd10;
6'd23 : music <= 5'd10;
6'd24 : music <= 5'd8;
6'd25 : music <= 5'd6;
6'd26 : music <= 5'd12;
6'd27 : music <= 5'd10;
6'd28 : music <= 5'd9;
6'd29 : music <= 5'd9;
6'd30 : music <= 5'd9;
6'd31 : music <= 5'd9;
6'd32 : music <= 5'd9;
6'd33 : music <= 5'd9;
6'd34 : music <= 5'd9;
6'd35 : music <= 5'd10;
6'd36 : music <= 5'd12;
6'd37 : music <= 5'd12;
6'd38 : music <= 5'd13;
6'd39 : music <= 5'd13;
6'd40 : music <= 5'd10;
6'd41 : music <= 5'd10;
6'd42 : music <= 5'd10;
6'd43 : music <= 5'd9;
6'd44 : music <= 5'd8;
6'd45 : music <= 5'd8;
6'd46 : music <= 5'd8;
6'd47 : music <= 5'd8;
6'd48 : music <= 5'd12;
6'd49 : music <= 5'd12;
6'd50 : music <= 5'd12;
6'd51 : music <= 5'd10;
6'd52 : music <= 5'd9;
6'd53 : music <= 5'd8;
6'd54 : music <= 5'd6;
6'd55 : music <= 5'd8;
6'd56 : music <= 5'd5;
6'd57 : music <= 5'd5;
6'd58 : music <= 5'd5;
6'd59 : music <= 5'd5;
6'd60 : music <= 5'd5;
6'd61 : music <= 5'd5;
6'd62 : music <= 5'd5;
6'd63 : music <= 5'd5;
default : music <= 5'd0;
endcase
end
endmodule
根据频率和音符的关系,将音符对应的频率值取出来,根据频率值算出分频比。驱动时钟为50MHz,所以分频比为50M除以频率。
cal_divmum模块的设计代码如下:
module cal_divnum (
input wire clk,
input wire rst_n,
input wire [4:0] music,
output reg [31:0] divnum
);
reg [31:0] freq;
always @ * begin
case (music)
5'd1 : freq = 32'd262;
5'd2 : freq = 32'd294;
5'd3 : freq = 32'd330;
5'd4 : freq = 32'd349;
5'd5 : freq = 32'd392;
5'd6 : freq = 32'd440;
5'd7 : freq = 32'd494;
5'd8 : freq = 32'd523;
5'd9 : freq = 32'd587;
5'd10 : freq = 32'd659;
5'd11 : freq = 32'd699;
5'd12 : freq = 32'd784;
5'd13 : freq = 32'd880;
5'd14 : freq = 32'd988;
5'd15 : freq = 32'd1050;
5'd16 : freq = 32'd1175;
5'd17 : freq = 32'd1319;
5'd18 : freq = 32'd1397;
5'd19 : freq = 32'd1568;
5'd20 : freq = 32'd1760;
5'd21 : freq = 32'd1976;
default : freq = 32'd1;
endcase
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
divnum <= 32'd50_000_000;
else
divnum <= 50_000_000/freq;
end
endmodule
知道分频数后,利用任意分频的方式,产生对的波形即可。
wave_gen模块的设计代码如下:
module wave_gen (
input wire clk,
input wire rst_n,
input wire [31:0] divnum,
output reg beep
);
reg [31:0] cnt;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
cnt <= 32'd0;
else
if (cnt < divnum - 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= 32'd0;
end
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
beep <= 1'b0;
else
if (cnt < divnum[31:1])
beep <= 1'b0;
else
beep <= 1'b1;
end
endmodule
设计好上述四个模块后,将它们之前设计架构的连接方式,连接起来。
music_beep顶层模块的设计代码如下:
module music_beep (
input wire clk,
input wire rst_n,
output wire beep
);
wire [5:0] cnt;
wire [4:0] music;
wire [31:0] divnum;
speed_ctrl speed_ctrl_inst(
.clk (clk),
.rst_n (rst_n),
.cnt (cnt)
);
music_mem music_mem_inst(
.clk (clk),
.rst_n (rst_n),
.cnt (cnt),
.music (music)
);
cal_divnum cal_divnum_inst(
.clk (clk),
.rst_n (rst_n),
.music (music),
.divnum (divnum)
);
wave_gen wave_gen_inst(
.clk (clk),
.rst_n (rst_n),
.divnum (divnum),
.beep (beep)
);
endmodule
RTL视图如下,和所设计架构相同。
图11 :RTL视图
在testbench中,将speed_ctrl_inst模块中的T_250ms改成10。
defparam可以重新定义参数。
testbench代码如下:
`timescale 1ns/1ps
module music_beep_tb;
reg clk;
reg rst_n;
wire beep;
defparam music_beep_inst.speed_ctrl_inst.T_250ms = 10;
music_beep music_beep_inst(
.clk (clk),
.rst_n (rst_n),
.beep (beep)
);
initial clk = 1'b0;
always # 10 clk = ~clk;
initial begin
rst_n = 1'b0;
# 200
@ (posedge clk);
# 2;
rst_n = 1'b1;
# 20000;
$stop;
end
endmodule
由于输出的频率都较低,所以仿真时间都很长。
将参数改小,也只是加快切换输出音符的频率。由于wave_gen模块和分频模块相同,故而不在验证。只看RTL视图中,分频数是不是正确即可。
在RTL视图中,也看到cnt每10个周期增长1,然后对应输出音符。音符得出频率,根据频率得出分频数。经过验证,数据都是正确的。
分配管脚,全编译形成下载文件,下板后就可以听到《世上只有妈妈好》的歌曲了。
通过更改speed_crtl中的控制音符前进的速度,可以控制播放的速度。如果将速度控制到1/2秒的话,那么听到的歌曲将会变慢。如果将速度控制到1/8秒的话,那么听到的歌曲将会变快。
大家好,我是【FPGA功夫熊猫】精益求精,不断推荐好文章。