首先應(yīng)該了解一下蜂鳴器音樂播放的原理,在這里我只講一下電磁式蜂鳴器驅(qū)動原理(還有一種是壓電式蜂鳴器):
電磁式蜂鳴器驅(qū)動原理:
蜂鳴器發(fā)聲原理是電流通過電磁線圈,使電磁圈產(chǎn)生磁場來驅(qū)動振動膜發(fā)聲的。因此需要一定的電流才能驅(qū)動它,而單片機I/O引腳輸出的電壓較小。單片機輸出的TTLK電平基本驅(qū)動不了蜂鳴器,因需要增加一個放大電路。這里用三極管作為放大電路。下面是原理圖:
我這里的J8端是跟芯片的P1^5端口相連,當(dāng)P1^5輸出高電平時,三極管截止,蜂鳴器不發(fā)聲,反之,輸出低電平時,蜂鳴器發(fā)聲。
而要驅(qū)動蜂鳴器能像唱歌一樣的發(fā)聲,其實只要使蜂鳴器發(fā)出頻率和持續(xù)時間不同的聲音即可。周期等于頻率的倒數(shù),所以可以通過頻率知道這段的時間,所以可以通過調(diào)用延時函數(shù)或者定時器實現(xiàn),同樣的發(fā)聲的持續(xù)時間也可以通過延時函數(shù)實現(xiàn),所以讓蜂鳴器唱歌最關(guān)鍵的就是知道要延長多少時間!
用單片機來演奏音樂,,只要搞清楚兩個概念就好了,分別是“音調(diào)”和“節(jié)拍”。
音調(diào)表示一個音符該唱的頻率。
節(jié)拍表示一個音符該唱多少時間。
這里有兩種方法來實現(xiàn)該功能:
(1)查表法這個方法復(fù)雜的地方在于你要找出每個音符相對應(yīng)的頻率(根據(jù)音符;頻率對照表找),然后根據(jù)公式轉(zhuǎn)換為相應(yīng)的時間(取半周期),然后通過延時函數(shù)實現(xiàn)。最后編程實現(xiàn)。
先上代碼好了:
1/***************************************************2實驗名稱:用蜂鳴器播放生日快樂歌3實驗說明:不使用定時器中斷,所有頻率完全用延時實現(xiàn)4實驗時間:2014/12/55***************************************************/67#include8#defineucharunsignedchar9#defineuintunsignedint1011sbitBEEP=P1^5;//蜂鳴器接芯片的P1^5端口1213/*生日快樂歌的音符頻率表,不同頻率由不同的延時來決定音符頻率明顯大于數(shù)組里面的值,但是因為是8位寄15存器,所以最多只能放511,但是有的頻率大于511,所以只能在延時函數(shù)中乘上相應(yīng)的值來接近實際樂譜頻率*/17ucharcodeSONG_TONE[]=18{212,212,190,212,159,169,212,212,190,212,142,159,212,19212,106,126,159,169,190,119,119,126,159,142,159,0};2021//生日快樂歌節(jié)拍表,節(jié)拍決定每個音符的演奏長短,只是取個系數(shù),并非準(zhǔn)確的值22ucharcodeSONG_LONG[]=23{9,3,12,12,12,24,9,3,12,12,12,24,9,243,12,12,12,12,12,9,3,12,12,12,24,0};2526//延時27voidDelayMS(uintx)28{29uchart;30while(x--)31for(t=0;t<120;t++);32}3334//播放函數(shù)35voidPlayMusic()36{37uinti=0,j,k;38while(SONG_LONG[i]!=0"|SONG_TONE[i]!=0)39{40/*播放各個音符,SONG_LONG為拍子長度,一個節(jié)拍大概為400ms-500ms,這里的節(jié)拍又受下面一個音符的影響,所以只能根據(jù)大概的來取值*/41for(j=0;j整個流程是這樣的:
首先根據(jù)生日快樂歌的樂譜將各個音調(diào)轉(zhuǎn)換為相應(yīng)的頻率。
比如:左邊是生日快樂歌樂譜,右邊是音符頻率轉(zhuǎn)換表
這里先來了解一下樂譜的一點知識,左邊樂譜數(shù)字下面有點說明是低音,沒點說明就是普通的,數(shù)字上面有點就是高音,而5的低音就是4.5,高音是5.5,其他音符也是相應(yīng)的道理。
樂譜的左上方有寫“1=F”,而一般的樂譜都是C調(diào),就是“1=C”,注意,樂譜里面的1234567(哆啦咪發(fā)索拉西多)相對應(yīng)的不是ABCDEFG而是CDEFGAB!所以這里規(guī)定是F調(diào)的話,
那么就說明2就要唱G,3要唱A,……7要唱E,所以這里的低音5對應(yīng)的應(yīng)該是低音的1.5!!?。【褪撬^的要相應(yīng)的左移或者右移。如果還是不明白的話,看下面:
1原本對應(yīng)的應(yīng)該是C,4原本應(yīng)該對應(yīng)的是F,對吧?
然后現(xiàn)在1對應(yīng)的變成F了,就相當(dāng)于對應(yīng)了4,對吧?
那么1.5對應(yīng)的是什么?
4.5咯!
那2對應(yīng)的是什么?
5唄!
那么好了咯,低音5是4.5,是不是就是等于1.5?所以半周期就是1803μs。
至于為什么是根據(jù)半周期算,那是因為單片機是通過循環(huán)對蜂鳴器接的端口置位,復(fù)位來使發(fā)聲的,所以就是半周期。因為我用的是無源的蜂鳴器,有源的蜂鳴器就是全周期了。
然后就是按照上述道理,一個個轉(zhuǎn)換,并用延時函數(shù)實現(xiàn),因為每個音符的轉(zhuǎn)換頻率都不一樣,要么使用多個延時函數(shù)一個個實現(xiàn)準(zhǔn)確的音調(diào)頻率,但是這樣太煩,而且單片機本身就不是專門
弄來唱歌的。我們不應(yīng)該為難他們,所以自己將就一下就算了。所以延時函數(shù)為了適應(yīng)每個音調(diào)都有差不多的頻率,這個就靠自己計算了,而且不同的歌那個值還不一樣,所以這就是這個問題
的難點。
接下來的就是那個唱多久的問題,一般的歌曲默認(rèn)的一個節(jié)拍是400ms-500ms。
同樣的看樂譜左上方,它有寫“3/4”,意思是以四分音符為節(jié)拍,每一個小結(jié)有三拍。
而在每個數(shù)字下面有一條橫線,那時間就是那個節(jié)拍的時間乘上0.5,有兩條就乘上0.25,三條就乘以0.125。。。音樂的基本知識就別為難我了,我是個音樂白癡。。所以我就這么理解了。。
哈哈哈哈哈~
而至于節(jié)拍轉(zhuǎn)換為頻率,也是有相應(yīng)的表的,見下:
同樣的也是通過延時函數(shù)來實現(xiàn),當(dāng)然也是會有誤差的。而至于延時函數(shù)怎么寫,見[51單片機學(xué)習(xí)筆記ONE]
編程思想的話挺簡單的,就是先將音符頻率和所要唱的時間轉(zhuǎn)換好,放到兩個數(shù)組里面。然后在主程序里面,通過延時達到相應(yīng)頻率,唱完一遍,停一會,接著唱就好了。
(2)用工具轉(zhuǎn)碼并用計時器實現(xiàn)先上代碼好了:
1/*說明**************************************************************************2曲譜存貯格式unsignedcharcodeMusicName{音高,音長,音高,音長....,0,0};末尾:0,0表示結(jié)束(Important)34音高由三位數(shù)字組成:5個位是表示1~7這七個音符6十位是表示音符所在的音區(qū):1-低音,2-中音,3-高音;7百位表示這個音符是否要升半音:0-不升,1-升半音。89音長最多由三位數(shù)字組成:10個位表示音符的時值,其對應(yīng)關(guān)系是:11|數(shù)值(n):|0|1|2|3|4|5|612|幾分音符:|1|2|4|8|16|32|64音符=2^n13十位表示音符的演奏效果(0-2):0-普通,1-連音,2-頓音14百位是符點位:0-無符點,1-有符點1516調(diào)用演奏子程序的格式17Play(樂曲名,調(diào)號,升降八度,演奏速度);18|樂曲名:要播放的樂曲指針,結(jié)尾以(0,0)結(jié)束;19|調(diào)號(0-11):是指樂曲升多少個半音演奏;20|升降八度(1-3):1:降八度,2:不升不降,3:升八度;21|演奏速度(1-12000):值越大速度越快;2223***************************************************************************/24#ifndef__SOUNDPLAY_H_REVISION_FIRST__25#define__SOUNDPLAY_H_REVISION_FIRST__2627#include2829//**************************************************************************3031#defineSYSTEM_OSC11059200//12000000//定義晶振頻率12000000HZ32#defineSOUND_SPACE4/5//定義普通音符演奏的長度分率,//每4分音符間隔33sbitBeepIO=P1^5;//定義輸出管腳3435unsignedintcodeFreTab[12]={262,277,294,311,330,349,369,392,415,440,466,494};//原始頻率表36unsignedcharcodeSignTab[7]={0,2,4,5,7,9,11};//1~7在頻率表中的位置37unsignedcharcodeLengthTab[7]={1,2,4,8,16,32,64};38unsignedcharSound_Temp_TH0,Sound_Temp_TL0;//音符定時器初值暫存39unsignedcharSound_Temp_TH1,Sound_Temp_TL1;//音長定時器初值暫存40//**************************************************************************41voidInitialSound(void)42{43BeepIO=1;44Sound_Temp_TH1=(65535-(1/1200)*SYSTEM_OSC)/256;//計算TL1應(yīng)裝入的初值(10ms的初裝值)45Sound_Temp_TL1=(65535-(1/1200)*SYSTEM_OSC)%256;//計算TH1應(yīng)裝入的初值46TH1=Sound_Temp_TH1;47TL1=Sound_Temp_TL1;48TMOD|=0x11;49ET0=1;50ET1=0;51TR0=0;52TR1=0;53EA=1;54}5556voidBeepTimer0(void)interrupt1//音符發(fā)生中斷57{58BeepIO=!BeepIO;59TH0=Sound_Temp_TH0;60TL0=Sound_Temp_TL0;61}62//**************************************************************************63voidPlay(unsignedchar*Sound,unsignedcharSignature,unsignedOctachord,unsignedintSpeed)64{65unsignedintNewFreTab[12];//新的頻率表66unsignedchari,j;67unsignedintPoint,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;68unsignedcharTone,Length,SL,SH,SM,SLen,XG,FD;69for(i=0;i11)73{74j=j-12;75NewFreTab[i]=FreTab[j]*2;76}77else78NewFreTab[i]=FreTab[j];7980if(Octachord==1)81NewFreTab[i]>>=2;82elseif(Octachord==3)83NewFreTab[i]<<=2;84}8586SoundLength=0;87while(Sound[SoundLength]!=0x00)//計算歌曲長度88{89SoundLength+=2;90}9192Point=0;93Tone=Sound[Point];94Length=Sound[Point+1];//讀出第一個音符和它時時值9596LDiv0=12000/Speed;//算出1分音符的長度(幾個10ms)97LDiv4=LDiv0/4;//算出4分音符的長度98LDiv4=LDiv4-LDiv4*SOUND_SPACE;//普通音最長間隔標(biāo)準(zhǔn)99TR0=0;100TR1=1;101while(Point>=2;//低音110if(SM==3)CurrentFre<<=2;//高音111Temp_T=65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//計算計數(shù)器初值112Sound_Temp_TH0=Temp_T/256;113Sound_Temp_TL0=Temp_T%256;114TH0=Sound_Temp_TH0;115TL0=Sound_Temp_TL0+12;//加12是對中斷延時的補償116}117SLen=LengthTab[Length%10];//算出是幾分音符118XG=Length/10%10;//算出音符類型(0普通1連音2頓音)119FD=Length/100;120LDiv=LDiv0/SLen;//算出連音音符演奏的長度(多少個10ms)121if(FD==1)122LDiv=LDiv+LDiv/2;123if(XG!=1)124if(XG==0)//算出普通音符的演奏長度125if(SLen0;i--)//發(fā)規(guī)定長度的音139{140while(TF1==0);141TH1=Sound_Temp_TH1;142TL1=Sound_Temp_TL1;143TF1=0;144}145}146if(LDiv2!=0)147{148TR0=0;BeepIO=1;149for(i=LDiv2;i>0;i--)//音符間的間隔150{151while(TF1==0);152TH1=Sound_Temp_TH1;153TL1=Sound_Temp_TL1;154TF1=0;155}156}157Point+=2;158Tone=Sound[Point];159Length=Sound[Point+1];160}161BeepIO=1;162}163//**************************************************************************164#endif165166167168//揮著翅膀的女孩169unsignedcharcodeMusic_Girl[]={0x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x15,0x03,1700x16,0x03,0x17,0x03,0x17,0x03,0x17,0x03,0x18,0x03,1710x19,0x02,0x16,0x03,0x17,0x03,0x18,0x02,0x18,0x03,1720x17,0x03,0x15,0x02,0x18,0x03,0x17,0x03,0x18,0x02,1730x10,0x03,0x15,0x03,0x16,0x02,0x15,0x03,0x16,0x03,1740x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x1A,0x03,1750x1B,0x03,0x1F,0x03,0x1F,0x03,0x17,0x03,0x18,0x03,1760x19,0x02,0x16,0x03,0x17,0x03,0x18,0x03,0x17,0x03,1770x18,0x03,0x1F,0x03,0x1F,0x02,0x16,0x03,0x17,0x03,1780x18,0x03,0x17,0x03,0x18,0x03,0x20,0x03,0x20,0x02,1790x1F,0x03,0x1B,0x03,0x1F,0x66,0x20,0x03,0x21,0x03,1800x20,0x03,0x1F,0x03,0x1B,0x03,0x1F,0x66,0x1F,0x03,1810x1B,0x03,0x19,0x03,0x19,0x03,0x15,0x03,0x1A,0x66,1820x1A,0x03,0x19,0x03,0x15,0x03,0x15,0x03,0x17,0x03,1830x16,0x66,0x17,0x04,0x18,0x04,0x18,0x03,0x19,0x03,1840x1F,0x03,0x1B,0x03,0x1F,0x66,0x20,0x03,0x21,0x03,1850x20,0x03,0x1F,0x03,0x1B,0x03,0x1F,0x66,0x1F,0x03,1860x1B,0x03,0x19,0x03,0x19,0x03,0x15,0x03,0x1A,0x66,1870x1A,0x03,0x19,0x03,0x19,0x03,0x1F,0x03,0x1B,0x03,1880x1F,0x00,0x1A,0x03,0x1A,0x03,0x1A,0x03,0x1B,0x03,1890x1B,0x03,0x1A,0x03,0x19,0x03,0x19,0x02,0x17,0x03,1900x15,0x17,0x15,0x03,0x16,0x03,0x17,0x03,0x18,0x03,1910x17,0x04,0x18,0x0E,0x18,0x03,0x17,0x04,0x18,0x0E,1920x18,0x66,0x17,0x03,0x18,0x03,0x17,0x03,0x18,0x03,1930x20,0x03,0x20,0x02,0x1F,0x03,0x1B,0x03,0x1F,0x66,1940x20,0x03,0x21,0x03,0x20,0x03,0x1F,0x03,0x1B,0x03,1950x1F,0x66,0x1F,0x04,0x1B,0x0E,0x1B,0x03,0x19,0x03,1960x19,0x03,0x15,0x03,0x1A,0x66,0x1A,0x03,0x19,0x03,1970x15,0x03,0x15,0x03,0x17,0x03,0x16,0x66,0x17,0x04,1980x18,0x04,0x18,0x03,0x19,0x03,0x1F,0x03,0x1B,0x03,1990x1F,0x66,0x20,0x03,0x21,0x03,0x20,0x03,0x1F,0x03,2000x1B,0x03,0x1F,0x66,0x1F,0x03,0x1B,0x03,0x19,0x03,2010x19,0x03,0x15,0x03,0x1A,0x66,0x1A,0x03,0x19,0x03,2020x19,0x03,0x1F,0x03,0x1B,0x03,0x1F,0x00,0x18,0x02,2030x18,0x03,0x1A,0x03,0x19,0x0D,0x15,0x03,0x15,0x02,2040x18,0x66,0x16,0x02,0x17,0x02,0x15,0x00,0x00,0x00};205//同一首歌206unsignedcharcodeMusic_Same[]={0x0F,0x01,0x15,0x02,0x16,0x02,0x17,0x66,0x18,0x03,2070x17,0x02,0x15,0x02,0x16,0x01,0x15,0x02,0x10,0x02,2080x15,0x00,0x0F,0x01,0x15,0x02,0x16,0x02,0x17,0x02,2090x17,0x03,0x18,0x03,0x19,0x02,0x15,0x02,0x18,0x66,2100x17,0x03,0x19,0x02,0x16,0x03,0x17,0x03,0x16,0x00,2110x17,0x01,0x19,0x02,0x1B,0x02,0x1B,0x70,0x1A,0x03,2120x1A,0x01,0x19,0x02,0x19,0x03,0x1A,0x03,0x1B,0x02,2130x1A,0x0D,0x19,0x03,0x17,0x00,0x18,0x66,0x18,0x03,2140x19,0x02,0x1A,0x02,0x19,0x0C,0x18,0x0D,0x17,0x03,2150x16,0x01,0x11,0x02,0x11,0x03,0x10,0x03,0x0F,0x0C,2160x10,0x02,0x15,0x00,0x1F,0x01,0x1A,0x01,0x18,0x66,2170x19,0x03,0x1A,0x01,0x1B,0x02,0x1B,0x03,0x1B,0x03,2180x1B,0x0C,0x1A,0x0D,0x19,0x03,0x17,0x00,0x1F,0x01,2190x1A,0x01,0x18,0x66,0x19,0x03,0x1A,0x01,0x10,0x02,2200x10,0x03,0x10,0x03,0x1A,0x0C,0x18,0x0D,0x17,0x03,2210x16,0x00,0x0F,0x01,0x15,0x02,0x16,0x02,0x17,0x70,2220x18,0x03,0x17,0x02,0x15,0x03,0x15,0x03,0x16,0x66,2230x16,0x03,0x16,0x02,0x16,0x03,0x15,0x03,0x10,0x02,2240x10,0x01,0x11,0x01,0x11,0x66,0x10,0x03,0x0F,0x0C,2250x1A,0x02,0x19,0x02,0x16,0x03,0x16,0x03,0x18,0x66,2260x18,0x03,0x18,0x02,0x17,0x03,0x16,0x03,0x19,0x00,2270x00,0x00};228//兩只蝴蝶229unsignedcharcodeMusic_Two[]={0x17,0x03,0x16,0x03,0x17,0x01,0x16,0x03,0x17,0x03,2300x16,0x03,0x15,0x01,0x10,0x03,0x15,0x03,0x16,0x02,2310x16,0x0D,0x17,0x03,0x16,0x03,0x15,0x03,0x10,0x03,2320x10,0x0E,0x15,0x04,0x0F,0x01,0x17,0x03,0x16,0x03,2330x17,0x01,0x16,0x03,0x17,0x03,0x16,0x03,0x15,0x01,2340x10,0x03,0x15,0x03,0x16,0x02,0x16,0x0D,0x17,0x03,2350x16,0x03,0x15,0x03,0x10,0x03,0x15,0x03,0x16,0x01,2360x17,0x03,0x16,0x03,0x17,0x01,0x16,0x03,0x17,0x03,2370x16,0x03,0x15,0x01,0x10,0x03,0x15,0x03,0x16,0x02,2380x16,0x0D,0x17,0x03,0x16,0x03,0x15,0x03,0x10,0x03,2390x10,0x0E,0x15,0x04,0x0F,0x01,0x17,0x03,0x19,0x03,2400x19,0x01,0x19,0x03,0x1A,0x03,0x19,0x03,0x17,0x01,2410x16,0x03,0x16,0x03,0x16,0x02,0x16,0x0D,0x17,0x03,2420x16,0x03,0x15,0x03,0x10,0x03,0x10,0x0D,0x15,0x00,2430x19,0x03,0x19,0x03,0x1A,0x03,0x1F,0x03,0x1B,0x03,2440x1B,0x03,0x1A,0x03,0x17,0x0D,0x16,0x03,0x16,0x03,2450x16,0x0D,0x17,0x01,0x17,0x03,0x17,0x03,0x19,0x03,2460x1A,0x02,0x1A,0x02,0x10,0x03,0x17,0x0D,0x16,0x03,2470x16,0x01,0x17,0x03,0x19,0x03,0x19,0x03,0x17,0x03,2480x19,0x02,0x1F,0x02,0x1B,0x03,0x1A,0x03,0x1A,0x0E,2490x1B,0x04,0x17,0x02,0x1A,0x03,0x1A,0x03,0x1A,0x0E,2500x1B,0x04,0x1A,0x03,0x19,0x03,0x17,0x03,0x16,0x03,2510x17,0x0D,0x16,0x03,0x17,0x03,0x19,0x01,0x19,0x03,2520x19,0x03,0x1A,0x03,0x1F,0x03,0x1B,0x03,0x1B,0x03,2530x1A,0x03,0x17,0x0D,0x16,0x03,0x16,0x03,0x16,0x03,2540x17,0x01,0x17,0x03,0x17,0x03,0x19,0x03,0x1A,0x02,2550x1A,0x02,0x10,0x03,0x17,0x0D,0x16,0x03,0x16,0x01,2560x17,0x03,0x19,0x03,0x19,0x03,0x17,0x03,0x19,0x03,2570x1F,0x02,0x1B,0x03,0x1A,0x03,0x1A,0x0E,0x1B,0x04,2580x17,0x02,0x1A,0x03,0x1A,0x03,0x1A,0x0E,0x1B,0x04,2590x17,0x16,0x1A,0x03,0x1A,0x03,0x1A,0x0E,0x1B,0x04,2600x1A,0x03,0x19,0x03,0x17,0x03,0x16,0x03,0x0F,0x02,2610x10,0x03,0x15,0x00,0x00,0x00};262263unsignedcharcodeMusic_birth[]={0x0F,0x03,0x0F,0x03,0x10,0x02,0x0F,0x02,0x15,0x02,0x11,0x01,0x0F,0x03,2640x0F,0x03,0x10,0x02,0x0F,0x02,0x16,0x02,0x15,0x01,0x0F,0x03,0x0F,0x03,2650x19,0x02,0x17,0x02,0x15,0x02,0x11,0x0C,0x10,0x02,0x18,0x03,0x18,0x03,2660x17,0x02,0x15,0x02,0x16,0x02,0x17,0x01,0x0F,0x02,0x0F,0x03,0x10,0x03,2670x0F,0x02,0x15,0x02,0x11,0x01,0x0F,0x03,0x0F,0x03,0x10,0x02,0x0F,0x02,2680x16,0x02,0x15,0x01,0x0F,0x03,0x0F,0x03,0x19,0x02,0x17,0x02,0x15,0x02,2690x11,0x0C,0x10,0x02,0x18,0x03,0x18,0x03,0x17,0x02,0x15,0x02,0x16,0x02,2700x10,0x01,0x00,0x00};271272voidmain()273{274275InitialSound();276277278while(1)279{280Play(Music_Girl,0,2,350);281Play(Music_Same,0,2,350);282Play(Music_Two,0,2,350);283Play(Music_birth,0,2,350);284}285}