很简单啊!你只要简谱中的节后取出来做流水路控制就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端口多的是,多益善! |