本次课程设计是一个基于ATC51系列单片机的音乐盒的设计,依据单片机技术原理,通过硬件电路制作以及软件编译,设计制作出一个音乐盒。该音乐盒主要由按键电路、复位电路、时钟电路以及蜂鸣器和led显示电路组成。使用两个按键控制音乐盒,一个用来切换歌曲,另一个用来切换8路led的变化花样。本音乐盒共有两首歌曲,花样灯花样共计3种。播放歌曲时,蜂鸣器发出某个音调,与之对应的led亮起。本设计利用keil编程软件对音乐盒源程序进行编程并调试,配合proteus仿真软件对硬件进行仿真调试。该音乐盒使用c语言编程和汇编语言相结合,程序段使用C语言,歌曲音谱和led显示花样使用汇编语言。
3.2.2 播放音乐子程序设计 13
绪论
21世纪,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地推动了社会生产力的发展和社会信息化程度的提高,同时也使现代电子产品性能进一步提高,产品更新换代的节奏也越来越快。
随着科学技术的进步和社会的发展,人类所接触的信息也在不断增加并且日益复杂。面对浩如烟海的信息,人们已经能够利用计算机等工具高效准确地对之进行处理,但要想将处理完的信息及时,清晰地传递给别人,还必须通过寻求更加卓越的显示技术来实现。单片机技术与液晶显示技术的结合,使信息传输交流向着智能可视化方向迅速发展。
随着人类社会的发展,人们对视觉、听觉方面的享受提出了越来越高的要求。小小的音乐盒可以给人们带来美好的回忆,提高人们的精神文化享受。传统音乐盒多是机械型的,体积笨重,发音单调,不能实现批量生产。本文设计的音乐盒是以单片机为核心元件的电子式音乐盒,体积小,重量轻,能演奏和旋音乐,功能多,外观效果多彩,使用方便,并具有一定的商业价值。
1 设计题目要求
1.1课题意义
音乐盒的起源,可追溯至中世纪欧洲文艺复兴时期。当时为使教会的钟塔报时,而将大小的钟表装上机械装置,被称为“可发出声音的组钟”。音乐盒有着300多年的发展历史,是人类文明发展的历史见证。
传统的音乐盒多是机械音乐盒,其工作原理是通过齿轮带动一个带有铁钉的铁桶转动,铁桶上的铁钉撞击铁片制成的琴键,从而发出声音。但是,机械式的音乐盒体积比较大,比较笨重,且发音单调。水、灰尘等外在因素,容易使内部金属发音条变形,从而造成发音跑调。另外,机械音乐盒放音时为了让音色稳定,必须放平不能动摇,而且价格昂贵,不能实现大批量生产。
本文设计的音乐盒,是基于单片机设计制作的电子式音乐盒。与传统的机械式音乐盒相比更小巧,音质更优美且能演奏和弦音乐。电子式音乐盒动力来源是电池,制作工艺简单,可进行批量生产,所以价格便宜。基于单片机制作的电子式音乐盒,控制功能强大,可根据需要选歌,使用方便。根据存储容量的大小,可以尽可能多的存储歌曲。另外,可以设计彩灯外观效果,使音乐盒的功能更加丰富。
1.2设计目的
设计一个基于ATC52系列单片机的音乐盒,利用按键切换演奏出不同的乐曲。蜂鸣器发出某个音调,与之相对应的LED亮起。使用两个按键,一个用来切换歌曲,另一个切换八路LED的变化花样。
1.3设计要求
1)电路有两种工作模式:演奏音乐模式和花样灯模式。
演奏音乐模式:演奏完整的一首的歌曲,八路LED随着音乐变化。
花样灯模式:八路LED变化出各种花样,蜂鸣器随着发出音乐声。
2)按下按键1进入演奏音乐模式,再按切换歌曲,共两首歌曲。
3)按下按键2进入花样灯模式,再按切换LED花样,共三种花样。
2 方案设计及硬件设计及其原理
2.1方案设计及硬件设计
2.1.1系统总体方案设计
音乐盒的系统结构以ATC51单片机位控制核心,加上2个按键、时钟复位电路、蜂鸣器、LED模块组成。单片机负责接收按键的输入,根据输入控制音乐播放曲目和音乐花样灯的显示样式以及蜂鸣器发音。系统组成框图如图2.1.1所示。
图2.1.1 系统组成框图
2.1.2音乐盒设计
音乐盒的功能结构如图2.1.2所示。Key1负责切换播放歌曲,播放歌曲共2首,分别是月亮代表我的心和国歌。Key2负责切换LED显示花样,显示花样共3种,第一种顺序显示,第二种由两边向中间移动然后向两边移动,第三种循环显示。
图2.1.2 音乐盒功能结构图
2.1.3硬件总体设计
图2.1.3总体设计框
2.1.4硬件仿真图及功能
总体硬件电路实现功能如下,如图2.1.4所示
1)电路中用P3.2、P3.3控制按键。
2)P1.0~P1.7控制LED。
3)P2.7控制蜂鸣器。
4)电路为11.0592MHZ晶振频率工作,起振电路中C1、C2均为 30PF。
图2.1.4 硬件电路图
2.2 相关知识,原理和理论介绍
2.2.1 ATC52简介
ATC52是一种带4K字节闪存可编程可擦除只读存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压,高性能CMOS 8位微处理器,俗称单片机。ATC2052是一种带2K字节闪存可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除100次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的ATC52是一种高效微控制器,ATC2052是它的一种精简版本。ATC52单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。外形及引脚排列如图2.2.1所示
图2.2.1 ATC52系列单片机
2.2.2 LED显示电路设计与原理
LED显示电路是由8个LED发光二极管组成,连接方式为共阳极,LED接到单片机的P1口,若为低电平,可使LED亮起。发光二极管的亮、灭由内部程序控制,8个LED发光二极管分别对应不同的音阶,所以LED会随着音阶的变化按规律亮、灭。
2.2.3 时钟振荡电路
ATC52中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。这个放大器与作为反馈元件的片外石英晶体或者陶瓷谐振器一起构成自然振荡器。外接石英晶体及电容C1、C2接在放大器的反馈回路中构成并联振荡电路。对外接电容C1,C2虽然没有什么严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性。如果使用石英晶体,我们推荐电容使用30PF10PF,而如果使用陶瓷振荡器建议选择40PF10PF。用户也可以采用外部时钟。采用外部时钟的电路如图示。这种情况下,外部时钟脉冲接到XTAL1端,即内部时钟发生器的输入端,XTAL2则悬空。由于外部时钟信号是通过一个2分频触发器后作为内部时钟信号的,所以对外部时钟信号的占空比没有特殊要求,但最小高电平持续时间和最大的低电平持续时间应符合产品技术条件的要求。振荡器电路图如下:
图2.2.3 单片机内部、外部振荡电路
2.2.4 花样灯3种花样图
1)第一种花样灯显示方式为:从D1移向D2,然后D1熄灭,再从D2移向D3,然后D2熄灭,以此类推,往复循环。
图2.2.4.1 第一种花样
2)第二种花样灯显示方式为:从两边向中间移动,首先从D1移向D8,再从D8移向D2,以此类推,往复循环。具体如图5.3。
图2.2.4.2 第2种花样
3)第三种花样灯显示方式为:从D1移向D2,然后D1熄灭,再从D2移向D3,然后D2熄灭,以此往复循环。与第一种方式的不同之处为:当D1移向D2时,D1不熄灭,再从D2移向D3时,D2也不熄灭,以此类推。
图2.2.4.3 第3中花样
3 软件设计
按键1使得count1在1和2之间切换,按键2使得count2在1~4之间切换。程序检测count1的值,count1等于1时播放第一首歌曲,等于2时播放第二首。另一方面根据count2的值来切换LED的花样。count1和count2的值是互斥的,设置count1等于1、2时,count2同时设置为0;设置count2等于1~4在本程序中设置了两个标志——count1和count2,分别初始化为1和0。时,count1也同时设置为0。
3.1 音调、节拍以及编码的确定方法
一般说来,单片机演奏音乐基本都是单音频率,它不包含相应幅度的谐波频率,也就是说不能像电子琴那样能奏出多种音色的声音。因此单片机奏乐只需弄清楚两个概念即可,也就是“音调”和节拍表示一个音符唱多长的时间。
3.1.1 音调的确定
不同音高的乐音是用C、D、E、F、G、A、B来表示,这7个字母就是音乐的音名,它们一般依次唱成DO、RE、MI、FA、SO、LA、SI,即唱成简谱的1、2、3、4、5、6、7,相当于汉字“多来米发梭拉西”的读音,这是唱曲时乐音的发音,所以叫“音调”,即Tone。把C、D、E、F、G、A、B这一组音的距离分成12个等份,每一个等份叫一个“半音”。两个音之间的距离有两个“半音”,就叫“全音”。在钢琴等键盘乐器上,C–D、D–E、F–G、G–A、A–B两音之间隔着一个黑键,他们之间的距离就是全音;E–F、B–C两音之间没有黑键相隔,它们之间的距离就是半音。通常唱成1、2、3、4、5、6、7的音叫自然音,那些在它们的左上角加上﹟号或者b号的叫变化音。﹟叫升记号,表示把音在原来的基础上升高半音,b叫降记音,表示在原来的基础上降低半音。例如高音DO的频率(1046Hz)刚好是中音DO的频率(523Hz)的一倍,中音DO的频率(523Hz)刚好是低音DO频率(266 Hz)的一倍;同样的,高音RE的频率(1175Hz)刚好是中音RE的频率(587Hz)的一倍,中音RE的频率(587Hz)刚好是低音RE频率(294 Hz)的一倍。
1)要产生音频脉冲,只要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用定时器计时这半个周期时间,每当计时到后就将输出脉冲的I/O反相,然后重复计时此半周期时间再对I/O反相,就可在I/O脚上得到此频率的脉冲。
2)利用ATC51的内部定时器使其工作在计数器模式MODE1下,改变计数值TH0及TL0以产生不同频率的方法。
此外结束符和休止符可以分别用代码00H和FFH来表示,若查表结果为00H,则表示曲子终了;若查表结果为FFH,则产生相应的停顿效果。
3)例如频率为523Hz,其周期T=1/523=1912us,因此只要令计数器计时956us/1us=956,在每次技术956次时将I/O反相,就可得到中音DO(523Hz)。
计数脉冲值与频率的关系公式如下:
N=Fi2Fr
N:计算值; Fi:内部计时一次为1us,故其频率为1MHz;
4)其计数值的求法如下:
T=65536-N=65536-Fi2Fr
例如:设K=65536,F=1000000=Fi=1MHz,球低音DO(261Hz)。中音DO(523Hz)。高音的DO(1046Hz)的计算值
T=65536-N=65536-Fi2Fr=65536-10000002Fr=65536-500000/Fr
低音DO的T=65536-500000/262=63627
低音DO的T=65536-500000/523=580
低音DO的T=65536-500000/1047=65059
5)C调各音符频率与计数值T的对照表如表3.1.1所示。
表3.1.1 C调各音符频率与计数值T的对照表
低音 | 频率 | T | 参数 | 中音 | 频率 | T | 参数 | 高音 | 频率 | T | 参数 |
Do | 262 | 1908 | 229 | Do | 523 | 956 | 115 | Do | 1046 | 57 | 57 |
Do﹟ | 277 | 1805 | 217 | Do﹟ | 554 | 903 | 108 | Do﹟ | 1109 | 54 | 54 |
Re | 294 | 1701 | 204 | Re | 587 | 852 | 102 | Re | 1175 | 51 | 51 |
Re﹟ | 311 | 1608 | 193 | Re﹟ | 622 | 804 | 97 | Re﹟ | 1245 | 48 | 48 |
Mi | 330 | 1515 | 182 | Mi | 659 | 759 | 91 | Mi | 1318 | 45 | 45 |
Fa | 349 | 1433 | 172 | Fa | 698 | 716 | 86 | Fa | 1397 | 43 | 43 |
Fa﹟ | 370 | 1351 | 162 | Fa﹟ | 740 | 676 | 81 | Fa﹟ | 1480 | 41 | 41 |
So | 392 | 1276 | 153 | So | 784 | 638 | 77 | So | 1568 | 38 | 38 |
So﹟ | 415 | 1205 | 145 | So﹟ | 831 | 602 | 72 | So﹟ | 1661 | 36 | 36 |
La | 440 | 1136 | 136 | La | 880 | 568 | 68 | La | 1760 | 34 | 34 |
La﹟ | 4 | 1078 | 129 | La﹟ | 932 | 536 | La﹟ | 1865 | 32 | 32 | |
Si | 494 | 1012 | 121 | Si | 988 | 506 | 61 | Si | 1976 | 30 | 30 |
若要构成音乐,光有音调是不够的,还需要节拍,让音乐具有旋律(固定的律动),而且可以调节各个音的快满度。“节拍”,即Beat,简单说就是打拍子,就像我们听音乐不自主的随之拍手或跺脚。若1拍实0.5s,则1/4 拍为0.125s。至于1拍多少s,并没有严格规定,就像人的心跳一样,大部分人的心跳是每分钟72下,有些人快一点,有些人慢一点,只要听的悦耳就好。音持续时间的长短即时值,一般用拍数表示。休止符表示暂停发音。
一首音乐是由许多不同的音符组成的,而每个音符对应着不同频率,这样就可以利用不同的频率的组合,加以与拍数对应的延时,构成音乐。了解音乐的一些基础知识,我们可知产生不同频率的音频脉冲即能产生音乐。对于单片机来说,产生不同频率的脉冲是非常方便的,利用单片机的定时/计数器来产生这样的方波频率信号。因此,需要弄清楚音乐中的音符和对应的频率,以及单片机定时计数的关系。表3.1.2给出了节拍和节拍码的对照。
表3.1.2节拍与节拍码对照
节拍码 | 节拍数 | 节拍码 | 节拍数 |
1 | 1/4拍 | 1 | 1/8拍 |
2 | 2/4拍 | 2 | 1/4拍 |
3 | 3/4拍 | 3 | 3/8拍 |
4 | 1拍 | 4 | 2/1拍 |
5 | 1又1/4拍 | 5 | 5/8拍 |
6 | 1又1/2拍 | 6 | 3/4拍 |
8 | 2拍 | 8 | 1拍 |
A | 2又1/2拍 | A | 1又1/4拍 |
C | 3拍 | C | 1又1/2拍 |
F | 3又3/4拍 |
do re mi fa so la si分别编码为1~7,重音do编为8,重音re编为9,停顿编为0。播放长度以十六分音符为单位(在本程序中为165ms),一拍即四分音符等于4个十六分音符,编为4,其它的播放时间以此类推。音调作为编码的高4位,而播放时间作为低4位,如此音调和节拍就构成了一个编码。以0xff作为曲谱的结束标志。
举例1:音调do,发音长度为两拍,即二分音符,将其编码为0x18。
举例2:音调re,发音长度为半拍,即八分音符,将其编码为0x22
歌曲播放的设计。先将歌曲的简谱进行编码,储存在一个数据类型为unsigned char 的数组中。程序从数组中取出一个数,然后分离出高4位得到音调,接着找出相应的值赋给定时器0,使之定时操作蜂鸣器,得出相应的音调;接着分离出该数的低4位,得到延时时间,接着调用软件延时。表3.1.3给出了简谱对应的简谱码,T值和节拍数。
表3.1.3 简谱对应的简谱码、T值、节拍数
简谱 | 发音 | 简谱码 | T值 | 节拍码 | 节拍数 |
5 | 低音SO | 1 | 260 | 1 | 1/4拍 |
6 | 低音LA | 2 | 400 | 2 | 2/4拍 |
7 | 低音TI | 3 | 524 | 3 | 3/4拍 |
1 | 中音DO | 4 | 580 | 4 | 1拍 |
2 | 中音RE | 5 | 684 | 5 | 1又1/4拍 |
3 | 中音MI | 6 | 777 | 6 | 1又1/2拍 |
4 | 中音FA | 7 | 820 | 8 | 2拍 |
5 | 中音SO | 8 | 8 | A | 2又1/2拍 |
6 | 中音LA | 9 | 968 | C | 3拍 |
7 | 中音TI | A | 65030 | F | 3又3/4拍 |
1 | 高音DO | B | 65058 | ||
2 | 高音RE | C | 65110 | ||
3 | 高音MI | D | 65157 | ||
4 | 高音FA | E | 65178 | ||
5 | 高音SO | F | 65217 |
3.2.1主程序设计
主程序流程图:
图3.2.1主程序流程
主程序代码:
main()
{
uchar x;
count1=0;
count2=1;
P34=0;
EA=1;
EX0=1;
IT0=1;
EX1=1;
IT1=1;
TMOD=0x01;
TH0=0;
TL0=0;
ET0=1;
while(1)
{
if(count1!=0)
{
switch(count1)
{
case 1:
for(x=0;x<14;x++)
{
duan=1;
P1=huayang1[x];
beep();
delay1(300);
duan=0;
if(count1!=1)
break;
}
break;
case 2:
for(x=0;x<14;x++)
{
duan=1;
P1=huayang2[x];
beep();
delay1(300);
duan=0;
if(count1!=2)
break;
}
break;
case 3:
for(x=0;x<16;x++)
{
duan=1;
P1=huayang3[x];
beep();
delay1(300);
duan=0;
if(count1!=3)
break;
}
break;
case 4:
for(x=0;x<8;x++)
{
duan=1;
P1=huayang4[x];
beep();
delay1(300);
duan=0;
if(count1!=4)
break;
}
break;
}
}
else
{
song();
delay1(1000);
}
}
}
3.2.2 播放音乐子程序设计
播放音乐子程序:
void song()
{
uint temp;
uchar jp;
i=0;
while(1)
{
if(count2==0)
{
break;
}
if(count2==1)
temp=qnzl[i];
if(count2==2)
temp=jmszl[i];
if(temp==0xff)
break;
jp=temp/16;
duan=1;
P1=yinyue[jp];
duan=0;
if(jp!=0)
{
timeh=cuzhi[jp*2];
timel=cuzhi[jp*2+1];
}
else
{
TR0=0;
fm=1;
}
delay(temp%16);
TR0=0;
fm=1;
delay1(10);
TR0=1;
i++;
}
TR0=0;
fm=1;
}
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=19000;y>0;y--);
}
void delay1(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}
void beep()
{
uchar i;
for(i=0;i<50;i++)
{
fm=~fm;
delay1(1);
}
fm=1;
}
3.3调试成果
软件硬件结合调试成果图3.3只是一部分。
图3.3 调试成果
4 心得体会
在这次课设中,从拿到课题,查阅资料,编程,画仿真图,进行仿真,焊接,达到最终结果。只能说是一个比较浩大的工程。编程的时候没有想那么多,程序编好之后,keil显示的没有错误真的很高兴。可是按照程序画好仿真图的时候,仿真结果却出不来,达不到理想结果,咨询老师发现是中断的问题,可是改完中断之后还是有嘟嘟声,经过查资料之后,发现主程序也有问题,又继续接着改。终于出来了理想的结果。以为焊接是最简单的,没想到焊接了两天还是错误的,开始是没有给芯片接上地和电源,还是没有声音,发现是蜂鸣器的原因,因为电流太小,加上一个三极管和两个电阻终于出来了想要的歌声,当时真的很激动,毕竟这个是自己参与做出来的,还成功那个了。通过这次实验,我明白了团队的力量是不容小觑的,不懂就要问,就要查资料,不能放任问题不管。
参考文献
[1] 李建忠.单片机原理及应用[M],西安电子科技大学出版社,2008.2.
[2] 黄智伟.全国大学生电子设计竞赛系统设计[M],北京:北京航空航天大学出版社,2006.6.
[3] 黄智伟.凌阳单片机课程设计指导[M],北京:北京航空航天大学出版社,2006.11.
[4] 李广弟,朱月秀,王秀山.单片机基础[M],北京:北京航空航天大学出版社,2001.7.
[5] 赵曙光,郭万有,杨颂华.可编程逻辑器件原理开发与应用[M],西安:西安电子科技大学, 2000.
[6] 候伯亨.VHDL硬件描述语言与数字逻辑电路设计[M], 西安:西安电子科技大学出版社, 1999.
[7] 康华光. 模拟电子技术基础(第四版)[M], 武汉:华中理工大学出版社,1999.
[8] 谭浩强.C语言程序设计(第二版)[M],北京:清华大学出版社,1991.
[9] 陈小忠,黄宁. 单片机接口技术实用子程序[M],北京:北京人民邮电出版社, 2005.
[10] 欧伟明,周春临,瞿遂春.电子信息系统设计[M],西安电子科技大学出版社,2005.9.
[11] 贾立新,王涌.电子系统设计与实践[M],北京:清华大学出版社,2007.
[12] 罗亚非.凌阳16位单片机应用基础[M],北京:北京航空航天大学出版社,2003.
[13] 雷思孝.凌阳单片机原理及实用技术[M],西安电子科技大学,2004.
附录
源程序代码
#include #define uchar unsigned char #define uint unsigned int sbit duan=P2^6; sbit key1=P3^2; sbit key2=P3^3; sbit fm=P2^7; sbit P34=P3^4; uchar code huayang1[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd, 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf}; uchar code huayang2[]={0x7f,0xfe,0xbf,0xfd,0xdf,0xfb,0xef, 0xf7,0xef,0xfb,0xdf,0xfd,0xbf,0xfe}; Uchar code huayang3[]={0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01, 0x0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; char code huayang4[]={0x55,0xaa,0xcc,0x33,0x99,0x66,0x0f, 0xf0}; uchar count1; uchar count2; uchar timeh,timel,i; uchar code qnzl[]={0x02,0x82,0x16,0x32,0x54,0x02,0x52,0xA6, 0x32,0x54,0x02,0x52,0x,0x74,0xB6,0x,0x52,0x5C,0x32,0x22, 0x16,0x12,0x14,0x32,0x22,0x16,0x12,0x14,0x22,0x32,0x26,0x12,0x94,0x22,0x32,0x2C,0x32,0x52,0x36,0x22,0x14,0x54,0xAC,0x92,0xA2,0x96,0xA2,0x96,0x82,0x3C,0x54,0x36,0x22,0x14,0x54, 0xAC,0x92,0xA2,0x16,0x12,0x14,0x22,0x32,0x2C,0x02,0x82, 0x16,0x32,0x56,0x12,0xA6,0x32,0x56,0x52,0x66,0x72,0xB6,0x62, 0x1C, 0xff}; uchar code jmszl[]={0x03,0x04,0x04,0xc2,0x14,0x12,0x12,0x12, 0x11,0x11,0xc2,0xd1,0xe1,0x14,0x02,0x32,0x12,0x21,0x31,0x52,0x51,0x51,0x54,0x32,0x31,0x31,0x12,0x11,0x31,0x52,0x51, 0x31,0x24,0x24,0x24,0x,0x54,0x24,0x34,0x52,0x32,0x21,0x31,0x12,0x11,0x21,0x34,0x04,0x52,0x51,0xd1,0x12,0x12,0x32, 0x31,0x31,0x52,0x51,0x51,0x22,0x22,0x22,0xd2,0xd1,0x24,0x22,0xc2,0x14,0x12,0x34,0x32,0x32,0x54,0x54,0x54,0x54, 0x12,0x11,0x31,0x52,0x51,0x51,0x,0x54,0x32,0x31,0x11,0x52,0x52,0x52,0x32,0x02,0x12,0x02,0xc4,0x14,0xa2,0xa1,0x11, 0x52,0x52,0x52,0x32,0x02,0x12,0x02,0xc4,0x14,0xc4,0x14,0xc4,0x14,0x14,0x04, 0x04,0x04,0x04,0x04, 0xff}; uchar code cuzhi[]={ 0xff,0xff, 0xFC,0x8E, 0xFC,0xED, 0xFD,0x43, 0xFD,0x6A, 0xFD,0xB3, 0xFD,0xF3, 0xFE,0x2D, 0xFE,0x47, 0xFE,0x76, 0xFE,0xA1, 0xFE,0xC7, 0xFE,0xD9, 0xFE,0xF9, 0xFF,0x16 }; Uchar yinyue[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f,0x0,0x0}; void delay1(uint z); void delay(uint z); void song(); void beep(); main() { uchar x; count1=0; count2=1; P34=0; EA=1; EX0=1; IT0=1; EX1=1; IT1=1; TMOD=0x01; TH0=0; TL0=0; ET0=1; while(1) { if(count1!=0) { switch(count1) { case 1: for(x=0;x<14;x++) { duan=1; P1=huayang1[x]; beep(); delay1(300); duan=0; if(count1!=1) break; } break; case 2: for(x=0;x<14;x++) { duan=1; P1=huayang2[x]; beep(); delay1(300); duan=0; if(count1!=2) break; } break; case 3: for(x=0;x<16;x++) { duan=1; P1=huayang3[x]; beep(); delay1(300); duan=0; if(count1!=3) break; } break; case 4: for(x=0;x<8;x++) { duan=1; P1=huayang4[x]; beep(); delay1(300); duan=0; if(count1!=4) break; } break; } } else { song(); delay1(1000); } } } void int0() interrupt 0 { EA=0; delay1(1); if(key1==0) { count2=0; TR0=0; count1++; if(count1==5) count1=1; } EA=1; } void int1() interrupt 2 { EA=0; delay1(1); if(key2==0) { count1=0; TR0=1; i=0; count2++; if(count2==3) count2=1; } EA=1; } void timer0() interrupt 1 { TH0=timeh; TL0=timel; fm=~fm; } void song() { uint temp; uchar jp; i=0; while(1) { if(count2==0) { break; } if(count2==1) temp=qnzl[i]; if(count2==2) temp=jmszl[i]; if(temp==0xff) break; jp=temp/16; duan=1; P1=yinyue[jp]; duan=0; if(jp!=0) { timeh=cuzhi[jp*2]; timel=cuzhi[jp*2+1]; } else { TR0=0; fm=1; } delay(temp%16); TR0=0; fm=1; delay1(10); TR0=1; i++; } TR0=0; fm=1; } void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=19000;y>0;y--); } void delay1(uint z) { uint x,y; for(x=z;x>0;x--) for(y=112;y>0;y--); } void beep() { uchar i; for(i=0;i<50;i++) { fm=~fm; delay1(1); } fm=1; }