相信大家已經在網上見識過很多“民間大神”們的天才(奇葩)手工DIY了,一些簡簡單單的材料在他們的搗鼓下,瞬間華麗轉身,變廢為寶。今天,我們為大家整理了一位手工大神的DIY心得——如何利用FPGA開發板DIY一個音樂盒,也就是如何使我們的FPGA播放聲音和音樂!
首先需生成單個音調,然后慢慢地做更有趣的事情,如制作警報聲和播放曲調。
需要準備的硬件
該項目使用的是一個Pluto的FPGA開發板,還有一個揚聲器和一個1kΩ的電阻。
更加直觀的展示是下面這樣的:
本次DIY的音樂盒分為4個部分:
1.簡單的嗶嗶聲
2.警報聲
3.音調
4.曲子
1.簡單的嗶嗶聲
FPGA可以輕松實現二進制計數器。例如,在回滾之前,16位計數器將從0到65535(65536個不同的值)計數。Pluto板具有一個25MHz的時鐘振蕩器,因此我們可以輕松構建一個25MHz時鐘16位自動計數器。其最高位切換頻率為25000000/65536 = 381Hz。
其VerilogHDL的代碼如下:
modulemusic(clk,speaker);
inputclk;
outputspeaker;
// 首先創建一個16位二級制計數器
reg[15:0]counter;
always@(posedgeclk)counter<=counter+1;
// 使用計數器的最高有效位來驅動揚聲器
assignspeaker=counter[15];
endmodule
詳細講解的話就是,“clk”在25MHz下運行,“counter [0]”看起來像是一個12.5MHz信號(它以25MHz的頻率進行更新變化,變化的值為0 1 0 1 ......因此看起來像12.5MHz信號),“counter [1]“是6.125MHz信號,依此類推。
由于我們使用計數器的最高有效位(第15位)來驅動輸出,因此“揚聲器”輸出會產生一個完美的381Hz方波信號。
2.警報聲
我們可以在兩個音調之間循環。我們首先用一個24位計數器的“音調”來產生一個較慢的方波。其MSB(最高有效位)“tone[23]”是一1.5Hz的頻率進行變換的。
然后我們就可以用這個最高有效位切換到另一個計數器,從而在兩個頻率之間切換。
代碼如下:
modulemusic(clk,speaker);
inputclk;
outputspeaker;
parameterclkdivider=25000000/440/2;
reg[23:0]tone;
always@(posedgeclk)tone<=tone+1;
reg[14:0]counter;
always@(posedgeclk)if(counter==0)counter<=(tone[23]?clkdivider-1:clkdivider/2-1);elsecounter<=counter-1;
regspeaker;
always@(posedgeclk)if(counter==0)speaker<=~speaker;
endmodule
3.演奏音符
現在我們想要演奏一首曲子,所以需要來獲取不同的音符,就像電子琴一樣。
如果我們用6位來實現音符,那么我可以獲得64個音符。每個八度一共有12個音符,所以64個音符可以實現5個八度,完全足夠彈奏一首曲目了。
步驟1
要想實現一組音調不斷升高的聲音,我們用一個28位計數器來距離,提取其中6個MSB,從而給到6位的音調。
代碼如下:
reg[27:0]tone;
always@(posedgeclk)tone<=tone+1;
wire[5:0]fullnote=tone[27:22];
在25MHz的時鐘下,每個音符持續167ms,64個音符一共需要10.6s才能演奏完成。
步驟2
我們將“fullnote”分成12份。這樣就可以給到我們一個八度(一共有5個8度,所以我們只需要3位,從0到4)和音符(從0到11,需要4位)。
代碼如下:
wire[2:0]octave;
wire[3:0]note;
divide_by12 divby12(.numer(fullnote[5:0]),.quotient(octave),.remain(note));
此處用了一個叫divide_by12的子模塊來實現分頻。細節稍后講解。
步驟3
從一個八度到另一個八度,頻率乘以了“2”。這個在硬件上很容易實現,我們在步驟4上進行實現。但是要從一個音符到另一個音符,頻率就要乘以1.0594。這樣的話就沒那么容易在硬件上實現了,所以我們需要看下提前計算好的音符值。
我們將主時鐘除以512得到音符A,除以483得到音符A#,除以456得到音符B…記住,除以一個更低的值得到的是更高的音符。
一個八度下的音符數值如下:
always@(note)
case(note)
0:clkdivider=512-1;// A
1:clkdivider=483-1;// A#/Bb
2:clkdivider=456-1;// B
3:clkdivider=431-1;// C
4:clkdivider=406-1;// C#/Db
5:clkdivider=384-1;// D
6:clkdivider=362-1;// D#/Eb
7:clkdivider=342-1;// E
8:clkdivider=323-1;// F
9:clkdivider=304-1;// F#/Gb
10:clkdivider=287-1;// G
11:clkdivider=271-1;// G#/Ab
12:clkdivider=0;// should never happen
13:clkdivider=0;// should never happen
14:clkdivider=0;// should never happen
15:clkdivider=0;// should never happen
endcase
always@(posedgeclk)if(counter_note==0)counter_note<=clkdivider;elsecounter_note<=counter_note-1;
每當counter_note等于0時,就進入到下一個八度。
步驟4
現在我們要處理好不同的八度,對于最低的八度,我們將“counter_note”除以256,對于第二個八度,除以128,以此類推。
reg[7:0]counter_octave;
always@(posedgeclk)
if(counter_note==0)
begin
if(counter_octave==0)
counter_octave<=(octave==0?255:octave==1?127:octave==2?63:octave==3?31:octave==4?15:7);
else
counter_octave<=counter_octave-1;
end
regspeaker;
always@(posedgeclk)if(counter_note==0&&counter_octave==0)speaker<=~speaker;
完整代碼如下:
modulemusic(clk,speaker);
inputclk;
outputspeaker;
reg[27:0]tone;
always@(posedgeclk)tone<=tone+1;
wire[5:0]fullnote=tone[27:22];
wire[2:0]octave;
wire[3:0]note;
divide_by12 divby12(.numer(fullnote[5:0]),.quotient(octave),.remain(note));
reg[8:0]clkdivider;
always@(note)
case(note)
0:clkdivider=512-1;// A
1:clkdivider=483-1;// A#/Bb
2:clkdivider=456-1;// B
3:clkdivider=431-1;// C
4:clkdivider=406-1;// C#/Db
5:clkdivider=384-1;// D
6:clkdivider=362-1;// D#/Eb
7:clkdivider=342-1;// E
8:clkdivider=323-1;// F
9:clkdivider=304-1;// F#/Gb
10:clkdivider=287-1;// G
11:clkdivider=271-1;// G#/Ab
12:clkdivider=0;// should never happen
13:clkdivider=0;// should never happen
14:clkdivider=0;// should never happen
15:clkdivider=0;// should never happen
endcase
reg[8:0]counter_note;
always@(posedgeclk)if(counter_note==0)counter_note<=clkdivider;elsecounter_note<=counter_note-1;
reg[7:0]counter_octave;
always@(posedgeclk)
if(counter_note==0)
begin
if(counter_octave==0)
counter_octave<=(octave==0?255:octave==1?127:octave==2?63:octave==3?31:octave==4?15:7);
else
counter_octave<=counter_octave-1;
end
regspeaker;
always@(posedgeclk)if(counter_note==0&&counter_octave==0)speaker<=~speaker;
endmodule
-
FPGA
+關注
關注
1630文章
21798瀏覽量
606038 -
開發板
+關注
關注
25文章
5121瀏覽量
98209
原文標題:大神教你DIY | 如何用一塊FPGA開發板制作音樂盒?!
文章出處:【微信號:EngicoolArabic,微信公眾號:電子工程技術】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論