硬件電子琴電路設(shè)計(jì)
一、實(shí)驗(yàn)?zāi)康?/strong>
(1)熟悉ISE Foundation設(shè)計(jì)流程和軟件操作,使用FPGA完成復(fù)雜的數(shù)字系統(tǒng)設(shè)計(jì);
(2)掌握基于Verilog的組合和時(shí)序邏輯電路的設(shè)計(jì)方法;
(3)學(xué)習(xí)利用數(shù)控分頻器設(shè)計(jì)硬件電子琴實(shí)驗(yàn)。
二、實(shí)驗(yàn)要求
設(shè)計(jì)的電子琴系統(tǒng)需滿足:
(1)正確播放“梁祝”樂(lè)曲;
(2)播放其他音樂(lè);
(3)實(shí)驗(yàn)下載和硬件調(diào)試。
三、實(shí)驗(yàn)原理
(一)播放原理
要實(shí)現(xiàn)系統(tǒng)設(shè)計(jì),分如下4步操作:
1、將待播放的《梁祝》音樂(lè)音符存入ROM;
2、以4HZ頻率讀取ROM ;
3、根據(jù)1MHZ的內(nèi)部時(shí)鐘要求,將讀出的音符換算成應(yīng)計(jì)數(shù)的數(shù)值;
4、以1MHZ為內(nèi)部時(shí)鐘,實(shí)現(xiàn)符合要求的方波信號(hào)。
由于系統(tǒng)時(shí)鐘是50Mhz,所以我們?yōu)榱藢?shí)現(xiàn)1Mhz的時(shí)鐘信號(hào),故將50M分成12.5Mhz,后續(xù)在得到近似1MHZ時(shí)鐘。故按照“自上而下”設(shè)計(jì)原則,系統(tǒng)框圖1如示。
圖1 硬件電子琴電路設(shè)計(jì)方案
(二)任務(wù)分析
1.輸入端口:
(1)復(fù)位信號(hào)RESET,當(dāng)RESET=1時(shí),輸出全部置零;當(dāng)RESET=1,系統(tǒng)正常工作;
(2)時(shí)鐘信號(hào)CLK_50M,CLK_50M用于產(chǎn)生4Hz和12.5MHz分頻時(shí)鐘信號(hào)。
2.輸出端口:
(1)Code[3]~Code[0]是琴音簡(jiǎn)譜碼;
(2)High是高8度端口,表示音階的高低;
(3)Spkout表示音符的頻率,外接蜂鳴器端口。
按照自頂向下設(shè)計(jì),應(yīng)該分為以下模塊:
3.分頻模塊
將下載板上50MHz時(shí)鐘分頻為頻率是4Hz和12.5Mhz的時(shí)鐘信號(hào),其中4Hz用于讀取Rom,12.5MHz在后續(xù)模塊中在分頻得到近似1MHz時(shí)鐘。
4.音階發(fā)生器模塊
模塊ToneTaba是音階發(fā)生器,當(dāng)8位發(fā)聲控制輸入Index中某一位為高電平時(shí),則對(duì)應(yīng)某一音階的數(shù)值將從端口Tone輸出,作為獲得該音階的分頻預(yù)置值;同時(shí)由Code輸出對(duì)應(yīng)該音階簡(jiǎn)譜的顯示數(shù)碼,如‘5’,并由High輸出指示音階高8度顯示。
5.數(shù)控分頻器模塊
模塊Speakera中的主要電路是一個(gè)數(shù)控分頻器,它由一個(gè)初值可預(yù)置的加法計(jì)數(shù)器構(gòu)成,當(dāng)模塊Speakera由端口Tone獲得一個(gè)2進(jìn)制數(shù)后,將以此值為計(jì)數(shù)器的預(yù)置數(shù),對(duì)端口Clk12MHZ輸入的頻率進(jìn)行分頻,之后由Spkout向揚(yáng)聲器輸出發(fā)聲。
6.樂(lè)曲自動(dòng)演奏電路模塊
在原設(shè)計(jì)的基礎(chǔ)上,增加一個(gè)Notetabs模塊用于產(chǎn)生節(jié)拍控制(Index數(shù)據(jù)存留時(shí)間)和音階選擇信號(hào),即在Notetabs模塊放置一個(gè)樂(lè)曲曲譜真值表,樂(lè)曲曲譜真值表放置于名為Music的ROM模塊中。
由一個(gè)計(jì)數(shù)器來(lái)生成讀取ROM所需的地址數(shù)據(jù),對(duì)ROM以4HZ的頻率進(jìn)行讀取,實(shí)現(xiàn)控制此真值表的輸出,而由此計(jì)數(shù)器的計(jì)數(shù)時(shí)鐘信號(hào)作為樂(lè)曲節(jié)拍控制信號(hào),從而可以設(shè)計(jì)出一個(gè)純硬件的樂(lè)曲自動(dòng)演奏電路。
圖2 音符半周期及頻率對(duì)應(yīng)圖
四、實(shí)驗(yàn)步驟
(一)模塊設(shè)計(jì)
利用Verilog HDL語(yǔ)言,對(duì)各個(gè)模塊分別進(jìn)行設(shè)計(jì)、仿真和綜合。
1.分頻代碼(12.5MHz)
`timescale 1ns / 1ps
module CLK_12M(CLK_50,CLR,CLK_12M);
input CLK_50,CLR;
output CLK_12M;
reg CLK_12M;
reg [3:0] div_count;
always @(posedge CLK_50 or posedge CLR)
if(CLR) div_count <= 4'h0;
else
if(div_count == 4'd3)//
div_count <= 4'h0;
else div_count <= div_count+1'b1;
always @ (posedge CLK_50 or posedge CLR)
if(CLR) CLK_12M <= 1'b0;
else
if(div_count== 0)
CLK_12M <= 1'b1;
else
CLK_12M <= 1'b0;
endmodule
圖3 分頻計(jì)12.5MHz綜合后RTL模塊符號(hào)
測(cè)試文件
module text_125M;
reg CLK_50;
reg CLR;
wire CLK_12M;
CLK_12M uut (
.CLK_50(CLK_50),
.CLR(CLR),
.CLK_12M(CLK_12M)
);
initial begin
CLK_50 = 0;
forever #10 CLK_50 = ~CLK_50 ;
end
initial begin
#20 CLR = 1'b1 ;
#20 CLR = 1'b0 ;
end
endmodule
圖4 分頻1Hz功能仿真圖
經(jīng)分析,CLK_50我給的T=20ns(即50MHz),從圖可以清晰看見(jiàn)分頻后時(shí)鐘周期為4T,即12.5MHz,故仿真正確。
2.分頻4Hz頻率
`timescale 1ns / 1ps
module CLK_4(CLK_50,CLR,CLK_4);
input CLK_50,CLR;
output CLK_4;
reg CLK_4;
reg [29:0] div_count;
always @(posedge CLK_50 or posedge CLR)
if(CLR) div_count <= 30'h0;
else
if(div_count == 30'd12500000)//和5000萬(wàn)個(gè)
div_count <= 31'h0;
else div_count <= div_count+1'b1;
always @ (posedge CLK_50 or posedge CLR)
if(CLR) CLK_4 <= 1'b0;
else
if(div_count== 0)
CLK_4 <= 1'b1;
else
CLK_4 <= 1'b0;
endmodule
圖5 分頻4Hz綜合后RTL模塊符號(hào)
測(cè)試文件和分頻12.5MHz類似,故不再贅述。
圖5 分頻4Hz功能仿真圖
CLK_50我給的T=20ns(即50MHz),從圖中,CLK_4在t=250ms處電平翻轉(zhuǎn),故T=0.25s仿真正確
3.音階發(fā)生器
- `timescale 1ns / 1ps
- module ToneTaba (Index,Code,High,Tone);
- input[3:0] Index;
- output[3:0] Code;
- output High;
- output[10:0] Tone;
- reg[3:0] Code;
- reg High;
- reg[10:0] Tone;
-
- always @ (Index)
- begin
- case(Index)
- 4'b0000 :begin Tone<=11'b11111111111;Code<=4'b0000;High<=1'b0;end//2047 0
- 4'b0001 :begin Tone<=11'b01100000101;Code<=4'b0001;High<=1'b0;end//773 1
- 4'b0010 :begin Tone<=11'b01110010000;Code<=4'b0010;High<=1'b0;end//912 2
- 4'b0011 :begin Tone<=11'b10000001100;Code<=4'b0011;High<=1'b0;end//1036 3
- 4'b0101 :begin Tone<=11'b10010101101;Code<=4'b0101;High<=1'b0;end//1197 4
- 4'b0110 :begin Tone<=11'b10100001010;Code<=4'b0110;High<=1'b0;end//1290 5
- 4'b0111 :begin Tone<=11'b10101011100;Code<=4'b0111;High<=1'b0;end//1372; 7
- 4'b1000 :begin Tone<=11'b10110000010;Code<=4'b0001;High<=1'b1;end//1410; 8
- 4'b1001 :begin Tone<=11'b10111001000;Code<=4'b0010;High<=1'b1;end//1480; 9
- 4'b1010 :begin Tone<=11'b11000000110;Code<=4'b0011;High<=1'b1;end//1542; 10
- 4'b1100 :begin Tone<=11'b11001010110;Code<=4'b0101;High<=1'b1;end//1622; 12
- 4'b1101 :begin Tone<=11'b11010000100;Code<=4'b0110;High<=1'b1;end//1668; 13
- 4'b1111 :begin Tone<=11'b11011000000;Code<=4'b0001;High<=1'b1;end//1728; 15
- default :begin Tone<=11'b11111111111;Code<=4'b0000;High<=1'b0;end//2047
- endcase
- end
- endmodule
復(fù)制代碼
從ROM中讀取音符值,在此模塊中,完成Tone、琴音頻譜和高8度賦值。
圖7 ToneTaba綜合后RTL模塊符號(hào)
測(cè)試文件:
- module test_toteTaba;
- reg [3:0] Index;
- wire [3:0] Code;
- wire High;
- wire [10:0] Tone;
- ToneTaba uut (
- .Index(Index),
- .Code(Code),
- .High(High),
- .Tone(Tone)
- );
- initial begin
- Index = 0;
- #20 Index = 4'b0000 ;
- #20 Index = 4'b0001 ;
- #20 Index = 4'b0010 ;
- #20 Index = 4'b0011 ;
-
- #20 Index = 4'b0100 ;
- #20 Index = 4'b0101 ;
- #20 Index = 4'b0110 ;
- #20 Index = 4'b0111 ;
-
- #20 Index = 4'b1000 ;
- #20 Index = 4'b1001 ;
- #20 Index = 4'b1010 ;
- #20 Index = 4'b1011 ;
-
- #20 Index = 4'b1100 ;
- #20 Index = 4'b1101 ;
- #20 Index = 4'b1110 ;
- #20 Index = 4'b1111 ;
- #100 $stop;
- end
- endmodule
復(fù)制代碼
圖5音階發(fā)生器功能仿真圖1
從仿真圖中,我擬輸入音階0~15,其中0~7時(shí),High=0;8、9、10、12、14、15時(shí)候,正好相反,High=1;code顯示對(duì)應(yīng)數(shù)值。
圖6音階發(fā)生器功能仿真圖2
圖7音階發(fā)生器功能仿真圖3
輸入音階12時(shí),toe=11'b11001010110,即1622;輸入音階13時(shí),toe=11'b11010000100,即1668;觀察仿真圖,與之符合,故音階發(fā)生器功能模塊滿足設(shè)計(jì)要求。
4.樂(lè)曲自動(dòng)演奏電路
`timescale 1ns / 1ps
module NoteTabs(Clk,ToneIndex);
input Clk;
output[3:0] ToneIndex;
reg[7:0] Counter=8'b0;
always@(posedge Clk ) begin
if(Counter>=138) Counter<=8'b00000000;
else Counter<=Counter+1'b1;
end
music1 u5( .addra(Counter),
.clka(Clk),
.douta(ToneIndex) );
endmodule
其中music1是IPCORE,用于調(diào)用ROM實(shí)現(xiàn)樂(lè)曲曲譜的存儲(chǔ),存儲(chǔ)器位寬,width=4,depth=256。通過(guò)在NoteTabs.v文件中例化ROM文件,實(shí)現(xiàn)按照4HZ頻率循環(huán)讀取ROM的音樂(lè)節(jié)拍、頻率信號(hào)。
圖8 IPCORE存儲(chǔ)器
圖9 存儲(chǔ)“梁祝”樂(lè)譜
圖10 NoteTabs綜合后RTL模塊符號(hào)
測(cè)試文件
- module xxxxnote;
- reg Clk;
- wire [3:0] ToneIndex;
- NoteTabs uut (
- .Clk(Clk),
- .ToneIndex(ToneIndex)
- );
-
- initial
- begin
- Clk = 0;
- forever #10 Clk=~Clk;
- end
- endmodule
復(fù)制代碼
圖11 NoteTabs綜合仿真圖
給定一個(gè)時(shí)鐘信號(hào),每一個(gè)周期讀取一次ROM值,故從仿真中顯示值3、3、3、3、3、5、5、5、6、8、8、8等,和梁祝樂(lè)譜(圖9對(duì)比)一致,故設(shè)計(jì)符合要求。
5.數(shù)控分頻器模塊
- `timescale 1ns / 1ps
- module Speakera(Clk,Tone,SpkS);
- input Clk;
- input[10:0] Tone;
- output SpkS;
-
- reg PreClk = 1'b0;
- reg FullSpkS = 1'b0;
- reg[3:0] Count4 = 4'b0000;
- reg[10:0]Count11 = 11'b0;
- reg Count2=1'b0;
- reg SpkS;
- //分頻1MHz
- always@(posedge Clk)
- begin
- if(Count4>11)begin
- PreClk<=1'b1;
- Count4<=1;
- end
- else begin
- PreClk<=1'b0;
- Count4<=Count4+1'b1;
- end
- end
- //音階半周期
- always@(posedge PreClk)begin
- if(Count11>=11'h7FF) begin
- Count11<=Tone;
- FullSpkS<=1'b1;
- end
- else begin
- Count11<=Count11+1'b1;
- FullSpkS<=0;
- end
- end
- //音階全周期
- always@(posedge FullSpkS)begin
- Count2<=~Count2;
- if(Count2==1'b1) SpkS<=1'b1;
- else SpkS<=1'b0;
- …………限于本文篇幅 余下代碼請(qǐng)從51hei下載附件…………
復(fù)制代碼
按照代碼,Clk是一個(gè)12M的時(shí)鐘信號(hào),進(jìn)過(guò)第一個(gè)always語(yǔ)句時(shí)分頻PreClk =1MHz(1us);第二個(gè)always語(yǔ)句觸發(fā)條件是1MHz時(shí)鐘上升沿,所以音符半周期
;第三個(gè)always語(yǔ)句觸發(fā)條件是Fullspks時(shí)鐘上升沿,所以最后
。
比如“5”,Tone=1290,則音符半周期是758us,最后的輸出時(shí)鐘信號(hào)周期即為1516us,查表表示“中3M”音符。
圖12 數(shù)控分頻器綜合后RTL模塊符號(hào)
激勵(lì)文件
- `timescale 1ns / 1ps
- module test_Speakera;
- reg Clk;
- reg [10:0] Tone;
- wire SpkS;
-
- Speakera uut (
- .Clk(Clk),
- .Tone(Tone),
- .SpkS(SpkS)
- );
- initial begin
- Clk = 0;
- forever #41.6 Clk = ~Clk ;
- end
- initial begin
- #2000 Tone = 11'b10100001010;//“5”--“中3M”音符,1290
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
激勵(lì)文件,我編寫的輸入時(shí)鐘信號(hào)近似12MHz,直接測(cè)“5”對(duì)應(yīng)的tone=1290,如果最后結(jié)果與計(jì)算相符,則設(shè)計(jì)滿足要求。
圖13十進(jìn)制計(jì)數(shù)器功能仿真圖
經(jīng)分析:
;
。 即“5”表示的半周期音符周期756us,忽略誤差因素,則可推出表示“中3M”音符,故數(shù)控分頻器滿足設(shè)計(jì)要求。
(二)系統(tǒng)頂層設(shè)計(jì)
按照自頂向下的設(shè)計(jì)原則,設(shè)計(jì)代碼如下
- `timescale 1ns / 1ps
- module songer(clk_50M,reset,Code1,High1,Spkout);
- input clk_50M;//CLK=50MHZ
- input reset;
-
- output[3:0] Code1;
- output High1,Spkout;
-
- wire[10:0] Tone;
- wire[3:0] ToneIndex;
- wire clk_4HZ,clk_12M;
-
- NoteTabs u0( .Clk(clk_4HZ),
- .ToneIndex(ToneIndex) );
- ToneTaba u1( .Index(ToneIndex),
- .Code(Code1),
- .High(High1),
- .Tone(Tone) );
- Speakera u2( .Clk(clk_12M),
- .Tone(Tone),
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
圖14電子琴綜合后RTL內(nèi)部邏輯模塊
圖15 電子琴系統(tǒng)設(shè)計(jì)綜合界面
由于Speakera.v、div_50_4HZ.v模塊的仿真時(shí)間過(guò)長(zhǎng),所以頂層模塊不需要仿真。
圖16 鎖引腳操作
鎖引腳,添加約束文件后,需要下載到實(shí)驗(yàn)板和硬件調(diào)試
四、思考題
1.電路上應(yīng)該滿足哪些條件,才能用數(shù)字器件直接輸出的方波驅(qū)動(dòng)揚(yáng)聲器發(fā)聲?
答:需滿足如下條件:①輸出頻率在揚(yáng)聲器的工作范圍內(nèi);②驅(qū)動(dòng)電流能夠驅(qū)動(dòng)揚(yáng)聲器。
2.如果演奏其他樂(lè)曲,程序應(yīng)做哪些方面的改動(dòng)?
答:首先.coe文件內(nèi)改成對(duì)應(yīng)樂(lè)曲的譜,同時(shí)在ToneTaba和NoteTaba做一些小改動(dòng)。
五、實(shí)驗(yàn)體會(huì)
本實(shí)驗(yàn)是預(yù)先將“梁祝”樂(lè)譜以.coe文件格式存儲(chǔ),在調(diào)用ROM實(shí)現(xiàn)樂(lè)曲曲譜的存儲(chǔ),結(jié)合程序?qū)?lè)譜的值依次讀出來(lái),轉(zhuǎn)化對(duì)應(yīng)的音階的頻率,同時(shí)在實(shí)驗(yàn)板上通過(guò)揚(yáng)聲器發(fā)出音樂(lè),LED等顯示琴音譜,因此這是一個(gè)純硬件樂(lè)曲演奏電路。對(duì)我而言,理解其原理難度很大。帶著問(wèn)題,一步步探索。首先,樂(lè)譜的音調(diào)、音階和節(jié)拍的含義;其次,樂(lè)譜的存儲(chǔ)和如何讀出值;再者,讀出的值怎樣才能轉(zhuǎn)換為對(duì)應(yīng)的頻率;最后,怎樣仿真驗(yàn)證功能。
在仿真中,驗(yàn)證數(shù)控分頻器模塊時(shí),我不能準(zhǔn)確把握每一個(gè)音符轉(zhuǎn)化成對(duì)應(yīng)的半周期的時(shí)間間隔,所以就只驗(yàn)證了一個(gè)“5”。并且,我遇到很多模塊仿真波形圖中,輸出端出現(xiàn)“xxx”。反復(fù)查閱資料,才發(fā)現(xiàn)原來(lái),定義的某些中間變量都需要賦初值,否則最后仿真數(shù)據(jù)結(jié)果就會(huì)出現(xiàn)“xxx”不定態(tài),對(duì)模塊的功能仿真驗(yàn)證造成干擾。
整個(gè)設(shè)計(jì)流程走下來(lái),能力得到了一定的提升,收獲很多,特別是對(duì)接下來(lái)的實(shí)驗(yàn)調(diào)試充滿了期待。