1. 程式人生 > 實用技巧 >【製作】基於金沙灘51微控制器的蜂鳴器音樂 - 克羅埃西亞狂想曲

【製作】基於金沙灘51微控制器的蜂鳴器音樂 - 克羅埃西亞狂想曲

基於金沙灘51微控制器的蜂鳴器音樂 - 克羅埃西亞狂想曲

當年剛學微控制器蜂鳴器不久做的一個小專案,能用蜂鳴器播放音樂,之前的網站掛了,在這裡重新發一下。

下面是原文:

當溫度超過設定值時,怎麼設定使蜂鳴器發出某首音樂聲?

敲黑板畫重點啦!!!這裡的重點是音樂聲而不是溫度超過設定值

於是去參考了下宋老師的程式碼:

蜂鳴器音樂例項程式碼

#include <reg52.h>

sbit BUZZ = P1^6;  //蜂鳴器控制引腳

unsigned int code NoteFrequ[] = {  //中音1-7和高音1-7對應頻率列表
    523,  587,  659,  698,  784,  880,  988,  //中音1-7
    1047, 1175, 1319, 1397, 1568, 1760, 1976  //高音1-7
};
unsigned int code NoteReload[] = { //中音1-7和高音1-7對應的定時器過載值
    65536 - (11059200/12) / (523*2),  //中音1
    65536 - (11059200/12) / (587*2),  //2
    65536 - (11059200/12) / (659*2),  //3
    65536 - (11059200/12) / (698*2),  //4
    65536 - (11059200/12) / (784*2),  //5
    65536 - (11059200/12) / (880*2),  //6
    65536 - (11059200/12) / (988*2),  //7
    65536 - (11059200/12) / (1047*2), //高音1
    65536 - (11059200/12) / (1175*2), //2
    65536 - (11059200/12) / (1319*2), //3
    65536 - (11059200/12) / (1397*2), //4
    65536 - (11059200/12) / (1568*2), //5
    65536 - (11059200/12) / (1760*2), //6
    65536 - (11059200/12) / (1976*2), //7
};
bit enable = 1;   //蜂鳴器發聲使能標誌
bit tmrflag = 0;  //定時器中斷完成標誌
unsigned char T0RH = 0xFF;  //T0過載值的高位元組
unsigned char T0RL = 0x00;  //T0過載值的低位元組

void PlayTwoTiger();

void main()
{
    unsigned int i;
    
    EA = 1;       //使能全域性中斷
    TMOD = 0x01;  //配置T0工作在模式1
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;      //使能T0中斷
    TR0 = 1;      //啟動T0
    
    while (1)
    {
        PlayTwoTiger();  //播放樂曲--兩支老虎
        for (i=0; i<40000; i++);  //停止一段時間
    }
}
/* 兩隻老虎樂曲播放函式 */
void PlayTwoTiger()
{
    unsigned char beat;   //當前節拍索引
    unsigned char note;   //當前節拍對應的音符
    unsigned int time = 0;      //當前節拍計時
    unsigned int beatTime = 0;  //當前節拍總時間
    unsigned int soundTime = 0; //當前節拍需發聲時間
    //兩隻老虎音符表
    unsigned char code TwoTigerNote[] = {
        1,   2,   3, 1,    1,   2,   3, 1,   3, 4, 5,   3, 4, 5,
        5,6, 5,4, 3, 1,    5,6, 5,4, 3, 1,   1, 5, 1,   1, 5, 1,
    };
    //兩隻老虎節拍表,4表示一拍,1就是1/4拍,8就是2拍
    unsigned char code TwoTigerBeat[] = {
        4,   4,   4, 4,    4,   4,   4, 4,   4, 4, 8,   4, 4, 8,
        3,1, 3,1, 4, 4,    3,1, 3,1, 4, 4,   4, 4, 8,   4, 4, 8,
    };
    
    for (beat=0; beat<sizeof(TwoTigerNote); )  //用節拍索引作為迴圈變數
    {
        while (!tmrflag);  //每次定時器中斷完成後,檢測並處理節拍
        tmrflag = 0;
        if (time == 0)  //當前節拍播完則啟動一個新節拍
        {
            note = TwoTigerNote[beat] - 1;
            T0RH = NoteReload[note] >> 8;
            T0RL = NoteReload[note];
            //計算節拍總時間,右移2位相當於除4,移位代替除法可以加快執行速度
            beatTime = (TwoTigerBeat[beat] * NoteFrequ[note]) >> 2;
            //計算髮聲時間,為總時間的0.75,移位原理同上
            soundTime = beatTime - (beatTime >> 2);
            enable = 1;  //指示蜂鳴器開始發聲
            time++;
        }
        else  //當前節拍未播完則處理當前節拍
        {
            if (time >= beatTime)  //當前持續時間到達節拍總時間時歸零,
            {                      //並遞增節拍索引,以準備啟動新節拍
                time = 0;
                beat++;
            }
            else  //當前持續時間未達到總時間時,
            {
                time++;   //累加時間計數
                if (time == soundTime)  //到達發聲時間後,指示關閉蜂鳴器,
                {                       //插入0.25*總時間的靜音間隔,
                    enable = 0;         //用以區分連續的兩個節拍
                }
            }
        }
    }
}
/* T0中斷服務函式,用於控制蜂鳴器發聲 */
void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;   //重新載入過載值
    TL0 = T0RL;
    tmrflag = 1;
    if (enable)   //使能時反轉蜂鳴器控制電平
        BUZZ = ~BUZZ;
    else          //未使能時關閉蜂鳴器
        BUZZ = 1;
}

下載到微控制器後,傳來了美妙的“兩隻老虎” ✧٩(ˊωˋ*)و✧

然而我並不喜歡把兩隻老虎作為報警音樂.......

宋老師的程式碼主要由資料和控制組成,而資料分為節拍資料和音調資料,那我們要換一首歌不就是換音調和節拍。

於是去百度“微控制器蜂鳴器音樂程式碼”,得到如下結果:

都是些八月桂花,生日快樂,兩隻蝴蝶,祝你平安這些經典音樂,沒有POP嗎?

那就自己動手吧,只要得到節拍資料和音調資料就好了,應該有轉換工具的,就像LED點陣一樣有點陣圖形轉換工具,於是百度:

還真有 (*≧▽≦) , 叫 music encode

於是下載,解包

還有Dome和說明,太好了。於是下載了Dome。是八月桂花....

然而我不喜歡這個,翻了翻音樂列表,就設定為“克羅埃西亞狂想曲”吧

٩(●´৺`●)૭٩(●´৺'●)و

於是去問度娘要樂譜,好不容易找到了由玉面小嫣然改編的古箏簡譜,其他的都是五線譜,原諒我看不懂五線譜 ( •̩̩̩̩_•̩̩̩̩ )


克羅埃西亞狂想曲鋼琴譜

找到樂譜後就開始輸樂譜........ (つд⊂) , 一個漫長的過程.........

終於輸好了,生成程式碼下載進去...... ٩(●´৺`●)૭٩(●´৺'●)و

克羅埃西亞狂想曲樂譜

樂譜

 0, 0, 0, 0,| 7__, .1__, 6_, 0, 3__, 4__, 2_, 0,| #, 4__, #, 5__, 3_, 3_, 7.__, 1__, 6._, 7.__, 1__, 6.,| 7__, .1__, 6_,  0, .3__, 6__, 3__, 4__, 2_, 0, 6__, 2__,|
 #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__, 6.,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,|
 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,| 7__, .1__, 6_,  0, .3__, 6__,  3__, 4__, 2_, 0,| #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__, 6.,| 7__, .1__, 6_,  0, .3__, 6__,  3__, 4__, 2_, 0,|
 #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__, 6.,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,|
 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,||| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| 7__, 3__, #, 5__, 6__,  7__, 3__, 5__, 7__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,|
 .3__, 3__, #, 5__, 3__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__, 6,||| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| 7__, 3__, #, 5__, 6__,  7__, 3__, 5__, 7__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,|
 .3__, 3__, #, 5__, 3__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__, 6,|| .3__, 6__, .1__, .2__,  .3__, 6__, .1__, .5__,  .4__, 6__, .3__, 6__, .2__, 6__, .1__, 6__,| .2__, 5__, 7__, .1__,  .2__, 5__, 7__, .4__,  .3__, 5__, .2__, 5__,  .1__, 5__, 7__, 5__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,|
 7_, 3_,  .1_, 7_,  6_, .3_,  .6,| 7_, 3_,  .1_, 7_,  6._, 6_,  6,| .3__, 6__, .1__, .2__,  .3__, 6__, .1__, .5__,  .4__, 6__, .3__, 6__,  .4__, 6__, .6__, 6__,| .5__, 7__, .2__, .6__,  .5__, 7__, .4__, 7__,  .3__, 3__, .2__, 3__,  .1__, 3__, 7__, 3__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,|
 7__, 3__, #, 5__, 7__,  .2__, 5__, 7__, .2__,  .3__, 7__, .2__, .3__,  #, .5__, .2__, .3__, .5__,| 7__, 3__, #, 5__, 7__,  .2__, 5__, 7__, .2__,  .3__, 7__, .2__, .3__,  #, .5__, .2__, .3__, .5__,| .6,  -,  -,  -,| 6.__, 1_, 3__,  2__, 6.__, 1__, 5.__,  6.__, 1_, 3__,  2__, 6.__, 1_,|
 0, 6__, 1__, 3__,  6.__, 1__, 6._,  0, #, 2.__, 3.__, 6.__,  1__, 2__, 1_,| 3.__, 5._, 3.__,  6.__,  3.__, 5.__, 2.__,  3.__, 5._, 3.__,  6.__, 3.__, 5._,| 7__, .1__, 6_,  0, .3__, 6__,  3__, 4__, 2_,  0,| #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,|
 7__, .1__, 6_,  0, .3__, 6__,  3__, 4__, 2_,  0,| #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  0, .3__, 6__,  7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,|
 7__, .1__, 6_,  0, .3__, 6__,  7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__, 6,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| 7__, 3__, #, 5__, 6__,  7__, 3__, 5__, 7__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,|
 .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| .3__, 3__, #, 5__, 3__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,  6,| .3__, 6__, .1__, .2__,  .3__, 6__, .1__, .5__,  .4__, 6__, .3__, 6__,  .4__, 6__, .6__, 6__,| .5__, 7__, .2__, .6__,  .5__, 7__, .4__, 7__,  .3__, 3__, .2__, 3__,  .1__, 3__, 7__, 3__,|
 .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| 7__, 3__, #, 5__, 7__,  .2__, 5__, 7__, .2__,  .3__, 7__, .2__, .3__,  #, .5__, .3__, .2__, .1__,| 7, -, .3, -,| 7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,|
 #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,| #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  0, .3__, 6__,  7__, .1__, 6_,  0, .3__, 6__,|
 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__,  6,| 7__, .1__, 6_,  0, .3__, 6__,  7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__,  6,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,|
 7__, 3__, #, 5__, 6__,  7__, 3__, 5__, 7__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| .3__, 3__, #, 5__, 3__,  .1__, 3__, 7__, 3__,  6__, 3__, .3__, 3__,  6,| .3__, 6__, .1__, .2__,  .3__, 6__, .1__, .5__,  .4__, 6__, .3__, 6__,  .4__, 6__, .6__, 6__,|
 .5__, 7__, .2__, .6__,  .5__, 7__, .4__, 7__,  .3__, 3__, .2__, 3__,  .1__, 3__, 7__, 3__,| .1__, 3__, 6__, 7__,  .1__, 3__, 6__, .1__,  .2__, 3__, .1__, 3__,  7__, 3__, 6__, 3__,| 7__, 3__, #, 5__, 7__,  .2__, 5__, 7__, .2__,  .3__, 7__, .2__, .3__,  #, .5__, .3__, .2__, .1__,|  7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,|
 #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,| #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,|
 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__,  6,| 7__, .1__, 6_,  0, .3__, 6__, 7__, .1__, 6_,  0, .3__, 6__,| 7__, .1__, 6_,  6_, #, 5__, 6__,  0, 7__, .1__,  6,| 7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,|
 #, 4__, #, 5__, 3_,  3_, 7.__, 1__,  6._, 7.__, 1__,  6.,| 7__, .1__, 6_,  7__, .1__, 6_,  3__, 4__, 2_,  3__, 4__, 2_,| #, 4__, #, 5__, 3_,  3_, 7_,  6_, .3_,  .6,| #, 4__, #, 5__, 3_,  3_, 7_,  3_, 6_,  .3,| #, 4__, #, 5__, 3_,  3_, 7_,  3_, 6_,  6,|

此處應有視訊......

Nice!

需要用到的原理圖和軟體

DS18B20讀寫時序

Music Encode:點選下載

原始碼和解釋:

只播放音樂的程式碼:(按K1可以暫停哦......)

#include <reg52.h>
 
sbit keyin = P2^4;
sbit keyout = P2^3;
 
/*----------------音樂函式申明------------------------------*/
void Play();
void InitialSound(unsigned char *Sound0,unsigned char Signature0,
    unsigned char Octachord0,unsigned int Speed0);
/*----------------音樂資料申明------------------------------*/
extern unsigned char code Music_Croatian_Rhapsody[];
//資料太大,放後面了,所以加extern以說明
void delay10ms(void)   //誤差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}
void main()
{
    unsigned int cnt = 0;
    InitialSound(Music_Croatian_Rhapsody,0,2,360);  //蜂鳴器初始化
     
    keyout = 0;
     
    while(1)
    {
        if(keyin == 0)
        {
            delay10ms();
            if(keyin == 0)
            {
                if(cnt<40)cnt = 200;
                else cnt = 20;
                while(keyin == 0);
            }
        }
         
        if(cnt < 40)
        {
            Play();                                 //蜂鳴器
        }
    }
}
 
 
 
/*-----------------------以下是蜂鳴器演奏------------------*/
#define SYSTEM_OSC      11059200    //12000000  //定義晶振頻率12000000HZ
#define SOUND_SPACE     4/5         //定義普通音符演奏的長度分率,//每4分音符間隔
sbit    BeepIO    =     P1^6;       //定義輸出管腳
 
unsigned int  code FreTab[12]  = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始頻率表
unsigned char code SignTab[7]  = { 0,2,4,5,7,9,11 };                                  //1~7在頻率表中的位置
unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };                      
unsigned char Sound_Temp_TH0,Sound_Temp_TL0;    //音符定時器初值暫存 
unsigned char Sound_Temp_TH1,Sound_Temp_TL1;    //音長定時器初值暫存
unsigned char Signature;
unsigned char Octachord;
unsigned int Speed;
unsigned char *Sound;
unsigned int NewFreTab[12];                     //新的頻率表
unsigned char i,j;
unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
 
void InitialSound(unsigned char *Sound0,unsigned char Signature0,unsigned char Octachord0,unsigned int Speed0)
{
        Signature = Signature0;
    Octachord = Octachord0;
    Speed = Speed0;
    Sound = Sound0;
    
    for(i=0;i<12;i++)               // 根據調號及升降八度來生成新的頻率表 
    {
        j = i + Signature;
        if(j > 11)
        {
            j = j-12;
            NewFreTab[i] = FreTab[j]*2;
        }
        else
            NewFreTab[i] = FreTab[j];

        if(Octachord == 1)
            NewFreTab[i]>>=2;
        else if(Octachord == 3)
            NewFreTab[i]<<=2;
    }                                   
    
    SoundLength = 1;
    while(Sound[SoundLength] != 0x00)   //計算歌曲長度
    {
        SoundLength+=2;
    }

    Point = 0;
    Tone   = Sound[Point];  
    Length = Sound[Point+1];            // 讀出第一個音符和它時時值
    
    LDiv0 = 12000/Speed;                // 算出1分音符的長度(幾個10ms)    
    LDiv4 = LDiv0/4;                    // 算出4分音符的長度 
    LDiv4 = LDiv4-LDiv4*SOUND_SPACE;    // 普通音最長間隔標準 
    
    BeepIO = 1;
    Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;   // 計算TL1應裝入的初值  (10ms的初裝值)
    Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;   // 計算TH1應裝入的初值 
    TH1 = Sound_Temp_TH1;
    TL1 = Sound_Temp_TL1;
    TMOD  |= 0x11;
    ET0    = 1;
    ET1    = 0;
    TR0    = 0;
    TR1    = 0;
    EA     = 1;
}
 
void BeepTimer0(void) interrupt 1   //音符發生中斷
{
    BeepIO = !BeepIO;
    TH0    = Sound_Temp_TH0;
    TL0    = Sound_Temp_TL0;
}
 
void Play()
{
    EA = 1;
    TR0   = 0;
    TR1   = 1;
    if(Point < SoundLength)
    {
        SL=Tone%10;                                 //計算出音符 
        SM=Tone/10%10;                              //計算出高低音 
        SH=Tone/100;                                //計算出是否升半 
        CurrentFre = NewFreTab[SignTab[SL-1]+SH];   //查出對應音符的頻率     
        if(SL!=0)
        {
            if (SM==1) CurrentFre >>= 2;        //低音 
            if (SM==3) CurrentFre <<= 2;        //高音
            Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//計算計數器初值
            Sound_Temp_TH0 = Temp_T/256; 
            Sound_Temp_TL0 = Temp_T%256; 
            TH0 = Sound_Temp_TH0;  
            TL0 = Sound_Temp_TL0 + 12; //加12是對中斷延時的補償 
        }
        SLen=LengthTab[Length%10];  //算出是幾分音符
        XG=Length/10%10;            //算出音符型別(0普通1連音2頓音) 
        FD=Length/100;
        LDiv=LDiv0/SLen;            //算出連音音符演奏的長度(多少個10ms)
        if (FD==1) 
        {
            LDiv=LDiv+LDiv/2;
        }
        
        if(XG!=1)
        {           
            if(XG==0)               //算出普通音符的演奏長度 
            {
                if (SLen<=4)    
                {
                    LDiv1=LDiv-LDiv4;
                }else{
                    LDiv1=LDiv*SOUND_SPACE;
                }
            }else{
                LDiv1=LDiv/2;       //算出頓音的演奏長度 
            }
        }else{
            LDiv1=LDiv;
        }
        
        if(SL==0) 
        {
            LDiv1=0;
        }
        
        LDiv2=LDiv-LDiv1;       //算出不發音的長度 
        
        if (SL!=0)
        {
            TR0=1;
            for(i=LDiv1;i>0;i--)    //發規定長度的音 
            {
                while(TF1==0);      //等待節拍過去
                TH1 = Sound_Temp_TH1;//重灌初值
                TL1 = Sound_Temp_TL1;
                TF1=0;              //清除中斷標誌位
            }
        }
        
        if(LDiv2!=0)
        {
            TR0=0; BeepIO=1;
            for(i=LDiv2;i>0;i--)    //音符間的間隔
            {
                while(TF1==0);      //等待節拍過去
                TH1 = Sound_Temp_TH1;//重灌初值
                TL1 = Sound_Temp_TL1;
                TF1=0;              //清除中斷標誌位
            }
        }
        
        Point+=2; 
        Tone=Sound[Point];
        Length=Sound[Point+1];
        
    }
    else
    {
        /*SoundLength = len;
        Point = poi;*/
        InitialSound(Music_Croatian_Rhapsody,0,2,360);
    }
    BeepIO = 1;
    
    TR0   = 0;
    TR1   = 0;
}
 
//這裡放生成的音樂資料
unsigned char code Music_Croatian_Rhapsody[]={
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x17,0x04, 0x18,0x04,
    0x16,0x7B, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x17,0x04, 0x18,0x04, 0x16,0x17, 0x1A,0x04,
    0x16,0x68, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67,
    0x19,0x04, 0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67, 0x19,0x04,
    0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x17,0x04,
    0x18,0x04, 0x16,0x7B, 0x18,0x68, 0x19,0x04, 0x17,0x03,
    0x17,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04,
    0x15,0x04, 0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17,
    0x21,0x04, 0x1A,0x04, 0x17,0x04, 0x18,0x04, 0x16,0x7B,
    0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03, 0x11,0x04,
    0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x02,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67, 0x19,0x04,
    0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x03, 0x1A,0x67, 0x19,0x04, 0x1A,0x18,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x02, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x68, 0x19,0x04, 0x1A,0x04, 0x1B,0x04, 0x17,0x04,
    0x19,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x04,
    0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04,
    0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04,
    0x17,0x04, 0x21,0x04, 0x17,0x68, 0x19,0x04, 0x17,0x04,
    0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04,
    0x17,0x04, 0x21,0x04, 0x17,0x04, 0x1A,0x02, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x68, 0x19,0x04, 0x1A,0x04, 0x1B,0x04,
    0x17,0x04, 0x19,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1B,0x04,
    0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x68, 0x19,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x04, 0x1A,0x02,
    0x21,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x21,0x04,
    0x1A,0x04, 0x1F,0x04, 0x23,0x04, 0x22,0x04, 0x1A,0x04,
    0x21,0x04, 0x1A,0x04, 0x20,0x04, 0x1A,0x04, 0x1F,0x04,
    0x1A,0x04, 0x20,0x04, 0x19,0x04, 0x1B,0x04, 0x1F,0x04,
    0x20,0x04, 0x19,0x04, 0x1B,0x04, 0x22,0x04, 0x21,0x04,
    0x19,0x04, 0x20,0x04, 0x19,0x04, 0x1F,0x04, 0x19,0x04,
    0x1B,0x04, 0x19,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04,
    0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x1B,0x03, 0x17,0x03,
    0x1F,0x03, 0x1B,0x03, 0x1A,0x03, 0x21,0x03, 0x24,0x02,
    0x1B,0x03, 0x17,0x03, 0x1F,0x03, 0x1B,0x03, 0x10,0x03,
    0x1A,0x03, 0x1A,0x02, 0x21,0x04, 0x1A,0x04, 0x1F,0x04,
    0x20,0x04, 0x21,0x04, 0x1A,0x04, 0x1F,0x04, 0x23,0x04,
    0x22,0x04, 0x1A,0x04, 0x21,0x04, 0x1A,0x04, 0x22,0x04,
    0x1A,0x04, 0x24,0x04, 0x1A,0x04, 0x23,0x04, 0x1B,0x04,
    0x20,0x04, 0x24,0x04, 0x23,0x04, 0x1B,0x04, 0x22,0x04,
    0x1B,0x04, 0x21,0x04, 0x17,0x04, 0x20,0x04, 0x17,0x04,
    0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x68, 0x19,0x04, 0x1B,0x04, 0x20,0x04,
    0x19,0x04, 0x1B,0x04, 0x20,0x04, 0x21,0x04, 0x1B,0x04,
    0x20,0x04, 0x21,0x68, 0x23,0x04, 0x20,0x04, 0x21,0x04,
    0x23,0x04, 0x1B,0x04, 0x17,0x68, 0x19,0x04, 0x1B,0x04,
    0x20,0x04, 0x19,0x04, 0x1B,0x04, 0x20,0x04, 0x21,0x04,
    0x1B,0x04, 0x20,0x04, 0x21,0x68, 0x23,0x04, 0x20,0x04,
    0x21,0x04, 0x23,0x04, 0x24,0x00, 0x10,0x04, 0x15,0x03,
    0x17,0x04, 0x16,0x04, 0x10,0x04, 0x15,0x04, 0x0F,0x04,
    0x10,0x04, 0x15,0x03, 0x17,0x04, 0x16,0x04, 0x10,0x04,
    0x15,0x17, 0x1A,0x04, 0x15,0x04, 0x17,0x04, 0x10,0x04,
    0x15,0x04, 0x10,0x7B, 0x0C,0x04, 0x0D,0x04, 0x10,0x04,
    0x15,0x04, 0x16,0x04, 0x15,0x03, 0x0D,0x04, 0x0F,0x03,
    0x0D,0x04, 0x10,0x04, 0x0D,0x04, 0x0F,0x04, 0x0C,0x04,
    0x0D,0x04, 0x0F,0x03, 0x0D,0x04, 0x10,0x04, 0x0D,0x04,
    0x0F,0x03, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x17,0x04, 0x18,0x04, 0x16,0x7B, 0x18,0x68,
    0x19,0x04, 0x17,0x03, 0x17,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x02, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x17,0x04,
    0x18,0x04, 0x16,0x7B, 0x18,0x68, 0x19,0x04, 0x17,0x03,
    0x17,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04,
    0x15,0x04, 0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17,
    0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17,
    0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03,
    0x1A,0x67, 0x19,0x04, 0x1A,0x18, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67,
    0x19,0x04, 0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02,
    0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04,
    0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x68, 0x19,0x04, 0x1A,0x04,
    0x1B,0x04, 0x17,0x04, 0x19,0x04, 0x1B,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x21,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04,
    0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x68,
    0x19,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x04,
    0x1A,0x02, 0x21,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04,
    0x21,0x04, 0x1A,0x04, 0x1F,0x04, 0x23,0x04, 0x22,0x04,
    0x1A,0x04, 0x21,0x04, 0x1A,0x04, 0x22,0x04, 0x1A,0x04,
    0x24,0x04, 0x1A,0x04, 0x23,0x04, 0x1B,0x04, 0x20,0x04,
    0x24,0x04, 0x23,0x04, 0x1B,0x04, 0x22,0x04, 0x1B,0x04,
    0x21,0x04, 0x17,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x68, 0x19,0x04, 0x1B,0x04, 0x20,0x04, 0x19,0x04,
    0x1B,0x04, 0x20,0x04, 0x21,0x04, 0x1B,0x04, 0x20,0x04,
    0x21,0x68, 0x23,0x04, 0x21,0x04, 0x20,0x04, 0x1F,0x04,
    0x1B,0x01, 0x21,0x01, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x17,0x04, 0x18,0x04,
    0x16,0x03, 0x17,0x04, 0x18,0x04, 0x16,0x67, 0x18,0x68,
    0x19,0x04, 0x17,0x03, 0x17,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x02, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x03, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03,
    0x17,0x04, 0x18,0x04, 0x16,0x03, 0x17,0x04, 0x18,0x04,
    0x16,0x67, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67,
    0x19,0x04, 0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x21,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1A,0x67, 0x19,0x04,
    0x1A,0x18, 0x1B,0x04, 0x1F,0x04, 0x1A,0x02, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x68, 0x19,0x04, 0x1A,0x04, 0x1B,0x04,
    0x17,0x04, 0x19,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1B,0x04,
    0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x68, 0x19,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x04, 0x1A,0x02,
    0x21,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x21,0x04,
    0x1A,0x04, 0x1F,0x04, 0x23,0x04, 0x22,0x04, 0x1A,0x04,
    0x21,0x04, 0x1A,0x04, 0x22,0x04, 0x1A,0x04, 0x24,0x04,
    0x1A,0x04, 0x23,0x04, 0x1B,0x04, 0x20,0x04, 0x24,0x04,
    0x23,0x04, 0x1B,0x04, 0x22,0x04, 0x1B,0x04, 0x21,0x04,
    0x17,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04,
    0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x68,
    0x19,0x04, 0x1B,0x04, 0x20,0x04, 0x19,0x04, 0x1B,0x04,
    0x20,0x04, 0x21,0x04, 0x1B,0x04, 0x20,0x04, 0x21,0x68,
    0x23,0x04, 0x21,0x04, 0x20,0x04, 0x1F,0x04, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x03, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03,
    0x17,0x04, 0x18,0x04, 0x16,0x03, 0x17,0x04, 0x18,0x04,
    0x16,0x67, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x03, 0x17,0x04, 0x18,0x04, 0x16,0x03,
    0x17,0x04, 0x18,0x04, 0x16,0x67, 0x18,0x68, 0x19,0x04,
    0x17,0x03, 0x17,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x02, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x17, 0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x03, 0x1A,0x67, 0x19,0x04, 0x1A,0x18, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17,
    0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x17,
    0x21,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03,
    0x1A,0x67, 0x19,0x04, 0x1A,0x18, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x02, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x1B,0x04,
    0x1F,0x04, 0x1A,0x03, 0x17,0x04, 0x18,0x04, 0x16,0x03,
    0x17,0x04, 0x18,0x04, 0x16,0x67, 0x18,0x68, 0x19,0x04,
    0x17,0x03, 0x17,0x03, 0x11,0x04, 0x15,0x04, 0x10,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x02, 0x1B,0x04, 0x1F,0x04,
    0x1A,0x03, 0x1B,0x04, 0x1F,0x04, 0x1A,0x03, 0x17,0x04,
    0x18,0x04, 0x16,0x03, 0x17,0x04, 0x18,0x04, 0x16,0x67,
    0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03, 0x1B,0x03,
    0x1A,0x03, 0x21,0x03, 0x24,0x66, 0x18,0x68, 0x19,0x04,
    0x17,0x03, 0x17,0x03, 0x1B,0x03, 0x17,0x03, 0x1A,0x03,
    0x21,0x66, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x1B,0x03, 0x17,0x03, 0x1A,0x03, 0x1A,0x02, 0x00,0x00
};

題目的程式碼,emmm.....音樂資料太多,只放了一小段

#include <reg52.h>
#include <intrins.h>
//_nop_()函式所在標頭檔案

char code waringset = 22;   //報警溫度

/*----------------音樂函式申明------------------------------*/
void InitialSound(unsigned char *Sound0,unsigned char Signature0,
    unsigned char Octachord0,unsigned int Speed0);
void Play();


/*----------------音樂資料申明------------------------------*/
extern unsigned char code Music_Croatian_Rhapsody[];
//(資料太大,放後面了,所以加extern以說明)


/*----------------溫度感測器申明----------------------------*/
bit Start18B20();           //初始化DS18B20
bit Get18B20Temp(int *temp);//讀取溫度


/*----------------LCD1602顯示模組申明------------------------*/
void InitLcd1602();         //LCD1602初始化函式
void display();         //顯示控制模組

/*-------------------LCD1602顯示快取-------------------------*/
unsigned char strbuff[11];//格式:“+125.0.0625°C”
unsigned char code waringstr[] = "     Alarm!     ";//報警顯示文字
unsigned char code striswaring[] = "            ";//取消報警顯示文字


/*----------------------其他全域性變數-------------------------*/
int Temp = 0;       //讀取到的當前溫度值(16bit二進位制)
int intT, decT;     //溫度值的整數和小數部分
bit sign;           //溫度值的正負(1正,0負)
bit iswaring = 0;   //是否報警標誌位

void main()
{
    bit sta;                //是否成功讀取標誌
    unsigned int cnt = 0;   //檢測標誌,主要用於控制檢測溫度的頻率
    
    InitialSound(Music_Croatian_Rhapsody,0,2,360);  //蜂鳴器初始化
    Start18B20();           //啟動DS18B20
    InitLcd1602();          //初始化LCD1602液晶模組
    
    while(1)
    {
        cnt++;
        if(((iswaring == 0)&&(cnt>14000))||((iswaring == 1)&&(cnt>3)))              //大約0.8s(模擬得到) DS18B20最多750ms轉化好
        {
            cnt = 0;
            sta = Get18B20Temp(&Temp);  //讀取當前溫度
            if (sta)                    //讀取成功時,重新整理當前溫度顯示
            {
                if((Temp >> 11) < 4)    //如果前面5位大部分是0
                {
                    sign = 1;           //正號,溫度值為正
                }else{
                    sign = 0;           //溫度值為負
                }
                
                if(sign == 1)           //正號
                {
                    intT = Temp >> 4;       //分離出溫度值整數部分
                    decT = Temp & 0x0F;     //分離出溫度值小數部分
                    decT = decT * 625;      //小數轉換成10進位制精度
                    //ftemp = intT + decT/10000;/*無效*/  //轉換為浮點,以便比較
                }else{                  //負號
                    Temp = (~Temp)+1;       //取反後+1
                    intT = (Temp >> 4)*(-1);//分離出溫度值整數部分
                    decT = Temp & 0x0F;     //分離出溫度值小數部分
                    decT = decT * 625;      //小數轉換成10進位制精度           
                    //ftemp = (intT + decT/10000)*(-1);//轉換為浮點
                }
            }
            else                            //讀取失敗時,給出錯誤資訊
            {
                intT = 200;                 //這個值隨便給,主要是大於126就好
                //ftemp = intT;
            }
            Start18B20();                   //重新啟動下一次轉換
            display();                      //顯示
            
            if(intT >= waringset)
            {
                iswaring = 1;
            }else{
                iswaring = 0;
            }
            
        }
        
        if((iswaring == 1)&&(intT<126)&&(intT>-55))
        {
            Play();                                 //蜂鳴器
        }else{
            EA = 0;         //蜂鳴器是用中斷,關掉
        }
    }
}

/*-----------------------以下是LCD1602顯示驅動------------------*/
//定義LCD1602顯示相關的IO介面
#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;
//LCD1602函式呼叫申明
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
//顯示控制模組
void display()
{
    
    static int intTb, decTb;    //溫度值的整數和小數部分備份
    static bit signb;           //溫度值的正負(1正,0負)備份
    if(iswaring == 1)
    {
        LcdShowStr(0,1,waringstr,16);
    }
    else
    {
        LcdShowStr(0,1,striswaring,11);
    }
    if((decTb != decT) || (intTb != intT) || (signb != sign))//如果有變化
    {
        /*備份當前值*/
        decTb = decT;
        intTb = intT;
        signb = sign;
        if(intT>126)    //如果資訊錯誤,這個判斷是溫度顯示特有的
        {
            unsigned char i = 1;
            //顯示錯誤Error!
            strbuff[10] = '!';
            strbuff[9] = 'r';
            strbuff[8] = 'o';
            strbuff[7] = 'r';
            strbuff[6] = 'r';
            strbuff[5] = 'E';
            for(i = 0;i<5;i++)
            {
                strbuff[i] = ' ';
            }
        }else{          //資訊正確
            if(sign == 1)strbuff[0] = ' ';else strbuff[0] = '-';//符號位
            if((intT/100) == 0)strbuff[1] = ' ';else strbuff[1] = ((intT/100)%10)+0x30;//百位
            if((intT/10) == 0)strbuff[2] = ' ';else strbuff[2] = ((intT/10)%10)+0x30;//十位
            if((intT) == 0)strbuff[3] = ' ';else strbuff[3] = (intT%10)+0x30;//個位加“.”
            if((decT/1000) == 0)strbuff[5] = '0';else strbuff[5] = ((decT/1000)%10)+0x30;//十分位
            if((decT/100) == 0)strbuff[6] = '0';else strbuff[6] = ((decT/100)%10)+0x30;//百分位
            if((decT/10) == 0)strbuff[7] = '0';else strbuff[7] = ((decT/10)%10)+0x30;//千分位
            if((decT) == 0)strbuff[8] = '0';else strbuff[8] = (decT%10)+0x30;//萬分位
            /*以上是 載數碼管快取程式碼,把十進位制分離,大家自己研究這裡不多解釋*/
            strbuff[4] = '.';
            strbuff[9] = 0XDF;//‘°’
            strbuff[10] = 'C';
        }
        
        LcdShowStr(4,0,strbuff,11); //顯示,初始位置隨意,只要能顯示完整就好
    }
}

//等待液晶準備好
void LcdWaitReady()
{
    unsigned char sta;
     
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;      //使能LCD1602
        sta = LCD1602_DB;   //讀取狀態字
        LCD1602_E = 0;      //避免干擾其他器件
    } while (sta & 0x80);   //第七位等於1表示液晶正忙,重複檢測直到第七位等於0為止
}
//向LCD1602液晶寫入一位元組命令,cmd為待寫入命令值
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//向LCD1602液晶寫入一位元組資料,dat為待寫入資料值
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//設定顯示RAM起始地址,亦即游標位置,(x,y)對應螢幕上的字元的座標
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
     
    if (y == 0)             //由輸入的螢幕座標計算顯示RAM的地址
        addr = 0x00 + x;    //第一行字元地址從0x00起始
    else
        addr = 0x40 + x;    //第二行字元地址從0x40起始
    LcdWriteCmd(addr | 0x80);   //設定RAM地址
}
//在液晶上顯示字串,(x,y)-對應螢幕上的起始座標,
//str-字串指標,len-需顯示的字元長度
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
{
    LcdSetCursor(x, y);   //設定起始地址
    while (len--)         //連續寫入len個字元資料
    {
        LcdWriteDat(*str++);  //先取str指向的資料,然後str自加1
    }
}

void InitLcd1602()//初始化1602液晶
{
    LcdWriteCmd(0x38);  //16*2顯示,5*7點陣,8位資料介面
    LcdWriteCmd(0x0C);  //顯示器開,游標關閉
    LcdWriteCmd(0x06);  //文字不動,地址自動+1
    LcdWriteCmd(0x01);  //清屏
}


/*-----------------------以下是溫度感測器驅動------------------*/
//DS18B20通訊引腳
sbit IO_18B20 = P3^2;
void DelayX10us(unsigned char t)
{
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
    /*_nop_()函式在12M晶振中延遲1us,為什麼這裡是8個_nop_()
    因為while和--t也是需要時間的,這裡不一定是準確的10us/迴圈
    只是大致的時間*/
}
bit Get18B20Ack() //DS18B20存在檢測函式 
{
    bit ack;

    EA = 0;             //關中斷 
    IO_18B20 = 0;       //拉低引腳 
    DelayX10us(50);     //延時500us(480us - 960us) 
    IO_18B20 = 1;       //釋放匯流排 
    DelayX10us(6);      //延時60us(15us - 60us) 
    ack = IO_18B20;     //讀取響應(60us - 240us) 
    while(!IO_18B20);   //等待DS18B20釋放匯流排 (60us - 240us) 
    EA = 1;             //取消關中斷 

    return ack;         //返回是否存在 (0:存在 1:不存在) 
}

void  Write18B20(unsigned char dat) //寫DS18B20 
{
    unsigned char mask;         //臨時變數定義 
    EA = 0;                     //關中斷 
    for(mask=0x01; mask!= 0; mask<<=1)  //迴圈傳送單個bit位 
    {
        IO_18B20 = 0;           //拉低(請求讀寫操作) 
        _nop_();                //延時(1us < time <= 15us) 
        _nop_();
        if((mask&dat) == 0)     //按位讀取dat 
            IO_18B20 = 0;       //本位是0,拉低 
        else
            IO_18B20 = 1;       //本位是1,拉高 
            //上面這個操作DS18B20讀取(最小時間 0us<time<15us,
            //典型時間 15us,最大時間45us) 
        DelayX10us(6);          //等待60us(足夠DS18B20讀取) 
        IO_18B20 = 1;           //釋放匯流排 
    }
    EA = 1;                     //取消關中斷 
}

unsigned char Read18B20()       //讀DS18B20 
{
    unsigned char dat;          //資料快取變數 
    unsigned char mask;         //臨時變數 

    EA = 0;                     //關中斷 
    for(mask=0x01; mask!=0; mask<<=1)//同上迴圈按位操作 
    {
        IO_18B20 = 0;           //讀寫請求 
        _nop_();                //等待(1us < time < 15us) 
        _nop_();
        IO_18B20 = 1;           //初始化讀操作 
        _nop_();                //等待DS18B20輸出 
        _nop_();
        if(!IO_18B20)           //讀 
            dat &= ~mask;       //“0” 
        else
            dat |= mask;        //“1” 
        DelayX10us(6);          //等待DS18B20釋放匯流排 
    }
    EA = 1;                     //取消關中斷 

    return dat;                 //返回資料 
}

bit Start18B20()        //初始化DS18B20 
{
    bit ack;            //存在標誌 

    ack = Get18B20Ack();//檢測存在 
    if(ack == 0)        //存在 
    {                   //寫命令使工作
        Write18B20(0xCC);   //跳過ROM檢測 
        Write18B20(0x44);   //啟動溫度轉換 
    }
    return ~ack;        //返回是否成功(1是,0否) 
}

bit Get18B20Temp(int *temp) //獲取DS18B20溫度存於temp 
{
    bit ack;                //存在標誌 
    unsigned char LSB, MSB; //資料低/高位 

    ack = Get18B20Ack();    //檢測存在 
    if(ack == 0)            //存在 
    {                       //寫指令 
        Write18B20(0xCC);   //跳過ROM檢測 
        Write18B20(0xBE);   //讀暫存器 
        LSB = Read18B20();  //讀低位 
        MSB = Read18B20();  //讀高位 
        *temp = ((int)MSB<<8) + LSB;    //合併 
    }
    return ~ack;            //返回結果(1成功,0失敗) 
}


/*-----------------------以下是蜂鳴器演奏------------------*/
#define SYSTEM_OSC      11059200    //12000000  //定義晶振頻率12000000HZ
#define SOUND_SPACE     4/5         //定義普通音符演奏的長度分率,//每4分音符間隔
sbit    BeepIO    =     P1^6;       //定義輸出管腳

unsigned int  code FreTab[12]  = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始頻率表
unsigned char code SignTab[7]  = { 0,2,4,5,7,9,11 };                                  //1~7在頻率表中的位置
unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };                      
unsigned char Sound_Temp_TH0,Sound_Temp_TL0;    //音符定時器初值暫存 
unsigned char Sound_Temp_TH1,Sound_Temp_TL1;    //音長定時器初值暫存
unsigned char Signature;
unsigned char Octachord;
unsigned int Speed;
unsigned char *Sound;
unsigned int NewFreTab[12];                     //新的頻率表
unsigned char i,j;
unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;
unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;
//unsigned int len = 0,poi = 0;     //備份SoundLength


void InitialSound(unsigned char *Sound0,unsigned char Signature0,
    unsigned char Octachord0,unsigned int Speed0)
{
    Signature = Signature0;
    Octachord = Octachord0;
    Speed = Speed0;
    Sound = Sound0;
    
    for(i=0;i<12;i++)               // 根據調號及升降八度來生成新的頻率表 
    {
        j = i + Signature;
        if(j > 11)
        {
            j = j-12;
            NewFreTab[i] = FreTab[j]*2;
        }
        else
            NewFreTab[i] = FreTab[j];

        if(Octachord == 1)
            NewFreTab[i]>>=2;
        else if(Octachord == 3)
            NewFreTab[i]<<=2;
    }                                   
    
    SoundLength = 1;
    while(Sound[SoundLength] != 0x00)   //計算歌曲長度
    {
        SoundLength+=2;
    }

    Point = 0;
    Tone   = Sound[Point];  
    Length = Sound[Point+1];            // 讀出第一個音符和它時時值
    
    LDiv0 = 12000/Speed;                // 算出1分音符的長度(幾個10ms)    
    LDiv4 = LDiv0/4;                    // 算出4分音符的長度 
    LDiv4 = LDiv4-LDiv4*SOUND_SPACE;    // 普通音最長間隔標準 
    
    BeepIO = 1;
    Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;   // 計算TL1應裝入的初值  (10ms的初裝值)
    Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;   // 計算TH1應裝入的初值 
    TH1 = Sound_Temp_TH1;
    TL1 = Sound_Temp_TL1;
    TMOD  |= 0x11;
    ET0    = 1;
    ET1    = 0;
    TR0    = 0;
    TR1    = 0;
    EA     = 1;
        
    /*len = SoundLength;
    poi = Point;*/
}

void BeepTimer0(void) interrupt 1   //音符發生中斷
{
    BeepIO = !BeepIO;
    TH0    = Sound_Temp_TH0;
    TL0    = Sound_Temp_TL0;
}

void Play()
{
    EA = 1;
    TR0   = 0;
    TR1   = 1;
    if(Point < SoundLength)
    {
        SL=Tone%10;                                 //計算出音符 
        SM=Tone/10%10;                              //計算出高低音 
        SH=Tone/100;                                //計算出是否升半 
        CurrentFre = NewFreTab[SignTab[SL-1]+SH];   //查出對應音符的頻率     
        if(SL!=0)
        {
            if (SM==1) CurrentFre >>= 2;        //低音 
            if (SM==3) CurrentFre <<= 2;        //高音
            Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//計算計數器初值
            Sound_Temp_TH0 = Temp_T/256; 
            Sound_Temp_TL0 = Temp_T%256; 
            TH0 = Sound_Temp_TH0;  
            TL0 = Sound_Temp_TL0 + 12; //加12是對中斷延時的補償 
        }
        SLen=LengthTab[Length%10];  //算出是幾分音符
        XG=Length/10%10;            //算出音符型別(0普通1連音2頓音) 
        FD=Length/100;
        LDiv=LDiv0/SLen;            //算出連音音符演奏的長度(多少個10ms)
        if (FD==1) 
        {
            LDiv=LDiv+LDiv/2;
        }
        
        if(XG!=1)
        {           
            if(XG==0)               //算出普通音符的演奏長度 
            {
                if (SLen<=4)    
                {
                    LDiv1=LDiv-LDiv4;
                }else{
                    LDiv1=LDiv*SOUND_SPACE;
                }
            }else{
                LDiv1=LDiv/2;       //算出頓音的演奏長度 
            }
        }else{
            LDiv1=LDiv;
        }
        
        if(SL==0) 
        {
            LDiv1=0;
        }
        
        LDiv2=LDiv-LDiv1;       //算出不發音的長度 
        
        if (SL!=0)
        {
            TR0=1;
            for(i=LDiv1;i>0;i--)    //發規定長度的音 
            {
                while(TF1==0);      //等待節拍過去
                TH1 = Sound_Temp_TH1;//重灌初值
                TL1 = Sound_Temp_TL1;
                TF1=0;              //清除中斷標誌位
            }
        }
        
        if(LDiv2!=0)
        {
            TR0=0; BeepIO=1;
            for(i=LDiv2;i>0;i--)    //音符間的間隔
            {
                while(TF1==0);      //等待節拍過去
                TH1 = Sound_Temp_TH1;//重灌初值
                TL1 = Sound_Temp_TL1;
                TF1=0;              //清除中斷標誌位
            }
        }
        
        Point+=2; 
        Tone=Sound[Point];
        Length=Sound[Point+1];
        
    }
    else
    {
        /*SoundLength = len;
        Point = poi;*/
        InitialSound(Music_Croatian_Rhapsody,0,2,360);
    }
    BeepIO = 1;
    
    TR0   = 0;
    TR1   = 0;
}

//這裡放生成的音樂資料
unsigned char code Music_Croatian_Rhapsody[]={
    0x1B,0x04, 0x1F,0x04, 0x1A,0x17, 0x17,0x04, 0x18,0x04,
    0x16,0x7B, 0x18,0x68, 0x19,0x04, 0x17,0x03, 0x17,0x03,
    0x11,0x04, 0x15,0x04, 0x10,0x03, 0x11,0x04, 0x15,0x04,
    0x10,0x02, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1B,0x04,
    0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04, 0x20,0x04,
    0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x68, 0x19,0x04,
    0x1A,0x04, 0x1B,0x04, 0x17,0x04, 0x19,0x04, 0x1B,0x04,
    0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04,
    0x17,0x04, 0x21,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04,
    0x17,0x68, 0x19,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04,
    0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x21,0x04,
    0x17,0x04, 0x1A,0x02, 0x1F,0x04, 0x17,0x04, 0x1A,0x04,
    0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1A,0x04, 0x1F,0x04,
    0x20,0x04, 0x17,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04,
    0x17,0x04, 0x1A,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x68,
    0x19,0x04, 0x1A,0x04, 0x1B,0x04, 0x17,0x04, 0x19,0x04,
    0x1B,0x04, 0x1F,0x04, 0x17,0x04, 0x1B,0x04, 0x17,0x04,
    0x1A,0x04, 0x17,0x04, 0x21,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1A,0x04, 0x1B,0x04, 0x1F,0x04, 0x17,0x04,
    0x1A,0x04, 0x1F,0x04, 0x20,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x21,0x04, 0x17,0x68, 0x19,0x04, 0x17,0x04, 0x1F,0x04,
    0x17,0x04, 0x1B,0x04, 0x17,0x04, 0x1A,0x04, 0x17,0x04,
    0x21,0x04, 0x17,0x04, 0x1A,0x02, 0x00,0x00
};

怎麼樣

音樂是不是很動聽呢? ٩(●´৺`●)૭٩(●´৺'●)و,想嘗試創作更多的蜂鳴器音樂嗎?快發表你的看法吧!!

嗶哩嗶哩效果視訊演示:https://www.bilibili.com/video/BV1Dt41197b9/

謝謝