低音3 低音5 低音6 低音7 中音1 9102 7653 6818 6073 5736 7281 8730 9565 10310 10647 中音2 中音3 中音5 中音6 高音1 5111 4552 3827 3409 2867 11272 11831 12556 12974 13516 此外,对于乐曲中的休止符,只要将分频系数设为0,即初始值为2141=16383即可,此时扬声器将不会发声。
2、音长的控制
音符的持续时间必须根据乐曲的速度及每个音符的节拍数来确定。本例演奏的梁祝片段,最短的音符为4分音符,如果将全音符的持续时间设为1s的话,则只需要再提供一个4Hz的时钟频率即可产生4分音符的时长[4]。
如图3.2所示是乐曲演奏电路的原理框图,其中,乐谱产生电路用来控制音乐的音调和音长。控制音调通过设置计数器的预置数来实现,预置不同的数值可以使计数器产生不同频率的信号,从而产生不同的音调。控制音长是通过控制计数器预置数的停留时间来实现的,预置数停留的时间越长,则该音符演奏的时间越长。每个音符的演奏时间都是0.25s的整数倍,对于节拍较长的音符,如2分音符,在记谱时将该音名连续记录两次即可。
乐曲演奏电路的系统框图
音名显示电路用来显示乐曲演奏时对应的音符。可以用3个数码管,分别显示高、中、低音的音名,实现演奏的动态显示,十分直观。在本例中,high[3:0]、med[3:0]、low[3:0]等
6
信号分别用于显示高音、中音、低音音符。为了使演奏能循环进行,需另外设置一个时长计数器,当乐曲演奏完成时,保证能自动从头开始演奏。
方案实现
由系统框图可以看到本方案分成8个模块。
1)48MHz分频成12MHz波形分频器,源代码和顶层模块如下 //48mhz分成12mhz的分频模块
module div_clk12mhz(clk_48mhz,clk_12mhz); input clk_48mhz; output clk_12mhz; reg clk_12mhz; reg [21:0] cnt;
always @(posedge clk_48mhz)
if(cnt<1) cnt=cnt+1; // (48mhz/12mhz=4,cnt<[4/2-1=1]) else begin cnt=0; clk_12mhz =!clk_12mhz; end endmodule
2)12MHz分频成6MHz波形分频器,源代码和顶层模块如下: //12mhz分成6mhz的分频模块,提供给song模块 module div_clk6mhz(clk_12mhz,clk_6mhz); input clk_12mhz; output clk_6mhz; reg clk_6mhz; reg cnt;
always @(posedge clk_12mhz) clk_6mhz=!clk_6mhz;
endmodule
3)12MHz分频成4Hz波形分频器,源代码和顶层模块如下: //12mhz分成4hz的分频模块,提供给song模块
7
module div_clk4hz(clk_12mhz,clk_4hz); input clk_12mhz; output clk_4hz; reg clk_4hz; reg [21:0] cnt;
always @(posedge clk_12mhz)
if(cnt<1499999) cnt=cnt+1; // (12mhz/4hz=3000000,cnt<[3000000/2-1=1499999]) else begin cnt=0; clk_4hz =! clk_4hz; end endmodule
4)12MHz分频成1mhz波形分频器,源代码和顶层模块如下: //12mhz分成1mhz的分频模块,提供给quma模块 module div_clk1mhz(clk_12mhz,clk_1mhz); input clk_12mhz; output clk_1mhz; reg clk_1mhz; reg [21:0] cnt;
always @(posedge clk_12mhz)
if(cnt<5) cnt=cnt+1; // (12mhz/1mhz=12,cnt<[12/2-1=5]) else begin cnt=0; clk_1mhz =! clk_1mhz; end endmodule
5)12MHz分频成1khz波形分频器,源代码和顶层模块如下: //12mhz分成1khz的分频模块,提供给quma模块 module div_clk1khz(clk_12mhz,clk_1khz); input clk_12mhz; output clk_1khz; reg clk_1khz; reg [21:0] cnt;
always @(posedge clk_12mhz)
if(cnt<5999) cnt=cnt+1; // (12mhz/1khz=12000,cnt<[12000/2-1=5999]) else begin cnt=0; clk_1khz =! clk_1khz; end endmodule
8
6) song模块源代码和顶层模块如下: //音乐产生模块
module song(clk_6mhz,clk_4hz,speaker,high,med,low,k); //模块名为song(端口列表) input clk_6mhz,clk_4hz;
input k; //定义两个输入端口
output speaker; //定义一个输出端口 output[3:0] high,med,low;
reg[3:0] high,med,low; //定义了3个4位寄存器 reg[13:0] divider,origin; //定义了2个14位寄存器 reg[9:0] counter; //定义了1个10位寄存器 reg speaker; wire carry;
assign carry=(divider==16383); //连续赋值语句 always @(posedge clk_6mhz)
begin if(carry) divider<=origin; else divider<=divider+1; end
always @(posedge carry)
begin speaker<=~speaker;end //二分频产生方波信号 always @(posedge clk_4hz) begin
case({high,med,low}) //分频比预置 'b000000000011:origin<=7281; //低音3 'b000000000101:origin<=8730; //低音5 'b000000000110:origin<=9565; //低音6 'b000000000111:origin<=10310; //低音7 'b000000010000:origin<=10647; //中音1 'b000000100000:origin<=11272; //中音2 'b000000110000:origin<=11831; //中音3 'b000001010000:origin<=12556; //中音5 'b000001100000:origin<=12974; //中音6 'b000001110000:origin<=13347; //中音7 'b000100000000:origin<=13516; //高音1 'b000000000000:origin<=16383; //休止符 endcase end
always @(posedge clk_4hz)
9
if (k==0) begin
if(counter==149) counter<=0; //计时,以实现循环演奏 else counter<=counter+1;
case(counter) //记谱 0: {high,med,low}<='b000000000011; //低音\
1: {high,med,low}<='b000000000011; //持续4个时钟节拍 2: {high,med,low}<='b000000000011; 3: {high,med,low}<='b000000000011;
4: {high,med,low}<='b000000000101; 5: {high,med,low}<='b000000000101; 6: {high,med,low}<='b000000000101;
7: {high,med,low}<='b000000000110; 8: {high,med,low}<='b000000010000; 9: {high,med,low}<='b000000010000; 10: {high,med,low}<='b000000010000;
11: {high,med,low}<='b000000100000; 12: {high,med,low}<='b000000000110; 13: {high,med,low}<='b000000010000; 14: {high,med,low}<='b000000000101; 15: {high,med,low}<='b000000000101;
16: {high,med,low}<='b000001010000; 17: {high,med,low}<='b000001010000; 18: {high,med,low}<='b000001010000;
19: {high,med,low}<='b000100000000; 20: {high,med,low}<='b000001100000; 21: {high,med,low}<='b000001010000; 22: {high,med,low}<='b000000110000; 23: {high,med,low}<='b000001010000; 24: {high,med,low}<='b000000100000; 25: {high,med,low}<='b000000100000; 26: {high,med,low}<='b000000100000; 27: {high,med,low}<='b000000100000; 28: {high,med,low}<='b000000100000; 29: {high,med,low}<='b000000100000; 30: {high,med,low}<='b000000100000; 31: {high,med,low}<='b000000100000; 32: {high,med,low}<='b000000100000; 33: {high,med,low}<='b000000100000; 34: {high,med,low}<='b000000100000;
35: {high,med,low}<='b000000110000; 36: {high,med,low}<='b000000000111; 37: {high,med,low}<='b000000000111;
38: {high,med,low}<='b000000000110;
//低音\
//发3个时钟节拍 //低音\ //中音\
//发3个时钟节拍 //中音\ //低音\ //中音\ //低音\ //中音\
//发3个时钟节拍 //高音\ //中音\ //中音\ //中音\ //中音\ //中音\
//持续11个时钟节拍 //中音\ //低音\ //低音\
10