?? 單片機播放音樂程序.txt
字號:
單片機播放音樂程序例程參考(C語言)
關于播放效果
1.由于輸出的是方波,比較難聽:-)
只能說是非常難聽:-)為什么呢?只因為輸出的是方波,包含了大量的奇次諧波。
你可以用雙龍的"虛擬儀器"分別產生正弦波、三角波和方波聽一下,正弦波感覺就比
較純正,
而方波則要多難聽有多難聽!
解決方案:
1.用3、4個IO及R-2R電阻網絡作3、4BitDAC
2.用PWM輸出
3.用專用音樂旋律發生芯片
4.用硬波表的聲卡或MIDI芯片
各方案比較:
1.制作簡單,占用IO、定時器資源較少,成本低,可行性好
2.制作簡單,但PWM頻率不能作高,行不通
3.4.可作出很好聽的效果,但成本較高
關于:如果單片機進作此工作還可以,加入其他的程序肯定不行
2.由于依靠T1的頻繁中斷產生相應頻率的輸出,
因此任何其他同級或更高級別的中斷發生都會使T1不能進入中斷,
使樂曲打頓,這樣就必須使其他中斷占用的時間盡量短才會感覺不出來
關于:功能齊全
底層的東西作出來后,而且是用C編程,要功能齊全是件相當容易的事
關于:音符編碼
優化的音符編碼是這個程序最大的優點(相對于所有見過的類似功能程序)
3.優化音符編碼:一個字節中包含節拍、音符、升降調,可區分數據和命令,
對于一般的樂曲調用功能碼的時候相當少,基本可做到一個音符對應一個字
節,
這點對于小存儲量的單片機來說是必要的。
同時人工將音符譯為機器碼非常容易。(格式看下面實例)
//音符碼格式:| D7 |D6 D5 D4| D3 |D2 D1 D0| |變調| 節拍|升降| 音符 |
// 示例:0xcb=11001011B,即升調,4/16拍,3Mi低音
//功能碼格式:| D7 D6 D5 D4 | D3 D2 D1 D0|
// |高4位=0時是功能碼|根據低4位散轉 |
0x00, //最后字節為功能碼必須==0x00退出
關于發布此貼的原因
1.幫助初學者,
2.拋磚引玉,
3.論壇正有人問相關的問題
4.就程序的規范性、寫法、注釋等征求大家的意見
還將有一系列的源程序公開,正在整理
關于樂理方面的知識
建議大家到 MIDI小屋 去看看,
有大量的MIDI、MIDI知識、MIDI軟件
其中的有一個YAMAHA軟波表一定要試一下,
你會對MIDI的觀念大大改觀(害的我當年發了瘋的從網上找了6萬多首MIDI:-)
上網想找東西的別忘了用搜索:-)
****************************************************************************/
//--------------------------------------------------------------------------//
// 源程序大公開 //
// (c) Copyright 2001-2002 xuwenjun //
// All Rights Reserved //
// V1.00 //
//--------------------------------------------------------------------------//
//標 題: 單片機IO口播放樂曲 //
//版 本: V1.00 //
//文件名: xwj_lcd16.C //
//創建人: 徐文軍 E-mail:xuwenjun@21cn.com //
//日 期: 02-11-5 //
//描 述: 單片機利用T1中斷在IO口P1.0輸出樂曲 //
//聲 明: //
// 以下代碼僅免費提供給學習用途,但引用或修改后必須在文件中聲明出處. //
// 如用于商業用途請與作者聯系. E-mail:xuwenjun@21cn.com //
// 有問題請mailto xuwenjun@21cn.com 歡迎與我交流! //
//--------------------------------------------------------------------------//
//修改人: 徐文軍 E-mail:xuwenjun@21cn.com //
//日 期: 02-11-5 //
//說 明: //
// 單片機用T1中斷在IO口P1.0輸出樂曲(在P1.0口與VCC間接一喇叭即可聽到) //
// 1.由于輸出的是方波,比較難聽:-)你也可以將波形細分用DA輸出正弦波 //
// 2.由于T1頻繁中斷,任何其他中斷發生都會是樂曲打頓,只適合試驗 //
// 3.優化音符編碼:一個字節中包含節拍、音符、升降調,可區分數據和命令//
// 同時人工將音符譯為機器碼非常容易。(格式看下面實例)//
//--------------------------------------------------------------------------//
#include <reg52.h>
#include <intrins.h>
#define FREQ 11059200
// 音樂_編碼2 -- 存儲器定義 //
unsigned char code music_tab1[]={ //音符碼格式:| D7 |D6 D5 D4| D3 |D2 D1 D0|
//梁祝 |變調| 節拍|升降| 音 符 |
0xcb, //示例:0xcb=11001011B,即升調,4/16拍,3Mi低音
0x35,0x16,0xb9,0x12,0x96,0x99,0xa5,
0xbd,0x99,0x96,0x15,0x13,0x15,0x62,
0x32,0x13,0xa7,0x26,0x25,0x16,0xa9,0x22,
0xa3,0xa9,0x96,0x15,0x16,0x99,0xe5,
0xbb,0x15,0xa7,0xaa,0x96,0x99,0xd5,
0x13,0x15,0x23,0x15,0x16,0x17,0x9a,0xd6,0x15,0x16,
0xb9,0x12,0x25,0x23,0x23,0x22,0x13,0x12,0x21,0x96,0x15,
0x43,0xc9,0x96,0x99,0x96,0x15,0x13,0x15,0x16,0x99,
0xd5, //功能碼格式:| D7 D6 D5 D4 | D3 D2 D1 D0|
// |高4位=0時是功能碼|根據低4位散轉 |
0x00, //最后字節為功能碼必須==0x00退出
};
unsigned char code music_tab2[]={ //康定情歌
0x23,0x25,0x26,0x16,0x15, 0x36,0x13,0x42,
0x23,0x25,0x26,0x16,0x15, 0x26,0x53,
0x23,0x25,0x26,0x16,0x15, 0x26,0x23,0x42,
0x25,0x23,0x12,0x13,0x12,0x11, 0x22,0xd6,
0x26,0xda, 0x25,0x53, 0x12,0x11,0xd6,
0xad,0x23,0x12,0x13,0x12,0x11, 0x22,0xd6,
0x00,
};
unsigned char code music_tab3[]={ //美酒加咖啡
0x55,0x23,0x25,0x26,0xa9,0x22, 0x73,
0x45,0x25,0x26,0x23,0x22,0x21,0x23, 0x72,
0x52,0x23,0x45,0x43, 0x22,0x21,0xa6,0x25,0x66,
0xc9,0xa6,0x25,0x23,0x25,0x26,0xa9, 0xf5,
0x45,0x23,0x25,0x46,0xc9, 0x22,0x13,0x12,0x21,0x22,0x63,
0x22,0x23,0x25,0x26,0x25,0x23,0x22,0x21, 0x72,
0x52,0x23,0x45,0x43, 0x22,0x21,0xa6,0x25,0x66,
0xb9,0x12,0x23,0x25,0x22,0xa5,0xab,0x22, 0x71,
0x00,
};
unsigned char code music_tab4[]={ //北國之春
0x15,0x16,0x75, 0x15,0x16,0x55,0x13,0x15,0x16,0x15,0x16,0x99,0x12,0x13,
0x65,0x45,0x13,0x12,0x11,0x12, 0x73,
0x62,0x42,0x12,0x11,0x96,0x15, 0x76,
0x55,0x23,0x45,0xa9,0x22, 0x53,0x12,0x13,0x65,
0x52,0x22,0x42,0x21,0xa6, 0xe9,0x91,0x12,0x13,0x12,0x13,0x15,0x99,0x12,
//以上為過門
0x20,0x23,0x23,0x23,0x63, 0x22,0x23,0x23,0x22,0x41,0xa6,0x25,
0x53,0x22,0x21,0xa9,0x21,0xa6, 0x75,
0x26,0xa9,0x21,0xa6,0xc9,0x12,0x11,0x96,0x15,
0x23,0x25,0x25,0x26,0x45,0x21,0x22,
0x13,0x35,0x25,0xa9,0xa6,0x25,0x23,0x22, 0x71,
0x52,0x25,0x45,0x13,0x15,0x13,0x12, 0x21,0x41,0x22,0x43,0x45,
0x23,0x25,0x26,0xa9,0x42,0x12,0x33, 0x72,
0x51,0x22,0x43,0x22,0x21, 0xc6,0xc9,0x29,0xc6,0x45,0x23,0x23,
0x53,0x25,0x26,0x25,0x13,0x12,0x21, 0x62,0x42,0x23,0x25,
0x55,0x26,0x25,0x23,0x45, 0x26,0xa9,0x21,0x22,0x63,
0x52,0x22,0x22,0x13,0x12,0x21,0xa6,0xf9,
0x00,
};
unsigned char code music_l_tab[8]={0,1,2,3,4,6,8,16};//節拍延時單位
unsigned char code music_freq_tab[64]={ //音符定時器值表
0xff,0xea, //0 休止符
255-FREQ/24/131/256, //256-FREQ/24/x/256 //1 do 高字節
256-FREQ/24/131%256, //256-FREQ/24/x%256 //1 do 低字節
255-FREQ/24/147/256,256-FREQ/24/147%256, //2 re
255-FREQ/24/165/256,256-FREQ/24/165%256, //3 mi
255-FREQ/24/175/256,256-FREQ/24/175%256, //4 fa
255-FREQ/24/196/256,256-FREQ/24/196%256, //5 suo
255-FREQ/24/221/256,256-FREQ/24/221%256, //6 la
255-FREQ/24/248/256,256-FREQ/24/248%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/262/256,256-FREQ/24/262%256, //1 do
255-FREQ/24/294/256,256-FREQ/24/294%256, //2 re
255-FREQ/24/330/256,256-FREQ/24/330%256, //3 mi
255-FREQ/24/350/256,256-FREQ/24/350%256, //4 fa
255-FREQ/24/393/256,256-FREQ/24/393%256, //5 suo
255-FREQ/24/441/256,256-FREQ/24/441%256, //6 la
255-FREQ/24/495/256,256-FREQ/24/495%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/525/256,256-FREQ/24/525%256, //1 do
255-FREQ/24/589/256,256-FREQ/24/589%256, //2 re
255-FREQ/24/661/256,256-FREQ/24/661%256, //3 mi
255-FREQ/24/700/256,256-FREQ/24/700%256, //4 fa
255-FREQ/24/786/256,256-FREQ/24/786%256, //5 suo
255-FREQ/24/882/256,256-FREQ/24/882%256, //6 la
255-FREQ/24/990/256,256-FREQ/24/990%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/1049/256,256-FREQ/24/1049%256, //1 do
255-FREQ/24/1178/256,256-FREQ/24/1178%256, //2 re
255-FREQ/24/1322/256,256-FREQ/24/1322%256, //3 mi
255-FREQ/24/1400/256,256-FREQ/24/1400%256, //4 fa
255-FREQ/24/1572/256,256-FREQ/24/1572%256, //5 suo
255-FREQ/24/1665/256,256-FREQ/24/1665%256, //6 la
255-FREQ/24/1869/256,256-FREQ/24/1869%256, //7 xi
};
unsigned char code music_frequp_tab[64]={ //升半音
0xff,0xea, //0 休止符
255-FREQ/24/139/256, //1 do 高字節 //255-FREQ/24/x/256
256-FREQ/24/139%256, //1 do 低字節 //256-FREQ/24/x%256
255-FREQ/24/156/256,256-FREQ/24/156%256, //2 re
255-FREQ/24/175/256,256-FREQ/24/175%256, //3 mi
255-FREQ/24/185/256,256-FREQ/24/185%256, //4 fa
255-FREQ/24/208/256,256-FREQ/24/208%256, //5 suo
255-FREQ/24/234/256,256-FREQ/24/234%256, //6 la
255-FREQ/24/262/256,256-FREQ/24/262%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/278/256,256-FREQ/24/278%256, //1 do
255-FREQ/24/312/256,256-FREQ/24/312%256, //2 re
255-FREQ/24/350/256,256-FREQ/24/350%256, //3 mi
255-FREQ/24/371/256,256-FREQ/24/371%256, //4 fa
255-FREQ/24/416/256,256-FREQ/24/416%256, //5 suo
255-FREQ/24/467/256,256-FREQ/24/467%256, //6 la
255-FREQ/24/525/256,256-FREQ/24/525%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/556/256,256-FREQ/24/556%256, //1 do
255-FREQ/24/624/256,256-FREQ/24/624%256, //2 re
255-FREQ/24/700/256,256-FREQ/24/700%256, //3 mi
255-FREQ/24/742/256,256-FREQ/24/742%256, //4 fa
255-FREQ/24/833/256,256-FREQ/24/833%256, //5 suo
255-FREQ/24/935/256,256-FREQ/24/935%256, //6 la
255-FREQ/24/1049/256,256-FREQ/24/1049%256, //7 xi
0xff,0xea, //0 休止符
255-FREQ/24/1112/256,256-FREQ/24/1112%256, //1 do
255-FREQ/24/1248/256,256-FREQ/24/1248%256, //2 re
255-FREQ/24/1400/256,256-FREQ/24/1400%256, //3 mi
255-FREQ/24/1484/256,256-FREQ/24/1484%256, //4 fa
255-FREQ/24/1618/256,256-FREQ/24/1618%256, //5 suo
255-FREQ/24/1764/256,256-FREQ/24/1764%256, //6 la
255-FREQ/24/1968/256,256-FREQ/24/1968%256, //7 xi
};
unsigned char temp_TH1;
unsigned char temp_TL1;
// 音樂_編碼2 -- IO定義 //
sbit PIN_MSC=P1^0; // 音樂輸出端口 //
// 音樂_編碼2 -- 函數原型//
void music_delay(unsigned char x); //音樂節拍延時
void music_play(unsigned char *msc); //播放音樂子程序
// 音樂_編碼2 -- 函數 //
//---------------------------------------------------------------------------//
void music_int_t1 (void) interrupt 3 using 1 //定時中斷1//
{
PIN_MSC=~PIN_MSC;
TH1=temp_TH1;
TL1=temp_TL1;
}
//---------------------------------------------------------------------------//
void music_delay(unsigned char n) //延時 125*n 毫秒
{
unsigned char i=125,j;
do {
do {
for (j=0; j<230; j++) _nop_(); //j=(11159KHz/12-10)/4
}while(--i);
}while(--n);
}
//---------------------------------------------------------------------------//
void music_play(unsigned char *msc) //音樂
{
unsigned char music_freq=32; //音高
unsigned char music_long; //節拍
unsigned char music_data=0; //音符數據
bit music_up=0; //升半音
bit music_break=0; //斷奏
temp_TH1=0xff;
temp_TL1=0xea; //關輸出(輸出超聲波)
TMOD=0x11; //T0:16位定時器、T1:16位定時器
// ET0=0; //關T0定時器中斷
ET1=1; //開T1定時器中斷
//---------------------------------------------------------
while (*msc != 0x00)
{
music_data=*msc & 0x07;
music_long=*msc>>4;
//---------------------------------------------------------
if (music_long != 0) //是音符
{
if (*msc >=128) //需升降調
{
if (((*msc) & 0x08) == 0)
{if (music_freq >= 16) music_freq -= 16;} //音高下降
else
{if (music_freq < 48) music_freq += 16;} //音高上升
}
//---------------------------------------------------------
if (music_up==1) //升半音
{
temp_TH1=music_frequp_tab[(music_freq + (music_data <<1))];
temp_TL1=music_frequp_tab[(music_freq + (music_data <<1)+1)];
}
else //不升半音
{
temp_TH1=music_freq_tab[(music_freq + (music_data <<1))];
temp_TL1=music_freq_tab[(music_freq + (music_data <<1)+ 1)];
}
//---------------------------------------------------------
if (music_break) //斷奏
{
music_delay(music_l_tab[music_long&0x07]-1);
temp_TH1=0xff;
temp_TL1=0xea;
music_delay(1);
}
else //連奏
music_delay(music_l_tab[music_long&0x07]);
}
//---------------------------------------------------------
else //是功能碼
{
switch(music_data)
{
case 0x04:
music_up=0; //不升半音
break;
case 0x05:
music_up=1; //升半音
break;
case 0x06:
music_break=0; //斷奏
break;
case 0x07:
music_break=1; //連奏
break;
default:
break;
}
}
//---------------------------------------------------------
msc++;
}
ET1=0; //播放結束,關T1中斷
PIN_MSC=1; //關輸出
// temp_TH1=0xff;
// temp_TL1=0xea; //關輸出(輸出超聲波)
// ET0=1; //開T0定時器中斷
// TMOD=0x51; //T0:16位定時器、T1:16位計數器
}
//---------------------------------------------------------------------------//
void main(void) //示例
{
// 設置定時器--------------------------------------
TMOD = 0x11; // TMOD: 定時器1:模式1:16位;定時器2:模式1:16 位 //
// TCON = 0x50; // TCON: 定時器 1運行; 定時器 2運行 //
// 設置并開啟中斷:
IP = 0x08; //中斷優先寄存器IP:|D7_x |x|x |PS|PT1|PX1|PT0|D0_PX0|//
IE = 0x88; //中斷允許寄存器IE:|D7_EA|x|ET2|ES|ET1|EX1|ET0|D0_EX0|//
for (;;) {
//在此調用鍵盤和顯示函數//
music_play(music_tab1);
music_play(music_tab2);
music_play(music_tab3);
music_play(music_tab4);
}
}
//---------------------------------------------------------------------------//
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -