mcu音樂(lè )程序的設計與實(shí)驗
1.單片機的基本發(fā)音實(shí)驗
本文引用地址:http://dyxdggzs.com/article/201611/322391.htm我們知道,聲音的頻譜范圍約在幾十到幾千赫茲,若能利用程序來(lái)控制單處機某個(gè)口線(xiàn)的“高”電平或低電平,則在該口線(xiàn)上就能產(chǎn)生一定頻率的矩形波,接上喇叭就能發(fā)出一定頻率的聲音,若再利用延時(shí)程序控制“高”“低”電平的持續時(shí)間,就能改變輸出頻率,從而改變音調。
例如,要產(chǎn)生200HZ的音頻信號,按圖1接入喇叭(若屬臨時(shí)實(shí)驗,也可將喇叭直接接在P1口線(xiàn)上),實(shí)驗程序為:
讀者可以根據表1所提供的常數,將其16進(jìn)制代碼送入R3,反復練習體會(huì )。根據表1可以奏出音符。僅這還不夠,要準確奏出一首曲子,必須準確地控制樂(lè )曲節奏,即一音符的持續時(shí)間。
音符的節拍我們可以用定時(shí)器T0來(lái)控制,送入不同的初值,就可以產(chǎn)生不同的定時(shí)時(shí)間。便如某歌曲的節奏為每分鐘94拍,即一拍為0.64秒。其它節拍與時(shí)間的對應關(guān)系見(jiàn)表2。
但時(shí),由于T0的最大定時(shí)時(shí)間只能為131毫秒,因此不可能直接用改變T0的時(shí)間初值來(lái)實(shí)現不同節拍。我們可以用T0來(lái)產(chǎn)生10毫秒的時(shí)間基準,然后設置一個(gè)中斷計數器,通過(guò)判別中斷計數器的值來(lái)控制節拍時(shí)間的長(cháng)短。表2中也給出了各種節拍所對應的時(shí)間常數。例如對1/4拍音符,定時(shí)時(shí)間為0.16秒,相應的時(shí)間常數為16(即10H);對3拍音符,定時(shí)時(shí)間為1.92秒,相應時(shí)間長(cháng)數為192(即C0H)。
我們將每一音符的時(shí)間常數和其相應的節拍常數作為一組,按順序將樂(lè )曲中的所有常數排列成一個(gè)表,然后由查表程序依次取出,產(chǎn)生音符并控制節奏,就可以實(shí)現演奏效果。
此外,結束符和體止符可以分別用代碼00H和FFH來(lái)表示,若查表結果為00H,則表示曲子終了;若查表結果為FFH,則產(chǎn)生相應的停頓效果。
為了產(chǎn)生手彈的節奏感,在某些音符(例如兩個(gè)相同音符)音插入一個(gè)時(shí)間單位的頻率略有不同的音符。
程序框圖如圖2所示。
可直接在TD-III型學(xué)習機上演奏,對其它不同型號的學(xué)習機,只需相應地改變一下地址即可。本程序演奏的是民歌“八月桂花遍地開(kāi)”,C調,節奏為94拍/分。讀者也可以自行找出一首歌,按表1和表2給定的常數,將樂(lè )曲翻譯成碼表輸入機器,而程序不變。本實(shí)驗方法簡(jiǎn)便,即使不懂音樂(lè )的人,將一首陌生的曲子翻譯成代碼也是易事,和著(zhù)機器的演奏學(xué)唱一首歌曲,其趣味無(wú)窮。
下面這個(gè)例子是我在網(wǎng)上找的簡(jiǎn)單易懂,只不過(guò)是用C編寫(xiě)的,而且基本思想跟上面講的相同。
#i nclude
#i nclude
//本例采用89C52, 晶振為11.0592MHZ
//關(guān)于如何編制音樂(lè )代碼, 其實(shí)十分簡(jiǎn)單,各位可以看以下代碼.
//頻率常數即音樂(lè )術(shù)語(yǔ)中的音調,而節拍常數即音樂(lè )術(shù)語(yǔ)中的多少拍;
//所以拿出譜子, 試探編吧!
unsigned char n=0;
unsigned char code music_tab[] ={
0x18, 0x30, 0x1C , 0x10, //格式為: 頻率常數, 節拍常數, 頻率常數, 節拍常數,
0x20, 0x40, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x10,
0x1C, 0x10, 0x18 , 0x40,
0x1C, 0x20, 0x20 , 0x20,
0x1C, 0x20, 0x18 , 0x20,
0x20, 0x80, 0xFF , 0x20,
0x30, 0x1C, 0x10 , 0x18,
0x20, 0x15, 0x20 , 0x1C,
0x20, 0x20, 0x20 , 0x26,
0x40, 0x20, 0x20 , 0x2B,
0x20, 0x26, 0x20 , 0x20,
0x20, 0x30, 0x80 , 0xFF,
0x20, 0x20, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x20, 0x1C , 0x10,
0x18, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x20, 0x15 , 0x20,
0x1C, 0x20, 0x20 , 0x20,
0x26, 0x40, 0x20 , 0x20,
0x2B, 0x20, 0x26 , 0x20,
0x20, 0x20, 0x30 , 0x80,
0x20, 0x30, 0x1C , 0x10,
0x20, 0x10, 0x1C , 0x10,
0x20, 0x20, 0x26 , 0x20,
0x2B, 0x20, 0x30 , 0x20,
0x2B, 0x40, 0x20 , 0x15,
0x1F, 0x05, 0x20 , 0x10,
0x1C, 0x10, 0x20 , 0x20,
0x26, 0x20, 0x2B , 0x20,
0x30, 0x20, 0x2B , 0x40,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x20, 0x15 , 0x20,
0x1C, 0x20, 0x20 , 0x20,
0x26, 0x40, 0x20 , 0x20,
0x2B, 0x20, 0x26 , 0x20,
0x20, 0x20, 0x30 , 0x30,
0x20, 0x30, 0x1C , 0x10,
0x18, 0x40, 0x1C , 0x20,
0x20, 0x20, 0x26 , 0x40,
0x13, 0x60, 0x18 , 0x20,
0x15, 0x40, 0x13 , 0x40,
0x18, 0x80, 0x00
};
void int0()
{
}
void delay (unsigned char m)
{
}
void delayms(unsigned char a)
{
}
void main()
{ unsigned char p,m;
play:
}
評論