单片机课程设计—八音盒
单片机课程设计—八音盒
专 业 自动化
学 号 1062510233
学生姓名 张成振
指导教师 黄皎
摘要
本设计是基于STC90C516RD+单片机设计的八音盒,按下按键可以演奏预先设定的歌曲旋律。通过本设计,可以学习MCS-51系列单片机定时器、外部中断、按键扫描、数码管显示以及蜂鸣器控制等程序设计,从而对51系列单片机有直观的认识。
本设计设定中7音和高7音,通过矩阵键盘可以控制蜂鸣器发出某一对应音调,可以弹奏乐曲,实现电子琴的功能。通过外部中断可实现演奏预先设定的歌曲的功能。同时,数码管动态显示歌曲对应曲目或音调对应音高。
通过反复调试,各项功能均能准确无误的实现,实现基本部分和提高部分要求。通过本次课程设计,加深了对单片机原理课程的理解,强化了责任意识,增强了团队合作,达到了预期目的和效果。
关键词:51单片机 八音盒 定时器 外部中断 按键扫描 数码管显示
一、绪论
1.1 课程设计背景
《单片机》是一门技术性、应用性很强的学科,实验课教学是它的一个极为重要的环节。不论理论学习还是实际应用,都离不开实验课教学。如果不在切实认真地抓好学生的实践技能的锻炼上下功夫,单凭课堂理论课学习,势必出现理论与实践脱节,学习与应用脱节的局面。
1.2 课程设计目的
让同学们在理论学习的基础上,通过完成一小系统的设计,使学生不但能够将课堂上学到的理论知识与实际应用结合起来,而且能够对电子电路、电子元器件、印制电路板等方面的知识进一步加深认识,同时在焊接技术、相关仪器设备的使用技能等方面得到较全面的锻炼和提高,为今后能够独立进行某些传感器应用系统的开发设计工作打下一定的基础。
1.3 课程设计任务
1.3.1 基本部分要求
利用蜂鸣器和K20-K27制作一个八音盒,内存八首乐曲,当按下不同的按键时,奏出不同的乐曲。其中《茉莉花》是必选曲目,其他任意。例如:按下K20奏出《茉莉花》。(提示:利用定时器产生不同的音调,需要查do,re,mi等音调的频率。)
1.3.2 提高部分要求
把其他按键当作琴键,可以弹奏乐曲。
1.4 课程设计意义
通过自己动手设计单片及组成的器件,在软件及硬件上进一步了解单片机的原理,深入了解了单片机C51语言的实际应用,能更深地理解课堂上所学的
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
,巩固C语言程序编写,体会作为一名设计人员所需要具备的各种能力,学会理论知识联系实际,提高发现问题,分析问题,解决问题和实践动手的能力。
二、系统整体设计
2.1 系统设计原理
2.1.1 音乐发生器设计
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
及思路
在进行设计前,首先要对音乐知识有基本的理解,其次要明白单片机产生音乐脉冲的原理,最后完成硬件原理图和相关程序的设计。
音作为一种物理现象,是由于物体振动而产生的,振动产生的声波作用于人耳,听觉系统将神经冲动传达给大脑,进而产生听觉。人耳能听到的声音频率大约在11~20000Hz,而音乐中使用的音一般在27~4100Hz。
乐音体系中各音级的名称叫做音名,被广泛采用的是C D E F G A B(do re
mi fa so la si则多用于歌唱,称为唱名)。乐音体系中音高关系的最小尽量单位叫做半音,两个半音构成一个全音。乐音中有几十个高低不同的音,但是最基本的只有这七个音,其他高、低音的音名都是在这个基础上变化出来的。
在乐谱表上用来表示正在进行的音的长短的符号,叫做音符。不同的音符代表不同的长度。音符有一下几种:全音符、二分音符、四分音符、八分音符、十六分音符、三十二分音符、六十四分音符。
此外,还有一种附点音符,它就是指带附点的音符,所谓附点就是记载音符右边的小圆点,表示增加前面音符时值的一半。
音持续的长短即时值,一般用拍数表示,休止符表示暂停发音。音符与节拍数之间的对应关系如表1所示。
表1 音符与节拍数之间的对应关系表
音符 节拍数 音符 节拍数
x--(全音符) 4拍 x?(附点八分音符) 3/4拍
x-(二分音符) 2拍 x?(附点十六分音符) 3/8拍
X(四分音符) 1拍 000(三分休止符) 休止3拍
X(八分音符) 1/2拍 00(二分休止符) 休止2拍 X(十六分音符) 1/4拍 0(四分休止符) 休止1拍 x?(附点四分音符) 1.5拍 0(八分休止符) 休止1/2拍
一首音乐及时由许多不同的音符组成的,而每一个音符对应着不同的频率,这样就可以利用不同的频率的组合,加以拍数对应的延时来构成不同的音乐。 2.1.2 音频脉冲和音乐节拍的实现
音乐是由不同的音乐脉冲和音乐节拍配合产生的,因此设计之前,首先要对它们进行了解。
2.1.3 音频脉冲的产生
音乐的产生需要不同频率的音频脉冲,对于单片机而言,可以利用它的定时/计数器产生这样的方波频率信号。具体地说,只要知道某一音频的频率,求得它的周期,然后将次周期除以2,得到半周期的时间,利用定时/计数器计时这半个周期,计时到后就将输出脉冲的I/O反相。就可以在I/O端口上得到此脉冲。
单片机工作在12MHz时钟频率下,其时钟周期为1us,因此可以利用89C51
[9]的内部定时/计数器T0,使其工作模式为1,工作在计数器状态下,改变计数初值TH0和TL0以产生不同频率的脉冲信号。T的值决定了计数初值TH0和TL0的值,TH0=T/256,TL0=T%256。
计数值公式如下:
T,65536,F,2,F,65536,1000000,2,262ir
F式中,:单片机内部时钟周期为1us,所以其频率为1MHz。 i
F :产生音符所需的频率。 r
通过上式计算,可以求得各个音符频率的计数值T。
2.1.4 音乐节拍的产生
节拍是指音乐持续的长短,是除音符之外音乐的另一关键组成部分,在单片机系统中可以通过延时来实现。
如果1/4拍的延时设为0.2s,则1拍的时间为0.8s。以此类推,可以求出
其余节拍的值,节拍的延时时间值与音乐的曲调值有相对应的关系,表2所示为不同曲调下的1/4和1/8节拍的时间设定。
如果单片机要实现自己播放音乐,那么必须在程序设计中考虑到节拍的设置,在89C51中,可以用一个直接存储一个音符,其中低4位是节拍码。节拍数和节拍码的对照表如表3所示。
表2 各调节拍的时间设定
曲调值(1/8节拍) DELAY 曲调值(1/4节拍) DELAY
调4/4 62ms 调4/4 125ms
调3/4 94ms 调3/4 185ms
调2/4 125ms 调2/4 250ms
表3 节拍数与节拍码的对照
节拍码 节拍数 节拍码 节拍数
1 1/4拍 1 1/8拍
2 2/4拍 2 1/4拍
3 3/4拍 3 3/8拍
4 1拍 4 1/2拍
5 1.25拍 5 5/8拍
6 1.5拍 6 3/4拍
8 2拍 8 1拍
A 2.25拍 A 1.25拍
C 3拍 C 1.5拍
F 3.75拍 2.1.5 音频功放
音乐的播放最后是通过扬声器完成的,但是直接用单片机产生的音频脉冲不足以直接驱动扬声器来完成音乐的播放,因此这就要求在单片机端口与扬声器之间链接功率放大电路,以实现最终的目的。
评定功率放大电路有3个重要的指标,即输出功率、效率、非线性失真。总的来说,要求功率放大器在保证系统安全运用的情况下,获得尽可能大的输出功
[10]率、尽可能高的效率和尽可能小的非线性失真。为了简化设计,这里用了基
于三极管的音频功放电路。驱动电路如图1所示。
图1 音频驱动电路
2.2 系统硬件设计
2.2.1 51单片机最小系统设计
音乐发生器设计电路包括51系列单片机系统图和音频功放电路以及显示电路。单片机输出的音频脉冲信号比较微弱,一般只有几个微安,经过三极管的放大可以直接驱动喇叭发声。硬件电路原理图如图2所示。
图2 硬件设计图
2.2.2 键盘接口电路
如图2-2所示,为键盘接口电路,包含行列式键盘和独立式按键输入电路。 P20,P23为行,P24,P27为列,构成4×4行列式键盘。按键编号规律为S2+行号,列号。例如S226表示P22行和P26列跨接处的按键。
图2-2 键盘接口电路
K20,K27构成独立式按键,分别接在P20-P27上,当按键按下时,对应的口线输入0,同时相应的LED点亮。D20,D27构成P20,P27的状态指示,当某口线输出0,相应的LED点亮。有4个用途:1、当行列式键盘逐行扫描时,可做为正在被扫描的行的指示。2、当行列式键盘逐行扫描时,可做为已按下键的指示。例:当S215键按下,扫到P21行时,D21和D25会被点亮。3、可做为独立式按键被按下的指示。见上一段。4、当P2口不做为键盘输入时,D20,D27可做为输出器件,实现流水灯等功能。
2.2.3 数码管显示电路
如图2-3所示,为数码管显示电路。这部分电路由4位共阴的数码管LED1、单个数码管LED2和8个独立发光二极管L1-L7组成。这3个部分都是共阴结构,并联在一起,连接在P0口上。
LED1用于完成LED动态显示实验,各个位选线为P24,P27,段码由P0口输出;LED2的COM端接地,完成LED静态显示实验;L1,L7,可以方便地读出P0输出的二进制数据,亦可做流水灯实验。
7407在此起驱动作用。
图2-3 数码管显示电路
2.2.4 外部中断0触发电路
图2-4 外部中断0触发电路
图2-4所示的电路为NE555和电容组成的单稳电路。
当S_INT0按钮按下后产生一个低电平单稳信号送单片机的INT0,同时D_PLUS1亮一次,做为外部中断请求信号。
2.3 系统软件设计
2.3.1 14音调的确定
通过前文所说的方法,可以确定各音调所对应的中断半周期,从而确定各音
调对应的定时器中断初值。具体如下:
uchar code cuzhi[]={ 0xff,0xff, //占位
0xFC,0x8E, //中央C调1-7
0xFC,0xED,
0xFD,0x43,
0xFD,0x6A,
0xFD,0xB3,
0xFD,0xF3,
0xFE,0x2D,
0xFE,0x47, //高八度1-7
0xFE,0x76,
0xFE,0xA1,
0xFE,0xC7,
0xFE,0xD9,
0xFE,0xF9,
0xFF,0x16 };
2.3.2 音乐播放函数
音乐播放函数主要实现音乐的播放,同时在音乐切换或者模式切换时能快速
实现终止当前播放的音乐。具体如下:
void Song()//唱歌函数
{
uint temp;
uchar jianpu;//jp是简谱
uchar i = 0;
TR0 = 1;
while((i<=200)) ///key_flag
{
if(song_number_last != song_number)
{i = 0; song_number_last = song_number;}
switch(song_number)
{
case 0: temp = song0[i]; break;
case 1: temp = song1[i]; break;
case 2: temp = song2[i]; break;
case 3: temp = song3[i]; break;
case 4: temp = song4[i]; break;
case 5: temp = song5[i]; break;
case 6: temp = song6[i]; break;
case 7: temp = song7[i]; break;
default: break;
}
if(temp == 0xff)
break;
jianpu = temp/16; //取数的高4位
if(jianpu != 0)
{
timeh = cuzhi[jianpu*2];
timel = cuzhi[jianpu*2+1];
}
else
{
TR0 = 0;
SPEAKER = 1;//关蜂鸣器
}
delay(temp%16); //取数的低4位
TR0 = 0;
SPEAKER = 1;
delay1(10); //唱完一个音停10MS
TR0 = 1;
i++;
}
TR0 = 0;
SPEAKER = 1;
}
2.3.3 音调播放函数
音调播放函数主要实现单个音调的播放,实现电子功能。具体如下: void Song_single()//音调函数
{
TR0 = 1;
timeh = cuzhi[key_number*2];
timel = cuzhi[key_number*2+1];
delay(3); //取数的低4位
TR0 = 0;
SPEAKER = 1;
}
2.3.4 数码管显示函数
通过对数码管的控制,实时显示歌曲对应的曲目或音调对应的音高。具体如下:
void Number_play(uchar number) //显示歌曲对应的数字
{
NUMBER_wei = 0xff;
NUMBER_wei = Number_wei[0]; // 位选
NUMBER = 0x00;//去除遗辉
NUMBER = Number[number];// 段选
delayms(1); //延时
}
2.3.5 中断函数
中断函数包括T0定时器和外部中断0中断函数,T0定时器中断产生一定
频率的方波,控制蜂鸣器发出不同的音调。外部中断控制歌曲曲目的变换。具体
如下:
void timer0() interrupt 1 //定时器0服务函数//用于产生各种音调 {
TH0 = timeh;
TL0 = timel;
SPEAKER = ~SPEAKER;
}
void interrupt0(void) interrupt 0 using 3 //外部中断0服务程序 {
//delayms(1);//保留,提高部分按键电子琴部分使用
song_number++;
song_number = song_number % 8;
}
三、实验结果及分析
3.1 调试过程
通过了解音阶和节拍的特点后,我们搜集了各音调对应的频率,经计算后烧入单片机发现效果不太好,噪音很大,各音调很难区分,经检查,发现是蜂鸣器存在问题,通过调换多个试验箱后,终于找到噪声较小的蜂鸣器。
各音调可以正常发出后,我们发现,歌曲的节拍存在问题,与实际歌曲相比偏快,经分析是延时间隔函数存在问题,经不断调整后,节拍正常。
在选择歌曲是,我们选择了大家耳熟能详的儿歌、流行歌曲及必选曲目《茉莉花》,在编曲时,主要由我们小组音乐素养较高的沈洁同学负责。 3.2 调试结果
经过小组讨论,我们小组确定了矩阵键盘控制音调,外部中断控制歌曲的设计
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
,达到了课程设计的基本要求,也完成了发挥部分的内容。
四 收获与
心得
信息技术培训心得 下载关于七一讲话心得体会关于国企改革心得体会关于使用希沃白板的心得体会国培计划培训心得体会
课程设计结束了,我收获了很多在课堂上无法学到的知识,不仅有设计方案的确定,还有解决问题的方法硬件发设计能力,以及编程的
规范
编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载
性等多方面的能力也得到了大幅度的提高。
通过本次课程设计将课本的知识实体化,化抽象为具体,激发了我们的兴趣。通过这次课程设计,我们不仅深入的学习了单片机,还学到了很多课本上没有的知识。
1)担当。做人做事要敢于担当,在课程设计期间,我负责班级的几个同学,每天督促他们及时独立完成实验,对于他们出现的问题,也尽自己所能给予解答。一个集体中,个人的强大不是真的强大,集体的强大才是真的强大。同时,在帮助同学的同时,我也巩固了自己的理论知识,增强了同他人交流的能力,收益匪浅。
2)团队合作。一个团队,只有团结一心才能发挥1+1>2的效果。在课程设计期间,我们小组共同讨论制定了最终的设计方案,同时,我们合理分工,各自发挥自己所长,团结合作。例如我主要负责软件设计、音乐素养较高的沈洁同学负责音调的确定及歌曲的编曲、常杰同学负责上网搜集资料,对于出现的问题及时给与解决。
3)解决问题的能力。对于在课程设计期间出现的问题,我们小组集体讨论,查找资料,大家齐心协力,共同思考,互相启发,最终解决问题。
总的来说,这次课程设计我受益匪浅,不仅巩固了我的基础知识,也进一步培养了动手实践的能力。最后说一句,单片机真的很有意思。
附录一:软件程序
#include
#define uchar unsigned char
#define uint unsigned int
#define NUMBER P0 //P0段选
#define NUMBER_wei P2 //位选自左刀右
sbit SPEAKER=P3^7;//蜂鸣器连续的IO口
uchar code Number[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, //数码管段
选
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
uchar code Number_wei[] = {0x7f,0xbf,0xdf,0xef}; //数码管位选
uchar hang = 0,lie = 0,song_number = 0,key_number = 0;//歌曲编号
uchar timeh,timel;//定时器初值
uchar key_number_last = 0,song_number_last = 0;//按键标志位 0表示有键值改变按下,
1无
//---------------------------简谱---------------------------------------
//编程规则:字节高位是简谱,低位是持续时间,代表多少个十六分音符
//1-7代表中央C调,8-E代表高八度,0代表停顿,最后的0是结束标志
uchar code
song1[]={0x31,0x21,0x31,0x51,0x61,0x51,0x81,0x61,0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x81,0x61,0x81,0x58, //茉莉花
0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x61,0x52,0x52,0x22,0x31,0x51,0x31,0x21,0x11,0xD1,0x16,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x21,0x11,0x21,0xD4,0x12,0x23,0x31,0x11,0x21,0x11,0xD1,0x11,0xD1,0xC6,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x21,0x11,0x21,0xD4,0x12,0x23,0x31,0x11,0x21,0x11,0xD1,0x11,0xD1,0xC6,
0x31,0x21,0x31,0x51,0x61,0x51,0x81,0x61,0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x81,0x61,0x81,0x58,
0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x61,0x52,0x52,0x22,0x31,0x51,0x31,0x21,0x11,0xD1,0x16,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x21,0x11,0x21,0xD4,0x12,0x23,0x31,0x11,0x21,0x11,0xD1,0x11,0xD1,0xC6,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x21,0x11,0x21,0xD4,0x12,0x23,0x31,0x11,0x21,0x11,0xD1,0x11,0xD1,0xC6,
0x31,0x21,0x31,0x51,0x61,0x51,0x81,0x61,0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x81,0x61,0x81,0x58,
0x51,0x31,0x54,0x62,0x82,0x91,0xA1,0x91,0x61,0x52,0x52,0x22,0x31,0x51,0x31,0x21,0x11,0xD1,0x16,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x21,0x11,0x21,0xD4,0x12,0x23,0x31,0x11,0x21,0x11,0xD1,0x11,0xD1,0xC6,
0x31,0x21,0x12,0x23,0x31,0x52,0x61,0x81,0x62,0x52,0x51,0x31,0x22,
0x31,0x51,0x31,0x31,0x21,0x11,0x21,0xD4,0x82,0x23,0x31,0x81,0x91,0x81,0x61,0x51,0x61,0x81,0xA1,0x91,0x81,0x61,0x81,0x58,
0xff};
uchar code
song0[]={0x12,0x22,0x32,0x12,0x12,0x22,0x32,0x12,0x32,0x42,0x54,0x32,0x42,0x54,0x51,0x61, //两只老虎
0x51,0x41,0x32,0x12,0x51,0x61,0x51,0x41,0x32,0x12,0x32,0x52,0x14,0x32,0x52,0x14,0x32,0x52,0x14,0xff};
uchar code
song2[]={0x12,0x12,0x14,0x54,0x32,0x32,0x34,0x14,0x12,0x32,0x54,0x54,0x42,// 新年快乐
0x32,0x28,0x22,0x32,0x44,0x44,0x32,0x22,0x34,0x14,0x12,0x32,
0x24,0x54,0x72,0x22,0x18,0xff };
uchar code
song3[]={0x12,0x12,0x52,0x52,0x62,0x62,0x54,0x42,0x42,0x32,0x32,0x22,0x21,0x14, //小星星
0x52,0x52,0x42,0x42,0x32,0x32,0x24,0x52,0x52,0x42,0x42,0x32,0x32,0x24,
0x12,0x12,0x52,0x52,0x62,0x62,0x64,0x42,0x42,0x32,0x32,0x22,0x22,0x14,0xff};
uchar code
song4[]={0x32,0x32,0x42,0x52,0x52,0x42,0x32,0x22,0x12,0x12,0x22,0x32,0x33,0x21,0x24,//欢
乐颂
0x32,0x32,0x42,0x52,0x52,0x42,0x32,0x32,0x12,0x12,0x22,0x32,0x23,0x11,0x14,
0x22,0x22,0x32,0x12,0x22,0x31,0x41,0x32,0x12,0x22,0x31,0x41,0x32,0x12,0x12,
0x22,0x52,0x32,0x32,0x42,0x52,0x52,0x41,0x32,0x22,0x12,0x12,0x22,0x32,0x22,0x11,0x14,0xff};
uchar code
song5[]={0x12,0x12,0x12,0x32,0x52,0x52,0x52,0x52,0x62,0x62,0x62,0x82,0x54,0x42,0x42,//小
毛驴
0x42,0x62,0x32,0x32,0x32,0x32,0x22,0x22,0x22,0x22,0x54,0x54,0x12,0x12,0x12,
0x32,0x52,0x52,0x52,0x52,0x62,0x62,0x62,0x82,0x54,0x42,0x42,0x44,0x64,0x32,
0x32,0x34,0x34,0x34,0x34,0x24,0x24,0x24,0x34,0x14,0xff};
uchar code song6[]={ //寂寞沙洲冷
0x12,0x12,0x22,0x32,0x31,0x22,0x21,0x22,0x21,0x31,0x51,0x52,
0x31,0x52,0x61,0x15,0x14,0x51,0x52,0x31,0x52,0x62,0x13,0x11,
0x13,0x32,0x28,0x08,0x28,0x31,0x32,0x31,0x32,0x11,0x21,0x51,
0x52,0x51,0x52,0x51,0x51,0x31,0x32,0x31,0x32,0x81,0x72,0x63,
0x62,0x71,0x81,0x72,0x61,0x61,0x52,0x31,0x21,0x32,0x51,0x54,
0x22,0x12,0x11,0x12,0x11,0x12,0x12,0x14,0x26,0x32,0x26,0x32,
0x61,0x51,0x51,0x31,0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51,
0x02,0x32,0x81,0x81,0x81,0x81,0x62,0x52,0x34,0x31,0x81,0x81,
0x81,0x61,0x91,0x82,0x51,0x51,0x51,0x51,0x31,0x61,0x53,0x21,
0x11,0x21,0x11,0x22,0x11,0x21,0x26,0x32,0x61,0x51,0x51,0x31,
0x31,0x21,0x31,0x51,0x61,0x51,0x31,0x51,0x52,0x31,0x31,0x81,
0x81,0x81,0x61,0x91,0x81,0x61,0x31,0x56,0x32,0x32,0x81,0x81,
0x81,0x81,0x91,0x81,0x61,0x81,0x61,0x51,0x31,0x51,0x34,0x21,
0x31,0x51,0x31,0x21,0x11,0x61,0x21,0x16,0xff};
uchar code
song7[]={0x61,0x71,0x82,0x71,0x62,0xA2,0x71,0x76,0x61,0x71,0x82,0x71,0x62,0x52,0x31, //千年之恋
0x36,0x61,0x71,0x82,0x71,0x62,0xA3,0x73,0x62,0x53,0x42,0x63,0x83,0x83,0x91,
0x91,0x61,0x71,0x82,0x71,0x62,0xA2,0x71,0x76,0x61,0x71,0x82,0x71,0x62,0x52,
0x31,0x36,0x61,0x71,0x82,0x71,0x62,0xA3,0x73,0x62,0x53,0x42,0x82,0x88,0x02,
0x74,0x93,0x89,0xff };
//简谱音调对应的定时器初值,适合11.0592M的晶振 uchar code cuzhi[]={0xff,0xff, //占位
0xFC,0x8E, //中央C调1-7
0xFC,0xED,
0xFD,0x43,
0xFD,0x6A,
0xFD,0xB3,
0xFD,0xF3,
0xFE,0x2D,
0xFE,0x47, //高八度1-7
0xFE,0x76,
0xFE,0xA1,
0xFE,0xC7,
0xFE,0xD9,
0xFE,0xF9,
0xFF,0x16 };
void delayms(uint x)//延时0.2ms*x
{
uint n_count;
for(x;x>0;x--)
for(n_count=200;n_count>0;n_count--);
}
void Number_play(uchar number) //显示歌曲对应的数字 {
NUMBER_wei = 0xff;
NUMBER_wei = Number_wei[0]; // 位选
NUMBER = 0x00;//去除遗辉
NUMBER = Number[number];// 段选
delayms(1); //延时
}
void delay(uint z) //延时165MS,即十六分音符
{ uint x,y;
for(x=z;x>0;x--)
for(y=19000;y>0;y--); }
void delay1(uint z) //延时1MS
{ uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}
void keyscan()//键盘扫描程序
{
P2=0xf0;
if((P2&0xf0)!=0xf0)
{
switch(P2)
{
case 0x70:hang = 0;break;
case 0xb0:hang = 1;break;
case 0xd0:hang = 2;break;
case 0xe0:hang = 3;break;
default: break;
}
delayms(1);
P2 = 0x0f;
if((P2&0x0f)!=0x0f)
{
switch(P2)
{
case 0x07:lie = 0;break;
case 0x0b:lie = 1;break;
case 0x0d:lie = 2;break;
case 0x0e:lie = 3;break;
default: break;
}
}
}
key_number = (hang+lie*4); }
void Song()//唱歌函数
{
uint temp;
uchar jianpu;//jp是简谱
uchar i = 0;
TR0 = 1;
while((i<=200)) ///key_flag
{
if(song_number_last != song_number)
{i = 0; song_number_last = song_number;}
switch(song_number)
{
case 0: temp = song0[i]; break;
case 1: temp = song1[i]; break;
case 2: temp = song2[i]; break;
case 3: temp = song3[i]; break;
case 4: temp = song4[i]; break;
case 5: temp = song5[i]; break;
case 6: temp = song6[i]; break;
case 7: temp = song7[i]; break;
default: break;
}
if(temp == 0xff)
break;
jianpu = temp/16; //取数的高4位
if(jianpu != 0)
{
timeh = cuzhi[jianpu*2];
timel = cuzhi[jianpu*2+1];
}
else
{
TR0 = 0;
SPEAKER = 1;//关蜂鸣器
}
delay(temp%16); //取数的低4位
TR0 = 0;
SPEAKER = 1;
delay1(10); //唱完一个音停10MS
TR0 = 1;
i++;
}
TR0 = 0;
SPEAKER = 1;
}
void Song_single()//音调函数
{
TR0 = 1;
timeh = cuzhi[key_number*2];
timel = cuzhi[key_number*2+1];
delay(3); //取数的低4位
TR0 = 0;
SPEAKER = 1;
}
void main()
{
EA=1;//开总中断
EX0=1;//开外部中断0
IT0=1;//外部中断0下降沿触发方式
TMOD=0x01;//定时器0工作在方式1
TH0 = 0;
TL0 = 0;
ET0 = 1;
//TR0 = 1;
while(1)
{
if(song_number_last != song_number)
{ Number_play( song_number );Song();song_number_last = song_number;}
if(key_number_last != key_number)
{ Number_play( key_number );Song_single();key_number_last =
key_number;}
keyscan();
Number_play( song_number );
}
}
void timer0() interrupt 1 //定时器0服务函数//用于产生各种音调 {
TH0 = timeh;
TL0 = timel;
SPEAKER = ~SPEAKER;
}
void interrupt0(void) interrupt 0 using 3 //外部中断0服务程序 {
//delayms(1);//保留,提高部分按键电子琴部分使用
song_number++;
song_number = song_number % 8;}