#include
sbit spek=P3^7;//声音输出端
sbit set=P3^2;//设定及退出键,按奇数次为设定功能;偶数次为退出功能
sbit up=P3^1;//上一曲
sbit down=P3^0;//下一曲
bit flag1,flag2;//按键扫描标志位,新键值标志位
unsigned char f_t,n,i,key,k_max; //音符频率对应的二分之一周期值,节拍常数值,查表用计数器,键值,最大键值
unsigned char *p_music;//指向音乐数据数组的指针
void timer_ms(unsigned char tim);//毫秒级延时函数声明
void timer_us(unsigned char t);//微秒级延时函数
void key_scan(void);//按键扫描函数
void key_manage();//键值处理函数
//格式为:频率常数,节拍常数,频率常数,节拍常数
unsigned char code music_table1[]={
0x18,0x30,0x1c,0x10,0x20,0x40,0x1c,0x10,0x18,
0x10,0x20,0x10,0x1c,0x10,0x18,0x40,0x1c,0x20,
0x20,0x20,0x1c,0x20,0x18,0x20,0x20,0x80,0xff,
0x20,0x30,0x1c,0x10,0x18,0x20,0x15,0x20,0x1c,
0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2b,0x20,
0x26,0x20,0x20,0x20,0x30,0x80,0xff,0x20,0x20,
0x1c,0x10,0x18,0x10,0x20,0x20,0x26,0x20,0x2b,
0x20,0x30,0x20,0x2b,0x40,0x20,0x20,0x1c,0x10,
0x18,0x10,0x20,0x20,0x26,0x20,0x2b,0x20,0x30,
0x20,0x2b,0x40,0x20,0x30,0x1c,0x10,0x18,0x20,
0x15,0x20,0x1c,0x20,0x20,0x20,0x26,0x40,0x20,
0x20,0x2b,0x20,0x26,0x20,0x20,0x20,0x30,0x80,
0x20,0x30,0x1c,0x10,0x20,0x10,0x1c,0x10,0x20,
0x20,0x26,0x20,0x2b,0x20,0x30,0x20,0x2b,0x40,
0x20,0x15,0x1f,0x05,0x20,0x10,0x1c,0x10,0x20,
0x20,0x26,0x20,0x2b,0x20,0x30,0x20,0x2b,0x40,
0x20,0x30,0x1c,0x10,0x18,0x20,0x15,0x20,0x1c,
0x20,0x20,0x20,0x26,0x40,0x20,0x20,0x2b,0x20,
0x26,0x20,0x20,0x20,0x30,0x30,0x20,0x30,0x1c,
0x10,0x18,0x40,0x1c,0x20,0x20,0x20,0x26,0x40,
0x13,0x60,0x18,0x20,0x15,0x40,0x13,0x40,0x18,
0x80,0x00}; //八月桂花香
unsigned char code music_table2[]={
0x26,0x20,0x20,0x20,0x20,0x20,0x26,0x10,0x20,
0x10,0x20,0x80,0x26,0x20,0x30,0x20,0x30,0x20,
0x39,0x10,0x30,0x10,0x30,0x80,0x26,0x20,0x20,
0x20,0x20,0x20,0x1c,0x20,0x20,0x80,0x2b,0x20,
0x26,0x20,0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,
0x80,0x26,0x20,0x30,0x20,0x30,0x20,0x39,0x10,
0x26,0x10,0x26,0x60,0x40,0x10,0x39,0x10,0x26,
0x20,0x30,0x20,0x30,0x20,0x39,0x10,0x26,0x10,
0x26,0x80,0x26,0x20,0x2b,0x10,0x2b,0x10,0x2b,
0x20,0x30,0x10,0x39,0x10,0x26,0x10,0x2b,0x10,
0x2b,0x20,0x2b,0x40,0x40,0x20,0x20,0x10,0x20,
0x10,0x2b,0x10,0x26,0x30,0x30,0x80,0x18,0x20,
0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x40,0x26,
0x20,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,
0x20,0x20,0x20,0x80,0x1c,0x20,0x1c,0x20,0x1c,
0x20,0x30,0x20,0x30,0x60,0x39,0x10,0x30,0x10,
0x20,0x20,0x2b,0x10,0x26,0x10,0x2b,0x10,0x26,
0x10,0x26,0x10,0x2b,0x10,0x2b,0x80,0x18,0x20,
0x18,0x20,0x26,0x20,0x20,0x20,0x20,0x60,0x26,
0x10,0x2b,0x20,0x30,0x20,0x30,0x20,0x1c,0x20,
0x20,0x20,0x20,0x80,0x26,0x20,0x30,0x10,0x30,
0x10,0x30,0x20,0x39,0x20,0x26,0x10,0x2b,0x10,
0x2b,0x20,0x2b,0x40,0x40,0x10,0x40,0x10,0x20,
0x10,0x20,0x10,0x2b,0x10,0x26,0x30,0x30,0x80,
0x00};//祝你平安
unsigned char code music_table3[]={
0x20,40,0x26,20,0x20,20,0x17,80,0x1c,40,0x17,40,
0x20,80,0x20, 40,0x2f,20,0x2a,20,0x26,40,0x2a,20,
0x2f,20,0x2a,80,0xff,0x20,40,0x26,20,0x20,20,0x17,60,
0x19,20, 0x1c,40,0x17,40,0x20,80,0x20,40,0x2a,20,
0x26,20,0x24,60,0x32,20,0x2f,80,0xff,0x1c,40,0x17,40,
0x17, 80,0x19,40,0x1c,20,0x19,20,0x17,80,0x1c,20,
0x19,20,0x17,20,0x1c,20,0x1c,20,0x20,20,0x26,20,0x2f,20,
0x2a,80,0xff,0x20,40,0x26,20,0x20,20,0x17,60,0x19,20,
0x1c,40,0x17,40,0x20,80,0x20,40,0x2a,20,0x26, 20,
0x24,60,0x32,20,0x2f,80,0xff,0x20,40,0x26,20,0x20,20,
0x17,80,0x1c,40,0x17,40,0x20,80,0x20,40, 0x2f,20,0x2a,20,
0x26,40,0x2a,20,0x2f,20,0x2a,80,0xff,0x20,40,0x26,20,
0x20,20,0x17,60,0x19,20,0x1c, 40,0x17,40,0x20,80,0x20,40,
0x2a,20,0x26,20,0x24,60,0x32,20,0x2f,80,0};//送别
main()
{
spek=0;
P3=0x7f;
TMOD=0x01;//T0工作于方式1,即16位定时器模式
IE=0x82;//开总中断,T0中断
flag2=0;//
flag1=0;
key=1;
k_max=3;//最大键值(取值范围1~254)
n=0;
i=0;
p_music=music_table1;//指针赋初值
while (1)
{
switch (p_music[i])
{
case 0x00: i=0;//歌曲完,则停止0.5S后重新开始
timer_ms(250);//延时0.25ms
timer_ms(250);
break;
case 0xff: i++;//遇到休止符则停止100us
timer_ms(250);
timer_ms(250);
break;
default: f_t=p_music[i++];
n=p_music[i++];
spek=1;
TR0=1;
while (n!=0)
{
spek=~spek;
timer_us(4*f_t);//改变f_t前面的系数可以调整音符频率的高低
}
TR0=0;
spek=0;
if(set==0)
{
key_scan();
key_manage();
}
}
}
}
/**************************************************************
函数名称: 定时器0的中断处理程序 函数功能: 完成10毫秒定时 入口参数:
出口参数:其 它: **************************************************************/
void timer0() interrupt 1 using 2
{
TH0=(65536-10000)/256;//定时10毫秒
TL0=(65536-10000)%256;
n--; }
/**************************************************************
函数名称: 延时程序函数功能: 完成微秒级的延时入口参数:
t为需延时的时间(取值范围1~255;延时时间5~1275us) 出口参数:
其 它: **************************************************************/
void timer_us(unsigned char t)
{
while (--t);//本语句执行一次需5us的时间
}
/**************************************************************
函数名称: 按键扫描函数 函数功能: 完成按键扫描处理入口参数:
应为在中断函数中被调用,所以不能有参数传递 出口参数:其 它:
**************************************************************/
void key_scan(void)
{
timer_ms(10);//延时10ms等待按键状态稳定
if (set==0)//再次确认
{
while (set==0);//等待按键松开
flag1=1;//该位为1,表示进入按键扫描处理;为0,表示本次按键扫描处理完成
while (flag1)
{
if (up==0)//加一键
{
timer_ms(10);
if (up==0)
{
while (!up);
key++;
if (key>k_max) key=1;
}
}
if (down==0)//减一键
{
timer_ms(10);
if (down==0)
{
while (!down);
key--;
if (key<1) key=k_max;
}
}
if (set==0)//退出键
{
timer_ms(10);
if (set==0)
{
while (set==0);
flag1=0;//表示本次按键扫描处理完成
flag2=1;//该位置1,表示有新键值要处理
}
}//以上键值处理的范围为1到254个键值
}
}
}
/**************************************************************
函数名称: 键值处理函数函数功能: 完成按键键值的处理
入口参数: 应为在中断函数中被调用,所以不能有参数传递
出口参数:其 它:
**************************************************************/
void key_manage()
{
flag2=0;
switch (key)
{
case 1: p_music=music_table1;//键值为1 播放第一首乐曲
goto kh1;
case 2: p_music=&music_table2[0];//键值为2 播放第2首乐曲
goto kh1;
case 3: p_music=&music_table3[0];//键值为3 播放第3首乐曲
goto kh1;
default:key=1;
p_music=music_table1;
kh1: TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
break;
}
n=0;
i=0;
}
/*----------------------------------------------------------------------------------------------------
函数名称: timer_ms函数说明: 1ms延时子程序入口参数: tim为接收主调传来需延时的毫秒数,取值范围1~256,定时时间1~256ms
出口参数: 其 它:----------------------------------------------------------------------------------------------------*/
void timer_ms(unsigned char tim)
{
unsigned char j;
while(tim--)
{
for(j=0;j<200;j++); //延时1ms
}
}