最新51单片机电子琴程序汇总.docx

上传人:b****2 文档编号:24191518 上传时间:2023-05-25 格式:DOCX 页数:19 大小:19.23KB
下载 相关 举报
最新51单片机电子琴程序汇总.docx_第1页
第1页 / 共19页
最新51单片机电子琴程序汇总.docx_第2页
第2页 / 共19页
最新51单片机电子琴程序汇总.docx_第3页
第3页 / 共19页
最新51单片机电子琴程序汇总.docx_第4页
第4页 / 共19页
最新51单片机电子琴程序汇总.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

最新51单片机电子琴程序汇总.docx

《最新51单片机电子琴程序汇总.docx》由会员分享,可在线阅读,更多相关《最新51单片机电子琴程序汇总.docx(19页珍藏版)》请在冰豆网上搜索。

最新51单片机电子琴程序汇总.docx

最新51单片机电子琴程序汇总

 

51单片机电子琴程序

#include

#include

#include

#include

#defineucharunsignedchar

#defineuintunsignedint

ucharSTH0;//定时器计数初值

ucharSTL0;

bitFY=0;//放乐曲时FY=1,电子琴弹奏时FY=0

ucharSong_Index=0,Tone_Index=0;//放音乐的参数

uchark,key;

sbitSPK=P3^7;

sbitLED1=P1^0;

sbitLED2=P1^1;

ucharcodeDSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6f,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

ucharcodeSong[][50]={{1,2,3,5,7,8,4,3,4,3,4,5,4,6,3,4,5},

{5,5,3,5,4,2,4,5,7,4,2,10,10,10,2,1,2,1,2,10,10},

{5,5,10,9,8,5,5,5,5,10,9,8,6,6,6,11,12,9,6,8-1},

{13,14,13,12,12,10,12,13,14,15,14,14},

{6,6,11,10,9,12,12,12,12,13,12,11,9,8,10,10,10,-1},

{9,13,13,13,13,8,13,13,13,13,14,15,14,13,13,14,12,13},

};

ucharcodeLen[][50]={{1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,2,2,2,1,2,2,1,2,2},

{1,1,1,1,1,1,2,1,1,1,2,2,1,1,1,1,-1},

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},

{1,1,2,0,1,1,2,0,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,2,0,1,2,1,2,1,2,1,2,1,2},

{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1},};

//音符与计数值对应表

uintcodetab[]={0,63628,63835,64021,64103,64260,64400,

64524,64580,64684,64777,

64820,64898,64968,65030,

65058,65110,65157,65178,65217,65252,65283};

voiddelay1(uintms)//播放歌曲时实现节拍的延时函数

{

uchart;

while(ms--)for(t=0;t<120;t++);

}

//键消抖延时函数

voiddelay(void)

{

uchari;

for(i=300;i>0;i--);

}

//键扫描函数

uchargetkey(void)

{

ucharscancode,tmpcode;

if((P0&0xf0)==0xf0)

return(0);

scancode=0xfe;

while((scancode&0x10)!

=0)

{

P0=scancode;//输入行扫描码

if((P0&0xf0)!

=0xf0)//本行有键按下

{

tmpcode=(P0&0xf0)|0x0f;

return((~scancode)+~(tmpcode));

}

elsescancode=(scancode<<1)|0x01;

}

}

//外部中断0

voidEX0_INT()interrupt0

{

FY=0;LED1=1;LED2=0;

}

//外部中断1,这里是播放按键

voidEX1_INT()interrupt2

{

FY=1;LED1=0;LED2=1;

}

//定时器0中断服务子程序

voidtime0_int(void)interrupt1using0

{

TH0=STH0;

TL0=STL0;

SPK=!

SPK;

P2=DSY_CODE[k];

}

voidmain(void)

{

LED1=1;

LED2=0;

P2=0x3f;

IE=0x87;

TMOD=0x01;

IT0=1;

IT1=1;

while

(1)

{

P0=0xf0;

if((P0&0xf0)!

=0xf0)

{

delay();

if((P0=0xf0)!

=0xf0)

{

key=getkey();

switch(key)

{

case0x11:

k=0;

break;

case0x21:

k=1;

break;

case0x41:

k=2;break;

case0x81:

k=3;break;

case0x12:

k=4;break;

case0x22:

k=5;break;

case0x42:

k=6;break;

case0x82:

k=7;break;

case0x14:

k=8;break;

case0x24:

k=9;break;

case0x44:

k=10;break;

case0x84:

k=11;break;

case0x18:

k=12;break;

case0x28:

k=13;break;

case0x48:

k=14;break;

case0x88:

k=15;break;

default:

break;

}

if(FY==0)

{

STH0=tab[k]/256;

STL0=tab[k]%256;

TR0=1;

while((P0&0xf0)!

=0xf0);

TR0=0;

}

else

{

while(FY==1)

{

if(Song[k][Tone_Index]==-1)

Tone_Index=0;

STH0=(tab[Song[k][Tone_Index]])/256;

STL0=(tab[Song[k][Tone_Index]])%256;

P2=DSY_CODE[Song[k][Tone_Index]];

TR0=1;

delay1(300*Len[k][Tone_Index]);

Tone_Index++;

TR0=0;

}

}

}

}

}

}

关于“世上只有妈妈好”的单片机音乐演奏程序

2009-11-2221:

45

单片机演奏一个音符,是通过引脚,周期性的输出一个特定频率的方波。

这就需要单片机,在半个周期内输出低电平、另外半个周期输出高电平,周而复始。

半个周期的时间是多长呢?

众所周知,周期为频率的倒数,可以通过音符的频率计算出半周期。

演奏时,要根据音符频率的不同,把对应的、半个周期的定时时间初始值,送入定时器,再由定时器按时输出高低电平。

下面是个网上广泛流传的单片机音乐演奏程序,它可以循环的播放“世上只有妈妈好”这首乐曲。

很多人都关心如何修改这个乐曲的内容,但是不知如何入手。

做而论道对这个程序,给出说明,希望对大家有所帮助,以后大家自己就能够编写进去新的乐曲。

在这个程序中,有两个数据表,其中存放了事先算好的、各种音符频率所对应的、半周期的定时时间初始值。

有了这些数据,单片机就可以演奏从低音、中音、高音和超高音,四个八度共28个音符。

演奏乐曲时,就根据音符的不同数值,从半周期数据表中找到定时时间初始值,送入定时器即可控制发音的音调。

比如把表中的0xF2和0x42送到定时器,定时器按照这个初始值来产生中断,输出的方波,人们听起来,这就是低音1。

乐曲的数据,也要写个数据表,程序中以codeunsignedcharsszymmh[]命名。

这个表中每三个数字,说明了一个音符,它们分别代表:

第一个数字是音符的数值1234567之一,代表多来咪发...;

第二个数字是0123之一,代表低音、中音、高音、超高音;

第三个数字是时间长度,以半拍为单位。

乐曲数据表的结尾是三个0。

程序如下:

#include

sbitspeaker=P1^7;

unsignedchartimer0h,timer0l,time;

//--------------------------------------

//单片机晶振采用11.0592MHz

//频率-半周期数据表高八位本软件共保存了四个八度的28个频率数据

codeunsignedcharFREQH[]={

0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8,//低音1234567

0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC,//1,2,3,4,5,6,7,i

0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,//高音234567

0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF};//超高音1234567

//频率-半周期数据表低八位

codeunsignedcharFREQL[]={

0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,//低音1234567

0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F,//1,2,3,4,5,6,7,i

0xEE,0x44,0x6B,0xB4,0xF4,0x2D,//高音234567

0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16};//超高音1234567

//--------------------------------------

//世上只有妈妈好数据表要想演奏不同的乐曲,只需要修改这个数据表

codeunsignedcharsszymmh[]={

6,2,3,5,2,1,3,2,2,5,2,2,1,3,2,6,2,1,5,2,1,

//一个音符有三个数字。

前为第几个音、中为第几个八度、后为时长(以半拍为单位)。

//6,2,3分别代表:

6,中音,3个半拍;

//5,2,1分别代表:

5,中音,1个半拍;

//3,2,2分别代表:

3,中音,2个半拍;

//5,2,2分别代表:

5,中音,2个半拍;

//1,3,2分别代表:

1,高音,2个半拍;

//

6,2,4,3,2,2,5,2,1,6,2,1,5,2,2,3,2,2,1,2,1,

6,1,1,5,2,1,3,2,1,2,2,4,2,2,3,3,2,1,5,2,2,

5,2,1,6,2,1,3,2,2,2,2,2,1,2,4,5,2,3,3,2,1,

2,2,1,1,2,1,6,1,1,1,2,1,5,1,6,0,0,0};

//--------------------------------------

voidt0int()interrupt1//T0中断程序,控制发音的音调

{

TR0=0;//先关闭T0

speaker=!

speaker;//输出方波,发音

TH0=timer0h;//下次的中断时间,这个时间,控制音调高低

TL0=timer0l;

TR0=1;//启动T0

}

//--------------------------------------

voiddelay(unsignedchart)//延时程序,控制发音的时间长度

{

unsignedchart1;

unsignedlongt2;

for(t1=0;t1

for(t2=0;t2<8000;t2++);//延时期间,可进入T0中断去发音

TR0=0;//关闭T0,停止发音

}

//--------------------------------------

voidsong()//演奏一个音符

{

TH0=timer0h;//控制音调

TL0=timer0l;

TR0=1;//启动T0,由T0输出方波去发音

delay(time);//控制时间长度

}

//--------------------------------------

voidmain(void)

{

unsignedchark,i;

TMOD=1;//置T0定时工作方式1

ET0=1;//开T0中断

EA=1;//开CPU中断

while

(1){

i=0;

time=1;

while(time){

k=sszymmh[i]+7*sszymmh[i+1]-1;

//第i个是音符,第i+1个是第几个八度

timer0h=FREQH[k];//从数据表中读出频率数值

timer0l=FREQL[k];//实际上,是定时的时间长度

time=sszymmh[i+2];//读出时间长度数值

i+=3;

song();//发出一个音符

}}}

//======================================

应网友要求,下面再详细写一下乐谱和数据的转换关系。

以李叔同大师的《送别》的前二小节来说明转换的方法。

这部分的歌词是:

“长亭外,古道边,”;

这部分的乐谱是:

|5351-|6165-|。

(注意:

乐谱中的1是高音,上边是带点的;还有些音符,应该有下划线,在这里都无法标出。

感兴趣的网友应该去查看正规的乐谱。

那么,据此就可以写出《送别》前二小节的数据表:

//--------------------------------------

codeunsignedcharsszymmh[]={

5,2,2,3,2,1,5,2,1,1,3,4,

//嗦,中音,2个半拍; 咪,中音,1个半拍; 嗦,中音,1个半拍; 哆,高音,4个半拍

6,2,2,1,3,1,6,2,1,5,2,4,

//啦,中音,2个半拍; 哆,高音,1个半拍; 啦,中音,1个半拍; 嗦,中音,4个半拍

0,0,0};

//结束标记

//--------------------------------------

记住:

三个数字一组,代表一个音符。

第一个数字是1234567之一,代表音符哆来咪发...;

第二个数字是0123之一,代表低音、中音、高音、超高音;

第三个数字是半拍的个数,代表时间长度。

当三个数字都是0,就代表乐曲数据表的结尾。

用这个数据表,替换掉程序中《世上只有妈妈好》的数据表,本程序就可以播放《送别》的前两小节。

#include

unsignedchartemp;

unsignedcharkey;

unsignedchari,j;

unsignedcharSTH0;

unsignedcharSTL0;

unsignedintcodetab[]={64021,64103,64260,64400,

64524,64580,64684,64777,

64820,64898,64968,65030,

65058,65110,65157,65178};

voidmain(void)

{

TMOD=0x01;

ET0=1;

EA=1;

while

(1)

{

P3=0xff;//将P3口取出

P3_4=0;//使P3_4为低电平,这样可以判断第一竖排有没有键按下

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)//有键按下

{

for(i=50;i>0;i--)

for(j=200;j>0;j--);//延时

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)//再判断是否有键按下

{

temp=P3;

temp=temp&0x0f;

switch(temp)//判断是哪个键按下

{

case0x0e:

key=0;

break;

case0x0d:

key=1;

break;

case0x0b:

key=2;

break;

case0x07:

key=3;

break;

}

temp=P3;

P1_0=~P1_0;

P0=table[key];

STH0=tab[key]/256;//找出键对应的频率的时间,作为定时器中断初始值

STL0=tab[key]%256;

TR0=1;

temp=temp&0x0f;

while(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

}

TR0=0;

}

}

P3=0xff;

P3_5=0;//跟上面差不多,现在是判断第二排的按键

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

for(i=50;i>0;i--)

for(j=200;j>0;j--);

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

switch(temp)

{

case0x0e:

key=4;

break;

case0x0d:

key=5;

break;

case0x0b:

key=6;

break;

case0x07:

key=7;

break;

}

temp=P3;

P1_0=~P1_0;

P0=table[key];

STH0=tab[key]/256;

STL0=tab[key]%256;

TR0=1;

temp=temp&0x0f;

while(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

}

TR0=0;

}

}

P3=0xff;

P3_6=0;

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

for(i=50;i>0;i--)

for(j=200;j>0;j--);

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

switch(temp)

{

case0x0e:

key=8;

break;

case0x0d:

key=9;

break;

case0x0b:

key=10;

break;

case0x07:

key=11;

break;

}

temp=P3;

P1_0=~P1_0;

P0=table[key];

STH0=tab[key]/256;

STL0=tab[key]%256;

TR0=1;

temp=temp&0x0f;

while(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

}

TR0=0;

}

}

P3=0xff;

P3_7=0;

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

for(i=50;i>0;i--)

for(j=200;j>0;j--);

temp=P3;

temp=temp&0x0f;

if(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

switch(temp)

{

case0x0e:

key=12;

break;

case0x0d:

key=13;

break;

case0x0b:

key=14;

break;

case0x07:

key=15;

break;

}

temp=P3;

P1_0=~P1_0;

P0=table[key];

STH0=tab[key]/256;

STL0=tab[key]%256;

TR0=1;

temp=temp&0x0f;

while(temp!

=0x0f)

{

temp=P3;

temp=temp&0x0f;

}

TR0=0;

}

}

}

}

voidt0(void)interrupt1using0

{

TH0=STH0;

TL0=STL0;

P1_0=~P1_0;

}

电路图和原理我都有,刚好我也在做这个。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 国外设计风格

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1