❶ 用單片機做電子琴,復音(合音)怎麼實現
解析MIDI電子琴的設計用單片機是如何實現的
摘要:用單片機控制通用MIDI音源模塊製作製作出的電子琴,結構簡單,可靠性高,並且價格低廉,具有實用的價值。這種電子琴能夠支持單音和復音彈奏,如果與高品質的音源晶元連接,音質更可與高檔電子琴相媲美。我們在實驗過程中,也曾採用手機中通用的音樂晶元構成音源模塊,效果不錯,價格更低廉,如韓國產的QS6400 等,這些晶元的驅動要復雜一些,需要對晶元進行初始化設置,詳細內容可參看國防工業出版社出版的《MIDI原理與開發應用》一書中的相關章節。
關鍵字:電子琴,單片機,音源板,MD2064
1、電子琴的硬體設計方案
本電子琴包含48個按鍵鍵盤,即具有4個8度的音域,單片機AT89C51通過對所彈按鍵的識別,產生相應的MIDI消息。它支持單音彈奏和最多16個復音彈奏。電子琴結構示意圖和電路原理圖分別如圖1和圖2所示。AT89C51作為主控晶元,它使得鍵盤矩陣模塊、通道和音色選擇以及串口發送等各功能模塊協調工作。48按鍵行列式鍵盤矩陣構成MIDI電子琴的鍵盤掃描輸入端,由於89C51的P0口內部沒有上拉電阻,故這里採用電阻R14——R21將列線拉至高電平,與六條行線組合完成48個琴鍵的掃描識別,在圖1中,單片機與鍵盤矩陣間的雙箭頭線表示單片機在掃描鍵盤矩陣時,P0口和P2口分別作為輸入/輸出口使用。人機介面電路則利用了單片機P1口的大部分口線,並通過或門向INT0發出中斷請求,該部分電路主要完成MIDI電子琴的通道設置和音色選擇等人機交互功能。鍵盤的彈奏信息以及通道、音色信息經CPU處理後,由串口將標準的MIDI數據發送給MIDI音源及放大器,推動揚聲器發聲。
圖1:MIDI電子琴結構示意圖
圖2:MIDI電子琴電路圖
音源模塊採用MD2064 套板,如圖3所示。它是一種模塊化的MIDI音源產品,由得理電子公司開發,具有標准MIDI介面,該板能接受標准GM MIDI命令進行音樂播放,自帶3D, REVERB, CHORUS等效果處理。由於該套板的MIDI 介面採用了光耦合器,電流驅動,故設計了由Q1、Q2等器件組成的驅動電路,使單片機串口數據得以正常傳輸。在模塊的耳機輸出端取得信號後,經小功率放大即可推動揚聲器發聲。
2、電子琴的軟體設計特點
該電子琴軟體採用模塊化設計方法,程序也較簡單。軟體中各功能模塊都由相應的子程序完成,主要包含通道選擇模塊,音色選擇模塊,48按鍵鍵盤掃描模塊,串口發送模塊等,其中為了及時完成用戶命令,音色選擇模塊採用了中斷服務子程序,可以在演奏中快速響應使用者的請求。
主程序在完成串口初始化、相關變數的初始化以及設置通道後,即進入鍵盤掃描、發送音符消息流程,為了使按鍵識別准確可靠,還設置了兩個緩沖區BUFF1和BUFF2保存鍵盤掃描值。主程序流程圖如圖3。
圖3:MIDI電子琴程序的流程圖
以下是部分功能模塊的程序設計介紹。
2.1 音色選擇模塊的設計
該模塊的功能是使MIDI電子琴能按要求快速改變音色,所以採用了中斷服務子程序。當某個音色選擇按鍵壓下時,通過或門向單片機的INT0發出中斷請求,CPU響應後進入該中斷服務子程序。MIDI技術規范規定,標准MIDI含有128種音色,它們的編號范圍是0~127,為了能夠快速找到所需音色,硬體中設置3個按鍵,其中2個用於音色編號的單步增加和減小,每次增加或減小1個音色編號,另外一個鍵用於音色快進,當快進鍵有效時,每次增加8個音色編號,選擇增加8個音色的原因是:標准MIDI的128種音色是按每8個音色一組編排的,共包含16個樂器組。電子琴開機時默認的音色編號是0,即大鋼琴音色。
單片機的P1.2口線連接著音色增加按鍵,P1.3則連接音色減小按鍵,P1.4連接音色快進鍵。低電平時按鍵有效,這三個按鍵通過與門連接外部中斷INT0,以便實時響應音色設置。該外部中斷0的中斷服務子程序流程圖見圖4,(圖中省去了按鍵延時去抖動部分):
圖4:音色改變子程序流程圖
在該子程序中,變數TAMBER中存放當前音色,其值可在0~127間循環,當TAMBER是最大值127時,加1後又變為0;而當TAMBER為0時,減1則變為127;在邊界范圍加8取模後,剛好為其對應的音色值。
2.2 串口發送模塊
串口發送模塊主要用於發送產生的MIDI消息,串口採用的模式1,發送的波特率是31.25KBPS。串口通過驅動電路連接MIDI音源,發送MIDI消息。通道號存放在變數CHANNEL中,通過與90H相與,所得值就是當前所設置的通道號。
2.3 鍵盤掃描模塊
本電子琴提供了48個MIDI按鍵,即4個8度音的音域范圍,當按下單個鍵時,產生一條MIDI消息,當按下多個鍵值時產生對應鍵值的多條MIDI音符開消息,當某個鍵值被釋放時,發送對應的音符關消息。這些MIDI消息通過串口發送給MIDI音源,產生MIDI音樂。音樂的時值由按鍵的時間長度控制,當按鍵被釋放,實時產生MIDI消息,關閉被釋放的鍵值音。
由P0口和P2口的P2.0~P2.5構成行列式鍵盤,也可繼續擴展鍵盤,例如改為常用的49鍵或64鍵。因為支持復音按鍵,鍵盤掃描程序必須掃描到行列式鍵盤的每個鍵值,掃描所得的鍵值存放在緩沖區BUFF1或BUFF2中。鍵盤掃描程序獲得的鍵盤編號范圍是0~47,還需將這個鍵盤編號值轉換為MIDI設備能夠識別的鋼琴鍵盤編號,這個功能由一個子程序來完成,限於篇幅本文不再詳述。鍵盤掃描子程序流程如圖5。
圖5:鍵盤掃描子程序
❷ 楂樺垎奼備竴涓鍗曠墖鏈虹數瀛愮惔c璇璦紼嬪簭
<p>6錛 鎶ヨ︿駭鐢熷櫒 </p> <p>1錛 瀹為獙浠誨姟 </p> <p>鐢≒1.0杈撳嚭1KHz鍜500Hz鐨勯煶棰戜俊鍙烽┍鍔ㄦ壃澹板櫒錛屼綔鎶ヨ︿俊鍙鳳紝瑕佹眰1KHz淇″彿鍝100ms錛500Hz淇″彿鍝200ms,浜ゆ浛榪涜岋紝P1.7鎺ヤ竴寮鍏寵繘琛屾帶鍒訛紝褰撳紑鍏沖悎涓婂搷鎶ヨ︿俊鍙鳳紝褰撳紑鍏蟲柇寮鍛婅︿俊鍙峰仠姝錛岀紪鍑虹▼搴忋 </p> <p>2錛 鐢佃礬鍘熺悊鍥 </p> <p> </p> <p>鍥4.6.1 </p> <p>3錛 緋葷粺鏉誇笂紜浠惰繛綰 </p> <p>錛1錛 鎶娾滃崟鐗囨満緋葷粺鈥濆尯鍩熶腑鐨凱1.0絝鍙g敤瀵肩嚎榪炴帴鍒扳滈煶棰戞斁澶фā鍧椻濆尯鍩熶腑鐨凷PK IN絝鍙d笂錛 </p> <p>錛2錛 鍦ㄢ滈煶棰戞斁澶фā鍧椻濆尯鍩熶腑鐨凷PK OUT絝鍙d笂鎺ヤ笂涓涓8嬈х殑鎴栬呮槸16嬈х殑鍠囧彮錛 </p> <p>錛3錛 鎶娾滃崟鐗囨満緋葷粺鈥濆尯鍩熶腑鐨凱1.7/RD絝鍙g敤瀵肩嚎榪炴帴鍒扳滃洓璺鎷ㄥ姩寮鍏斥濆尯鍩熶腑鐨凨1絝鍙d笂錛 </p> <p>4錛 紼嬪簭璁捐″唴瀹 </p> <p>錛1錛 淇″彿浜х敓鐨勬柟娉 </p> <p>500Hz淇″彿鍛ㄦ湡涓2ms錛屼俊鍙風數騫充負姣1ms鍙樺弽1嬈★紝1KHz鐨勪俊鍙峰懆鏈熶負1ms錛屼俊鍙風數騫蟲瘡500us鍙樺弽1嬈★紱 </p> <p> </p> <p>5錛 紼嬪簭妗嗗浘 </p> <p> </p> <p>鍥4.6.2 </p> <p>6錛 奼囩紪婧愮▼搴</p> <p>FLAG BIT 00H</p> <p>ORG 00H</p> <p>START: JB P1.7,START</p> <p>JNB FLAG,NEXT</p> <p>MOV R2,#200</p> <p>DV: CPL P1.0</p> <p>LCALL DELY500</p> <p>LCALL DELY500</p> <p>DJNZ R2,DV</p> <p>CPL FLAG</p> <p>NEXT: MOV R2,#200</p> <p>DV1: CPL P1.0</p> <p>LCALL DELY500</p> <p>DJNZ R2,DV1</p> <p>CPL FLAG</p> <p>SJMP START</p> <p>DELY500: MOV R7,#250</p> <p>LOOP: NOP</p> <p>DJNZ R7,LOOP</p> <p>RET</p> <p>END</p> <p>7錛 C璇璦婧愮▼搴</p> <p>#include <AT89X51.H></p> <p>#include <INTRINS.H></p> <p>bit flag;</p> <p>unsigned char count;</p> <p>void dely500(void)</p> <p>{</p> <p>unsigned char i;</p> <p>for(i=250;i>0;i--)</p> <p>{</p> <p>_nop_();</p> <p>}</p> <p>}</p> <p>void main(void)</p> <p>{</p> <p>while(1)</p> <p>{</p> <p>if(P1_7==0)</p> <p>{</p> <p>for(count=200;count>0;count--)</p> <p>{</p> <p>P1_0=~P1_0;</p> <p>dely500();</p> <p>}</p> <p>for(count=200;count>0;count--)</p> <p>{</p> <p>P1_0=~P1_0;</p> <p>dely500();</p> <p>dely500();</p> <p>}</p> <p>}</p> <p>}</p> <p>}</p> <p></p>
❸ 用單片機做電子琴的問題
你首先要保證你的單片機外圍電路要正常,他們是單片機工作的前提,我給你提點你查查,看看復位電路是否接好,最好用上電復位電路,再觀察你的晶振電路是否正常,最好用示波器觀察。不知道你用的是哪個型號的單片機,如果是40管腳的51系列,那你就再看看31管腳是否接的是高電平!就那個VPP,這個很多人就忽視了。檢查完以後如果一切都正常,那要用軟體測試的辦法了,你寫一個小程序,燒寫進去,看看是否運行,如果可以的話,那就不是硬體的問題了,而是你的軟體問題了,行了就說這么多了,如果 還有問題可以交流!祝你成功!!
❹ 單片機電子琴的工作原理
眾所周知,聲音是周圍空氣的震動,音調取決於震動的頻率,頻率越高音調越高。
電子琴按下不同的琴鍵就會發出不同音調的聲音,其實就是產生不同頻率的震動。
單片機電子琴說白了就是利用單片機產生不同頻率的電壓波形,推動揚聲器或蜂鳴器來發出不同音調的聲音。
假設電子琴有八個音階,就對應8個不同的頻率,頻率越高音調就越高。單片機很容易輸出方波信號,那麼只要讓它產生不同頻率的方波就可以了,然後用這個方波信號驅動揚聲器就可以了。單片機的按鍵可以模擬琴鍵,按下不同的按鍵就對應不同的頻率的方波,就能發出不同頻率的聲音了。
❺ 單片機電子琴的發聲原理
簡單點兒用IO口輸出不同頻率的方波給喇叭就行
❻ 單片機簡易電子琴程序
22. 電子琴
1. 實驗任務
(1. 由4X4組成16個按鈕矩陣,設計成16個音。
(2. 可隨意彈奏想要表達的音樂。
2. 電路原理圖
圖4.22.1
3. 系統板硬體連線
(1. 把「單片機系統」區域中的P1.0埠用導線連接到「音頻放大模塊」區域中的SPK IN埠上;
(2. 把「單片機系統「區域中的P3.0-P3.7埠用8芯排線連接到「4X4行列式鍵盤」區域中的C1-C4 R1-R4埠上;
4. 相關程序內容
(1. 4X4行列式鍵盤識別;
(2. 音樂產生的方法;
一首音樂是許多不同的音階組成的,而每個音階對應著不同的頻率,這樣我們就可以利用不同的頻率的組合,即可構成我們所想要的音樂了,當然對於單片機來產生不同的頻率非常方便,我們可以利用單片機的定時/計數器T0來產生這樣方波頻率信號,因此,我們只要把一首歌曲的音階對應頻率關系弄正確即可。現在以單片機12MHZ晶振為例,例出高中低音符與單片機計數T0相關的計數值如下表所示
音符 頻率(HZ) 簡譜碼(T值) 音符 頻率(HZ) 簡譜碼(T值)
低1 DO 262 63628 # 4 FA# 740 64860
#1 DO# 277 63731 中 5 SO 784 64898
低2 RE 294 63835 # 5 SO# 831 64934
#2 RE# 311 63928 中 6 LA 880 64968
低 3 M 330 64021 # 6 932 64994
低 4 FA 349 64103 中 7 SI 988 65030
# 4 FA# 370 64185 高 1 DO 1046 65058
低 5 SO 392 64260 # 1 DO# 1109 65085
# 5 SO# 415 64331 高 2 RE 1175 65110
低 6 LA 440 64400 # 2 RE# 1245 65134
# 6 466 64463 高 3 M 1318 65157
低 7 SI 494 64524 高 4 FA 1397 65178
中 1 DO 523 64580 # 4 FA# 1480 65198
# 1 DO# 554 64633 高 5 SO 1568 65217
中 2 RE 587 64684 # 5 SO# 1661 65235
# 2 RE# 622 64732 高 6 LA 1760 65252
中 3 M 659 64777 # 6 1865 65268
中 4 FA 698 64820 高 7 SI 1967 65283
下面我們要為這個音符建立一個表格,有助於單片機通過查表的方式來獲得相應的數據
低音0-19之間,中音在20-39之間,高音在40-59之間
TABLE: DW 0,63628,63835,64021,64103,64260,64400,64524,0,0
DW 0,63731,63928,0,64185,64331,64463,0,0,0
DW 0,64580,64684,64777,64820,64898,64968,65030,0,0
DW 0,64633,64732,0,64860,64934,64994,0,0,0
DW 0,65058,65110,65157,65178,65217,65252,65283,0,0
DW 0,65085,65134,0,65198,65235,65268,0,0,0
DW 0
2、音樂的音拍,一個節拍為單位(C調)
曲調值 DELAY 曲調值 DELAY
調4/4 125ms 調4/4 62ms
調3/4 187ms 調3/4 94ms
調2/4 250ms 調2/4 125ms
對於不同的曲調我們也可以用單片機的另外一個定時/計數器來完成。
下面就用AT89S51單片機產生一首「生日快樂」歌曲來說明單片機如何產生的。
在這個程序中用到了兩個定時/計數器來完成的。其中T0用來產生音符頻率,T1用來產生音拍。
5. 程序框圖
貼不了.
7. C語言源程序
#include <AT89X51.H>
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char STH0;
unsigned char STL0;
unsigned int code tab[]={64021,64103,64260,64400,
64524,64580,64684,64777,
64820,64898,64968,65030,
65058,65110,65157,65178};
void main(void)
{
TMOD=0x01;
ET0=1;
EA=1;
while(1)
{
P3=0xff;
P3_4=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=0;
break;
case 0x0d:
key=1;
break;
case 0x0b:
key=2;
break;
case 0x07:
key=3;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_5=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=4;
break;
case 0x0d:
key=5;
break;
case 0x0b:
key=6;
break;
case 0x07:
key=7;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_6=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=8;
break;
case 0x0d:
key=9;
break;
case 0x0b:
key=10;
break;
case 0x07:
key=11;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_7=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=12;
break;
case 0x0d:
key=13;
break;
case 0x0b:
key=14;
break;
case 0x07:
key=15;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
}
}
void t0(void) interrupt 1 using 0
{
TH0=STH0;
TL0=STL0;
P1_0=~P1_0;
}
根據自己的情況稍微改改就好了