搬一篇文章过来,2009年本人写在网易博客上的,现在网页博客已经关了,先挪过来,避免以后不在了。
关于程序的补充说明:
1、两个定时器的作用,及中断优先级的问题。
(1)定时器0——是一直输出方波,直到音乐结束;优先级最高;
(2)定时器1——控制输出方波的时间。当输出一个音符的时间到达规定长度时,改变定时器0的计数值,也就是改变方波频率,输出下一个音符;
2、系统的时钟频率
注意下系统的时钟频率;
/***********************************************************
文件名: MusicPlay.c
描 述:
单片机演奏音乐;
程序结构描述:
main()函数在初始化后即进入while(1);功能主要在两个中断中完成;
定时器0中断主要输出一定频率的方波,初始值在于FreqTab中获取;
定时器1中断完成音长的控制,在完成特定音符的音长后读取下一个
音符,并且更新定时器0的初始设置值;
补充音乐知识:
音乐主要由音频和音长;
换个角度,
要输出一首音乐即用一个IO口输出特定时间长度和频率的方波
|<------- 音长1(节拍) --------->| <---- 音长2(节拍)------>| ...
__ __ __ __ __ ___ ___ ___
|__| |__| |__| |__| |__| |___| |___| |___| |___
| 音符1(频率1) | 音符2(频率2) | ...
Email:xiesx1985@126.com
by xiesx,2008.12.26
**************************************************************/
#include <reg51.h>
unsigned char volatile FlagBeat; // 基本节拍单位计数变量
unsigned int volatile FreqTemp;
unsigned char volatile music_temp; //暂时存放从MusicTable数组中读出的变量
unsigned char volatile beat; //
unsigned char volatile freq; //简谱码对应T值数组的下标
unsigned char volatile *pmusic;
sbit Pin_Buzzer=P1^0;
unsigned int code FreqTab[]={ //简谱对应的简谱码、T值
65535,
64260,64400,64524,64580,64684,
64777,64820,64898,64968,65030,
65058,65110,65157,65178,65217
};
unsigned char code MusicTable[]={//音符节拍码
0x82,0x01,0x81,0x94,0x84,
0xb4,0xa4,0x04,
0x82,0x01,0x81,0x94,0x84,
0xc4,0xb4,0x04,
0x82,0x01,0x81,0xf4,0xd4,
0xb4,0xa4,0x94,
0xe2,0x01,0xe1,0xd4,0xb4,
0xc4,0xb4,0x04,
0x82,0x01,0x81,0x94,0x84,
0xb4,0xa4,0x04,
0x82,0x01,0x81,0x94,0x84,
0xc4,0xb4,0x04,
0x82,0x01,0x81,0xf4,0xd4,
0xb4,0xa4,0x94,
0xe2,0x01,0xe1,0xd4,0xb4,
0xc4,0xb4,0x04,
0x00
};
//中断优先级最高,产生FreqTab表中对应的频率
void timer0() interrupt 1 using 0
{
TR0=0;
TL0= FreqTemp;
TH0= FreqTemp>>8;
TR0=1;
Pin_Buzzer=~Pin_Buzzer;
}
//用于控制音长的定时中断, 每1/4拍变量FlagBeat加1
//47ms中断一次
void timer1() interrupt 3 using 1
{
FlagBeat++;
TR1=0;
TL1=0x68;
TH1=0x48;
TR1=1;
//
if(*pmusic==0x00)pmusic=MusicTable;
{
if(FlagBeat==beat)
{
FlagBeat=0;
music_temp=*pmusic;
beat= music_temp&0x0F; //取得节拍数
beat=beat*4;
freq =music_temp>>4; //取得音符编码
pmusic++;
if(freq==0)TR0=0;
else
{
TR0=0;
FreqTemp=FreqTab[freq];
TL0= FreqTemp;
TH0= FreqTemp>>8;
TR0=1;
}
}
}
}
void main()
{
pmusic=MusicTable;
beat=1;
FlagBeat=0;
TMOD=0x11;//定时器0,1都工作16位计数方式
ET0=1; //允许定时器0溢出中断;
ET1=1; //允许定时器1溢出中断
EA=1;
TL1=0xF0;
TH1=0xFF;
TR1=1;
while(1)
{
}
}