/*--------------------------------------------------------------------------
程序在硬件上调试通过
本程序的单片机晶振采用11.0592M ,
曲目为《上海滩》的主题曲
---------------------------------------------------------------------------*/
#include <reg51.h>
sbit speaker=P2^3;
unsigned char timer0h,timer0l,time;
unsigned char bdata flg;
sbit flag=flg^0;
bit er;
//上海滩数据表:一个音符有三个数字。前为第几个音、中为第几个八度、后为时长(以半拍为单位)
code unsigned char sszymmh[]={ 3,1,1, 5,1,1, 6,1,3, /*0,0,1, 0,0,1,*/ 3,1,1, 5,1,1,
2,1,2, /*0,0,1,*/ 0,0,1, 3,1,1, 5,1,1, 6,1,1, 1,2,2, 6,1,1, 5,1,2, 6,0,1, 1,1,1, 3,1,1,
2,1,3, /*0,0,1, 0,0,1,*/ 2,1,1, 3,1,1, 5,1,3, /*0,0,1, 0,0,1,*/ 2,1,1, 3,1,1,
2,1,1, 6,0,3, 0,0,1, /*0,0,1,*/ 6,0,1, 1,1,1, /*2,1,3, 3,1,1, 2,1,3, 7,0,1,//咪,中音,1个半拍;
6,0,1, 1,1,1, 5,0,2, 0,0,1, /*0,0,0,*/ /*3,1,1, 5,1,2, */2,1,3, 3,1,1, 2,1,1, 7,0,1,//咪,中音,1个半拍;
6,0,1, 5,0,1, 1,2,1, 0,0,1, 1,2,1, 1,2,1, 6,1,1, 1,2,2, 0,0,1, 6,1,1, 1,2,1, 6,1,1, //音调+ 音高+几个半拍
5,1,2, 0,0,1, /*0,0,1,*/ 5,1,1, 3,1,1, 6,1,3, 5,1,1, 1,1,2, 2,1,1, 1,1,1, 2,1,1, 3,1,2,
0,0,1, 3,1,1, 3,1,1, 2,1,1, 3,1,1, 0,0,1, 1,2,1, 1,2,1, 7,1,1, 6,1,1, 3,1,1, 3,1,1, 2,1,2, 3,1,1, 1,2,1, 7,1,1, 6,1,1, 3,1,1, 5,1,2,
0,0,1, /*0,0,1, *//*3,1,1, 5,1,1, 2,1,3, 3,1,1, 2,1,1, 7,0,1, 6,0,1, 5,0,1, 1,1,2, 3,1,1, 5,1,1,
*/0,0,0};
// 音阶频率表 高八位
/* //--------------------------------------
记住:三个数字一组,代表一个音符。
第一个数字是1234567之一,代表音符哆来咪发...;
第二个数字是0123之一,代表低音、中音、高音、超高音;
第三个数字是半拍的个数,代表时间长度。
当三个数字都是0,就代表乐曲数据表的结尾。
*/
code unsigned char FREQH[]={
0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8, //低音 1,2,3,4,5,6,7
0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC, //中音 1,2,3,4,5,6,7,i
0xFC,0xFD,0xFD,0xFD,0xFD,0xFE, //高音 2,3,4,5,6,7
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF, //超高音1,2,3,4,5,6,7
} ;
// 音阶频率表 低八位
code unsigned char FREQL[]={
0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,
0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F, //1,2,3,4,5,6,7,8,i
0xEE,0x44, 0x6B,0xB4,0xF4,0x2D,
0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,//低音、中音、高音和超高音,四个八度共28个音符
};
void delay(unsigned char t)
{
unsigned char t1;
unsigned long t2;
for(t1=0;t1<t;t1++) //双重循环, 共延时t个半拍
{
for(t2=0;t2<8000;t2++) //延时期间, 可进入T0中断去发音
{
;
}
}
TR0=0; //关闭T0, 停止发音
}
void t0int() interrupt 1
{
TR0=0;
if(flag==0)
speaker=!speaker; //T0中断程序,控制发音的音调
else
{speaker=1;}
TH0=timer0h; //输出方波, 发音
TL0=timer0l; //下次的中断时间, 这个时间, 控制音调高低
TR0=1;
}
void song() //演奏一个音符
{
TH0=timer0h; //延时程序,控制发音的时间长度
TL0=timer0l;
TR0=1; //打开T0, 开始发音
delay(time); //控制时间长度
}
void main(void)
{
unsigned char k,i;
TMOD=1; //置CT0定时工作方式1
EA=1;
ET0=1;//IE=0x82 //CPU开中断,CT0开中断
while(1)
{
i=0;
while(i<100)
{ //音乐数组长度 ,唱完从头再来
k=sszymmh[i]+7*sszymmh[i+1]-1; // 6+7*2-1=19
if(k!=-1)
{
flag=0;
timer0h=FREQH[k]; //K-1是因为这里的数是0开始的
timer0l=FREQL[k];
time=sszymmh[i+2];
i=i+3;
song();
}
else
{
flag=1;
i=i+3;
song();
if(i==99)
delay(10000);
}
}
}
}