很簡單啊!你只要簡譜中的節后取出來做流水路控制就OK
不知這個代碼你是否能看懂
51單片機音樂播放實驗
-----------------------------------------------*/
#include<reg51.h> //51頭文件,
//---------常用的兩個宏定義--------------
#define uint8 unsigned char
#define uint16 unsigned int
sbit Music=P2^0;
uint16 code FreTab_Low[7]={262,294,330,349,392,440,494}; //低音頻率表
uint16 code FreTab_Mid[7]={523,578,659,698,784,880,988}; //中音頻率表
uint16 code FreTab_Hight[7]={1046,1175,1318,1397,1568,1760,1976}; //高音頻率表
/*-----------------------------------------------------
曲譜存貯格式 uchar code MusicName{音高,音長,...., 0,0};
末尾:0,0 表示結束。
音高由頻率決定,音長也就是節拍可以自己規定,在本程序中,
定時器T1用作節拍定時,定時時間為50ms,那么在該樂譜中1拍
表示50ms。
-------------------------------------------------------*/
uint8 code Happy_Birthday[]={0x11,0x05,0x11,0x05,0x12,0x0a,0x11,0x0a,
0x14,0x0a,0x13,0x14,
0x11,0x05,0x11,0x05,0x12,0x0a,0x11,0x0a,
0x15,0x0a,0x14,0x14,
0x11,0x05,0x11,0x05,0x21,0x0a,0x16,0x0a,
0x14,0x0a,0x13,0x0a,0x22,0x0a,
0x17,0x05,0x17,0x05,0x16,0x0a,0x14,0x0a,
0x15,0x0a,0x14,0x14,0x00,0x00
};
uint16 Fre; //存放獲取頻率值的變量
/*-----------------------------------------------
函數名:Timer_Init()
函數功能:對兩個定時器初始化
入口參數:無
------------------------------------------------*/
void Timer_Init()
{
TMOD=0x11;
EA=1;
ET0=1;
ET1=0;
TR0=0;
TR1=0;
}
/*-----------------------------------------------
函數名:Timer0_Ser()
函數功能:定時器0的中斷服務程序,主要是產生需要的頻率
從而驅動喇叭發出相應的音符
入口參數:無
------------------------------------------------*/
void Timer0_i() interrupt 1
{
TH0=Fre/256;
TL0=Fre%256;
if(Music==0)
Music=1;
else Music=0;
}
/*-----------------------------------------------
函數名:Music_Play(uchar *MusicTab)
函數功能:音樂播放函數,
入口參數:*MusicTab 所要播放音樂的首地址
------------------------------------------------*/
void Music_Play(uint8 *MusicTab)
{
uint8 *pMusic;
uint8 temp,i;
pMusic=MusicTab; //將歌曲首地址給指針變量
while(*pMusic!=0)
{
if((*pMusic&0xf0)==0x00)
Fre=65536-1000000/FreTab_Low[*pMusic&0x0f];
else if((*pMusic&0xf0)==0x10)
Fre=65536-1000000/FreTab_Mid[*pMusic&0x0f];
else if((*pMusic&0xf0)==0x20)
Fre=65536-1000000/FreTab_Hight[*pMusic&0x0f];
TH0=Fre/256; //計算頻率初值,賦高八位
TL0=Fre%256; //計算頻率初值,賦低八位
TH1=0x3c; //定時器1賦初值,定時50ms
TL1=0xb0;
pMusic++; //獲得節拍值
temp=*pMusic;
TR0=1; //開啟定時器T0
TR1=1; //開啟定時器T1
for(i=0;i<temp;i++)
{
while(TF1==0); //判斷定時器1是否溢出
TH1=0x3c;
TL1=0xb0;
TF1=0;
}
pMusic++;
}
}
/*-----------------------------------------------
函數名:main()
函數功能:主函數
入口參數:無
------------------------------------------------*/
void main()
{
Timer_Init();
while(1)
{
Music_Play(Happy_Birthday);
}
} 如果能將取得的節拍取做一個變量,放到while中,再用個switch語句將節拍值變量對應你要點亮LED的個數。比如一個節拍一個LED亮,兩個節拍是兩個LED燈亮,不要憐惜,單片機IO端口多的是,多益善! |