硬件電子琴電路設計
一、實驗目的
(1)熟悉ISE Foundation設計流程和軟件操作,使用FPGA完成復雜的數字系統設計;
(2)掌握基于Verilog的組合和時序邏輯電路的設計方法;
(3)學習利用數控分頻器設計硬件電子琴實驗。
二、實驗要求
設計的電子琴系統需滿足:
(1)正確播放“梁祝”樂曲;
(2)播放其他音樂;
(3)實驗下載和硬件調試。
三、實驗原理
(一)播放原理
要實現系統設計,分如下4步操作:
1、將待播放的《梁祝》音樂音符存入ROM;
2、以4HZ頻率讀取ROM ;
3、根據1MHZ的內部時鐘要求,將讀出的音符換算成應計數的數值;
4、以1MHZ為內部時鐘,實現符合要求的方波信號。
由于系統時鐘是50Mhz,所以我們為了實現1Mhz的時鐘信號,故將50M分成12.5Mhz,后續在得到近似1MHZ時鐘。故按照“自上而下”設計原則,系統框圖1如示。
1_1.002.jpg (16.49 KB, 下載次數: 72)
下載附件
2017-5-10 22:45 上傳
圖1 硬件電子琴電路設計方案
(二)任務分析
1.輸入端口:
(1)復位信號RESET,當RESET=1時,輸出全部置零;當RESET=1,系統正常工作;
(2)時鐘信號CLK_50M,CLK_50M用于產生4Hz和12.5MHz分頻時鐘信號。
2.輸出端口:
(1)Code[3]~Code[0]是琴音簡譜碼;
(2)High是高8度端口,表示音階的高低;
(3)Spkout表示音符的頻率,外接蜂鳴器端口。
按照自頂向下設計,應該分為以下模塊:
3.分頻模塊
將下載板上50MHz時鐘分頻為頻率是4Hz和12.5Mhz的時鐘信號,其中4Hz用于讀取Rom,12.5MHz在后續模塊中在分頻得到近似1MHz時鐘。
4.音階發生器模塊
模塊ToneTaba是音階發生器,當8位發聲控制輸入Index中某一位為高電平時,則對應某一音階的數值將從端口Tone輸出,作為獲得該音階的分頻預置值;同時由Code輸出對應該音階簡譜的顯示數碼,如‘5’,并由High輸出指示音階高8度顯示。
5.數控分頻器模塊
模塊Speakera中的主要電路是一個數控分頻器,它由一個初值可預置的加法計數器構成,當模塊Speakera由端口Tone獲得一個2進制數后,將以此值為計數器的預置數,對端口Clk12MHZ輸入的頻率進行分頻,之后由Spkout向揚聲器輸出發聲。
6.樂曲自動演奏電路模塊
在原設計的基礎上,增加一個Notetabs模塊用于產生節拍控制(Index數據存留時間)和音階選擇信號,即在Notetabs模塊放置一個樂曲曲譜真值表,樂曲曲譜真值表放置于名為Music的ROM模塊中。
由一個計數器來生成讀取ROM所需的地址數據,對ROM以4HZ的頻率進行讀取,實現控制此真值表的輸出,而由此計數器的計數時鐘信號作為樂曲節拍控制信號,從而可以設計出一個純硬件的樂曲自動演奏電路。
1_1.003.jpg (27.17 KB, 下載次數: 101)
下載附件
2017-5-10 22:45 上傳
圖2 音符半周期及頻率對應圖
四、實驗步驟
(一)模塊設計
利用Verilog HDL語言,對各個模塊分別進行設計、仿真和綜合。
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
1_1.004.jpg (16.23 KB, 下載次數: 74)
下載附件
2017-5-10 22:45 上傳
圖3 分頻計12.5MHz綜合后RTL模塊符號
測試文件
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
1_1.005.jpg (17.99 KB, 下載次數: 61)
下載附件
2017-5-10 22:45 上傳
圖4 分頻1Hz功能仿真圖
經分析,CLK_50我給的T=20ns(即50MHz),從圖可以清晰看見分頻后時鐘周期為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萬個
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
1_1.006.jpg (14.26 KB, 下載次數: 58)
下載附件
2017-5-10 22:45 上傳
圖5 分頻4Hz綜合后RTL模塊符號
測試文件和分頻12.5MHz類似,故不再贅述。
1_1.007.jpg (26 KB, 下載次數: 67)
下載附件
2017-5-10 22:45 上傳
圖5 分頻4Hz功能仿真圖
CLK_50我給的T=20ns(即50MHz),從圖中,CLK_4在t=250ms處電平翻轉,故T=0.25s仿真正確
3.音階發生器
- `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
復制代碼
從ROM中讀取音符值,在此模塊中,完成Tone、琴音頻譜和高8度賦值。
1_1.008.jpg (16.7 KB, 下載次數: 92)
下載附件
2017-5-10 22:45 上傳
圖7 ToneTaba綜合后RTL模塊符號
測試文件:
- 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
復制代碼
1_1.009.jpg (15.52 KB, 下載次數: 53)
下載附件
2017-5-10 22:45 上傳
圖5音階發生器功能仿真圖1
從仿真圖中,我擬輸入音階0~15,其中0~7時,High=0;8、9、10、12、14、15時候,正好相反,High=1;code顯示對應數值。
1_1.010.jpg (18.27 KB, 下載次數: 73)
下載附件
2017-5-10 22:45 上傳
圖6音階發生器功能仿真圖2
1_1.011.jpg (15.42 KB, 下載次數: 74)
下載附件
2017-5-10 22:45 上傳
圖7音階發生器功能仿真圖3
輸入音階12時,toe=11'b11001010110,即1622;輸入音階13時,toe=11'b11010000100,即1668;觀察仿真圖,與之符合,故音階發生器功能模塊滿足設計要求。
4.樂曲自動演奏電路
`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,用于調用ROM實現樂曲曲譜的存儲,存儲器位寬,width=4,depth=256。通過在NoteTabs.v文件中例化ROM文件,實現按照4HZ頻率循環讀取ROM的音樂節拍、頻率信號。
1_1.012.jpg (5.39 KB, 下載次數: 67)
下載附件
2017-5-10 22:45 上傳
圖8 IPCORE存儲器
1_1.013.jpg (25.98 KB, 下載次數: 62)
下載附件
2017-5-10 22:45 上傳
圖9 存儲“梁祝”樂譜
1_1.014.jpg (13.91 KB, 下載次數: 65)
下載附件
2017-5-10 22:45 上傳
圖10 NoteTabs綜合后RTL模塊符號
測試文件
- module xxxxnote;
- reg Clk;
- wire [3:0] ToneIndex;
- NoteTabs uut (
- .Clk(Clk),
- .ToneIndex(ToneIndex)
- );
-
- initial
- begin
- Clk = 0;
- forever #10 Clk=~Clk;
- end
- endmodule
復制代碼
1_1.015.jpg (10.87 KB, 下載次數: 86)
下載附件
2017-5-10 22:45 上傳
圖11 NoteTabs綜合仿真圖
給定一個時鐘信號,每一個周期讀取一次ROM值,故從仿真中顯示值3、3、3、3、3、5、5、5、6、8、8、8等,和梁祝樂譜(圖9對比)一致,故設計符合要求。
5.數控分頻器模塊
- `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;
- …………限于本文篇幅 余下代碼請從51hei下載附件…………
復制代碼
按照代碼,Clk是一個12M的時鐘信號,進過第一個always語句時分頻PreClk =1MHz(1us);第二個always語句觸發條件是1MHz時鐘上升沿,所以音符半周期
1_1.016.jpg (2.42 KB, 下載次數: 75)
下載附件
2017-5-10 22:45 上傳
;第三個always語句觸發條件是Fullspks時鐘上升沿,所以最后
1_1.017.jpg (1.61 KB, 下載次數: 58)
下載附件
2017-5-10 22:45 上傳
。
比如“5”,Tone=1290,則音符半周期是758us,最后的輸出時鐘信號周期即為1516us,查表表示“中3M”音符。
1_1.018.jpg (16.79 KB, 下載次數: 68)
下載附件
2017-5-10 22:45 上傳
圖12 數控分頻器綜合后RTL模塊符號
激勵文件
- `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
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
激勵文件,我編寫的輸入時鐘信號近似12MHz,直接測“5”對應的tone=1290,如果最后結果與計算相符,則設計滿足要求。
1_1.019.jpg (20.39 KB, 下載次數: 89)
下載附件
2017-5-10 22:45 上傳
圖13十進制計數器功能仿真圖
經分析:
1_1.020.jpg (4.03 KB, 下載次數: 71)
下載附件
2017-5-10 22:45 上傳
;
1_1.021.jpg (2.19 KB, 下載次數: 82)
下載附件
2017-5-10 22:45 上傳
。 即“5”表示的半周期音符周期756us,忽略誤差因素,則可推出表示“中3M”音符,故數控分頻器滿足設計要求。
(二)系統頂層設計
按照自頂向下的設計原則,設計代碼如下
- `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),
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
1_1.022.jpg (21.77 KB, 下載次數: 84)
下載附件
2017-5-10 22:45 上傳
圖14電子琴綜合后RTL內部邏輯模塊
1_1.023.jpg (18.2 KB, 下載次數: 73)
下載附件
2017-5-10 22:45 上傳
圖15 電子琴系統設計綜合界面
由于Speakera.v、div_50_4HZ.v模塊的仿真時間過長,所以頂層模塊不需要仿真。
1_1.024.jpg (8.66 KB, 下載次數: 81)
下載附件
2017-5-10 22:45 上傳
圖16 鎖引腳操作
鎖引腳,添加約束文件后,需要下載到實驗板和硬件調試
四、思考題
1.電路上應該滿足哪些條件,才能用數字器件直接輸出的方波驅動揚聲器發聲?
答:需滿足如下條件:①輸出頻率在揚聲器的工作范圍內;②驅動電流能夠驅動揚聲器。
2.如果演奏其他樂曲,程序應做哪些方面的改動?
答:首先.coe文件內改成對應樂曲的譜,同時在ToneTaba和NoteTaba做一些小改動。
五、實驗體會
本實驗是預先將“梁祝”樂譜以.coe文件格式存儲,在調用ROM實現樂曲曲譜的存儲,結合程序將樂譜的值依次讀出來,轉化對應的音階的頻率,同時在實驗板上通過揚聲器發出音樂,LED等顯示琴音譜,因此這是一個純硬件樂曲演奏電路。對我而言,理解其原理難度很大。帶著問題,一步步探索。首先,樂譜的音調、音階和節拍的含義;其次,樂譜的存儲和如何讀出值;再者,讀出的值怎樣才能轉換為對應的頻率;最后,怎樣仿真驗證功能。
在仿真中,驗證數控分頻器模塊時,我不能準確把握每一個音符轉化成對應的半周期的時間間隔,所以就只驗證了一個“5”。并且,我遇到很多模塊仿真波形圖中,輸出端出現“xxx”。反復查閱資料,才發現原來,定義的某些中間變量都需要賦初值,否則最后仿真數據結果就會出現“xxx”不定態,對模塊的功能仿真驗證造成干擾。
整個設計流程走下來,能力得到了一定的提升,收獲很多,特別是對接下來的實驗調試充滿了期待。