原理图简单,单片机p0^7口接个三极管放大驱动蜂鸣器,晶震频率11.05922MHZ。
拿去改改曲谱数组可以唱其他歌。
#include <REG51.H>
#define uchar unsigned char
sbit beepIO=P0^7; //定义蜂鸣器端口为p0^7,根据单片机实际蜂鸣器实际接口改变
uchar m,n; //定义4个八度每八度12分音律共48音律
uchar code T[49][2]={{0,0},//定义音律49个二维数组
{0xF9,0x1F},{0xF9,0x82},{0xF9,0xDF},{0xFA,0x37},{0xFA,0x8A},{0xFA,0xD8},{0xFB,0x23},{0xFB,0x68},{0xFB,0xAA},{0xFB,0xE9},{0xFC,0x24},{0xFC,0x5B},
{0xFC,0x8F},{0xFC,0xC1},{0xFC,0xEF},{0xFD,0x1B},{0xFD,0x45},{0xFD,0x6C},{0xFD,0x91},{0xFD,0xB4},{0xFD,0xD5},{0xFD,0xF4},{0xFE,0x12},{0xFE,0x2D},
{0xFE,0x48},{0xFE,0x60},{0xFE,0x78},{0xFE,0x86},{0xFE,0xA3},{0xFE,0xB6},{0xFE,0xC9},{0xFE,0xDA},{0xFF,0xEB},{0xFE,0xFA},{0xFF,0x09},{0xFF,0x17},
{0xFF,0x24},{0xFF,0x30},{0xFF,0x3C},{0xFF,0x47},{0xFF,0x51},{0xFF,0x5B},{0xFF,0x64},{0xFF,0x6D},{0xFF,0x75},{0xFF,0x7D},{0xFF,0x84},{0xFF,0x8B}
};
uchar code music[][2]={{0,4},//定义曲谱数组,前数为音律,后数为音符节拍 ,要换歌改变简谱对应的音律号即可
{17,16},{20,12},{22,4},{25,12},{27,4},{22,4},{25,3},{20,8},{32,12},{37,4},{34,4},{32,4},{29,4},{32,4},{27,32},//梁祝曲谱
{27,8},{27,4},{29,4},{24,8},{22,8},{20,12},{22,4},{25,8},{27,8},{17,8},{25,8},{22,4},{20,4},{22,4},{25,4},{20,32},//
{29,12},{32,4},{24,8},{27,8},{22,4},{25,4},{20,8},{20,16},{17,4},{20,4},{17,8},{20,4},{22,4},{24,4},{27,4},{22,16},{20,8},{22,8},
{25,12},{27,4},{32,8},{29,8},{27,8},{29,4},{27,4},{25,8},{22,4},{20,4},{29,16},{25,16},{22,4},{25,4},{22,4},{20,4},{29,4},{20,4},{22,4},{25,4},{20,32},{0,32},
{0xFF,0xFF}}; //歌曲结尾标识
void delay(uchar p) //延时函数 无符号字符型变量
{
uchar i,j; //定义无符号字符型变量J和I
for(;p>0;p--) // 此处P值即主函数的n值节拍个数
for(i=181;i>0;i--) //延时181*181个机器周期约25毫秒,即一个1/16节拍
for(j=181;j>0;j--);
}
void T0_int() interrupt 1
{
beepIO=!beepIO; //蜂鸣器翻转发声
TH0=T[m][0]; TL0=T[m][1]; //音律延时周期次数码表赋给定时寄存器作为计数初始值,每TH0TL0个机器周期触发蜂鸣器端口翻转,演奏出不同音符
}
void main()
{
uchar i=0; //定义无符号字符型变量i,初始值为0
TMOD=0x01; EA=1; ET0=1; //开启T0定时16位方式,总中断开启,开启T0外部中断请求
while(1) //开始曲谱演奏,循环无限重复
{
m=music[0];n=music[1]; //将音律号赋值给m, 将节拍号赋值给n
if(m==0x00) //如果音律号为0,
{TR0=0;delay(n);i++;} //关闭计时器,延迟n拍,将循环数I加1 ,准备读下一个音符
else if(m==0xFF) //否则如果音律数为FF
{TR0=0;delay(30);i=0;} //开启节拍延时30个1/16节拍,歌曲停顿2秒,将循环数I置0
else if(m==music[i+1][0]) // 否则如果把下一个音律号数给变量m
{TR0=1;delay(n);TR0=0;i++;} //定时器0打开延迟n拍,关闭定时器T0,读下一个音符,循环数加1读下一个音律
else //音符若不为零
{TR0=1;delay(n);i++;}//打开定时器,延时n个1/16拍,循环数I加1 ,准备演奏下一个音符
}
}
|