资源描述
通信工程系电子线路实现训练报告
目 录
前 言 1
1. 设计目的 2
2. 硬件设计 2
2.1 AT89S51简介 2
2.2 硬件电路设计的系统框图 3
2.3 AT89S51控制模块的设计 4
2.4 电源模块设计 4
2.5 播放模块设计 4
2.6 按键模块设计 5
2.7 LED显示模块设计 6
3. 软件设计 7
3.1 单片机发声的基本原理 7
3.2 设计的相关音乐说明 7
3.3 主程序 8
3.3.1 主程序设计 8
3.3.2 主程序流程图 8
3.4 延时程序 8
3.4.1 延时程序设计 9
3.4.2 延时程序设计 9
3.5 按键扫描程序 9
3.5.1 按键程序设计 9
4. 调试 10
4.1 检查硬件连接 10
4.2 检查软件系统 10
5. 设计总结 10
6. 参考文献 11
附 录 12
附录1 电路原理图 12
附录2 PCB图 13
附录3 源程序 14
2
前 言
二十世纪九十年代以来,计算机、信息、电子、控制、通信等技术得到迅速发展,促使了社会生产力的提高,也使人们的生产方式和生活方式产生了日新月异的变化。随着人们生活水平的提高及对音乐的喜爱,对音乐播放器的品质,功能,品种等提出了越来越多的要求,表现在对控制系统性能、可靠性等要求越来越高。而品质的提高,功能的更新,可靠性的增强,品种的变化无不与产品的核心控制部分水平的提高密不可分。家用音乐播放器产品及其它有关消费电器产品都是一些开环或闭环控制系统,都由核心控制部分,执行部分与人机界面三部分组成。而最为重要的控制部分一般是由单片机来执行完成的,这就必将导致和促进单片机在音乐领域应用的发展。现在这些由单片机实现的音乐播放器的功能越来越强、费用越来越低。例如,就目前市场上的MP3的功能越来越强大体积却越来越小,价格也逐渐便宜,被大多数人所能接受。但这些音乐播放器也或多或少的存在着一些问题,解决这些问题,非智能化的单片机莫属。
本设计由硬件电路设计和软件程序设计两大部分组成。整个硬件电路是由中心控制、播放、选曲、显示等模块组成,中心控制模块采用AT89S51单片机,播放模块是由8550 NPN三极管和电磁蜂鸣器组成,采用LED显示模块。软件程序运用C语言编程实现。
1. 设计目的
本设计以MSC-51系列单片机为核心,充分利用了AT89S51芯片的I/O引脚,以独立式键盘作为曲目的选择键,采用LED对当前曲目进行显示。本文从理论上分析了该设计方案的可行性,并预计能达到设计要求,主要体现在:
l 可播放多首音乐,且通过按键来选择播放的音乐
l 选择音乐时,显示音乐名称
l 可暂停,能实现循环播放
2. 硬件设计
2.1 AT89S51简介
AT89S51是一个低功耗,高性能CMOS 8位单片机,片内含4k Bytes ISP(In-system programmable)的可反复擦写1000次的Flash只读程序存储器,器件采用ATMEL公司的高密度、非易失性存储技术制造,兼容标准MCS -51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISP Flash存储单元,功能强大的微型计算机的AT89S51可为许多嵌入式控制应用系统提供高性价比的解决方案。
AT89S51具有如下特点:40个引脚,4k Bytes Flash片内程序存储器,128 bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个 全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。
(1)AT89S51引脚图
图1 AT89S51引脚图
此外,AT89S51设计和配置了振荡频率可为0Hz并可通过软件设置省电模式。空闲模式下,CPU暂停工作,而RAM定时计数器,串行口,外中断 系统可继续工作,掉电模式冻结振荡器而保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。同时该芯片还具有PDIP、TQFP和PLCC等三 种封装形式,以适应不同产品的需求。
(2)主要功能特性:
· 兼容MCS-51指令系统 · 4k可反复擦写(>1000次)ISP Flash ROM
· 32个双向I/O口 · 4.5-5.5V工作电压
· 2个16位可编程定时/计数器 · 时钟频率0-33MHz
· 全双工UART串行中断口线 · 128x8bit内部RAM
· 2个外部中断源 · 低功耗空闲和省电模式
· 中断唤醒省电模式 · 3级加密位
· 看门狗(WDT)电路 · 软件设置空闲和省电功能
· 灵活的ISP字节和分页编程 · 双数据寄存器指针
2.2 硬件电路设计的系统框图
硬件电路如图1所示由复位电路、电源电路、时钟电路、按键输入电路、LED显示电路、蜂鸣器电路组成。
图2 音乐播放器的系统框图
按键模块共由16个按键组成,其中4个键作为音符的输入或音乐的播放选择。LED显示模块利用LED对当前播放的歌曲称进行显示。扬声器播放模块由三极管及无源蜂鸣器组成,通过控制模块的控制对当前音乐进行播放。
2.3 AT89S51控制模块的设计
时钟振荡电路在加电后延迟大约10ms振荡器起振,在XTAL2引脚产生幅度为3V左右的正弦波时钟信号,其振荡频率主要由石英晶振的频率决定。电路中两个电容C1、C2的作用使电路快速振,提高电路的运行速度。
通过高电平时单片机复位,在时钟电路开始工作后,当高电平的时间超过大约5ms的时候,即可实现复位。此复位电路同时具备了上电自动复位和按键人工复位的功能,上电复位发生在开机加电时,由系统自动完成,按键人工复位通过一个按键来实现在程序运行时,若遇到死机或死循环等情况时,通过手动复位就可以实现重新启动的操作。按键人工复位需要认为在复位输入端RST上加入高电平。
单片机及其最小系统电路图如3图所示:
图3 最小系统电路图
2.4 电源模块设计
本设计采用直流稳压电源,如图4所示。电源变压器是将交流电网220V的电压变为所需要的电压值。电源模块用于检测电路连接是否正确,正确LED将被点亮。
图4 电源电路
2.5 播放模块设计
鸣器播放模块是由8550三极管和无源蜂鸣器组成,如图5所示。无源蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。无源蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此需要一定的电流才能驱动它,单片机IO引脚输出的电流较小,单片机输出的TTL电平基本上驱动不了蜂鸣器,因此设计过程中增加一个由8550三极管组成的电流放大电路。如图所示,蜂鸣器电路由一个1千欧的电阻,三极管及蜂鸣器组成,通过控制三极管的导通和截止来实现蜂鸣器的响与不响。
图5 蜂鸣器电路
2.6 按键模块设计
按键电路由一个组成,如图6所示。按键用来设置音乐播放器的模式(播放音乐还是按键发音),由于修改模式和弹奏音乐时需要用到很多按键,如果采用独立按键的方式,在这种情况下,编程会很简单,但是会占用大量的I/O口资源,因此在很多情况下都不采用这种方式。为此,我们引入了矩阵键盘的应用,采用四条I/O线作为行线,四条I/O线作为列线组成键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4个,这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。
图6 按键电路
按键功能表如下所示:
播放第
一首歌
播放第
一首歌
播放第
一首歌
播放第
一首歌
表1 按键功能表
2.7 LED显示模块设计
设计选择的是共阳结构的LED显示器,这样只要在公共端接高电平就可以了,且选择的是动态扫描方式。
动态扫描显示接口是单片机中应用最为广泛的一种显示方式之一。其接口电路是把所有显示器的8个笔划段a-h同名端连在一起,而每一个显示器的公共极COM是各自独立地受I/O线控制。CPU向字段输出口送出字形码时,所有显示器接收到相同的字形码,但究竟是那个显示器亮,则取决于COM端,而这一端是由I/O控制的,所以我们就可以自行决定何时显示哪一位了。而所谓动态扫描就是指采用分时的方法,轮流控制各个显示器的COM端,使各个显示器轮流点亮。在轮流点亮扫描过程中,每位显示器的点亮时间是极为短暂的(约1ms),但由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位显示器并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感。播放器显示电路模块设计的电路图如图7所示:
图7 LED显示模块电路图
LED显示功能表如下所示:
播放第一首歌
播放第二首歌
播放第三首歌
播放第四首歌
表2 LED显示功能表
3. 软件设计
3.1 单片机发声的基本原理
我们知道,声音的频谱范围约在几十到几千赫兹,若能利用程序来控制单处机某个口线的高电平或低电平,则在该口线上就能产生一定频率形波,接上喇叭就能发出一定频率的声音,若再利用延时程序控制高 、低电平的持续时间,就能改变输出频率,从而改变音调。音符的节拍我们可以用定时器T0来控制,送入不同的初值,就可以产生不同的定时时间。便如某歌曲的节奏为每分钟94拍,即一拍为0.64秒。但是,由于T0的最大定时时间只能为131毫秒,因此不可能直接用改变T0的时间初值来实现不同节拍。我们可以用T0来产生10毫秒的时间基准,然后设置一个中断计数器,通过判别中断计数器的值来控制节拍时间的长短。例如对1/4拍音符,定时时间为0.16秒,相应的时间常数为16(即10H);对3拍音符,定时时间为1.92秒,相应时间长数为192(即C0H)。我们将每一音符的时间常数和其相应的节拍常数作为一组,按顺序将乐曲中的所有常数排列成一个表,然后由查表程序依次取出,产生音符并控制节奏,就可以实现演奏效果。此外,结束符和休止符可以分别用代码00H和FFH来表示,若查表结果为00H,则表示曲子终了;若查表结果为FFH,则产生相应的停顿效果。为了产生手弹的节奏感,在某些音符(例如两个相同音符)音插入一个时间单位的频率略有不同的音符。
3.2 设计的相关音乐说明
要产生音频脉冲,只要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期时间。利用半周期时间定时这个半周期时间,每当计时到后就将输出的I/O反向,然后重复计时此半周期再对I/O反向,就可以在I/O脚上得到此频率的脉冲。
记数脉冲值与频率的关系公式如:N=Fi/2/Fr。N:记数值;Fi:内部计时依次为1us,故其频率为1 MHZ;Fr:要产生的频率。
其记数值的求法如:T=65536-N=65536-Fi/2/Fr。例:设K=65536,F=1000000=Fi=1 MHZ。求低音DO(26HZ),中音DO(523HZ),高音DO(1046HZ)的记数值。
每个音符使用1个音节,字节的高四位代表音符的高低,低四位代表音符的节拍。如果1拍为0.4秒,1/4拍为0.1秒,假设1/4拍为 DELAY,则1拍为4 DELAY。
3.3 主程序
3.3.1 主程序设计
播放器工作时,先对在程序过程中所需的各种标记位及参数进行初始化赋值,再执行按键扫描子程序并计算及保存键值,根据其中的模式转换键的按键次数进行模式判断,按键次数为1时播放器处于自动播放模式,扬声器播放模块开始工作,同时显示模块进入工作状态对当前曲目进行显示。
3.3.2 主程序流程图
图7 主程序流程图
3.4 延时程序
3.4.1 延时程序设计
延时程序一般是通过一层或多层循环实现,整个过程延时的时间是程序执行的指令总条数乘以执行每条指令所用的时间。由于该系统的晶振选用的是12M,所以执行每条指令所所用时间为2us,程序如下:
void delay_5ms()
{
unsigned int i,j;
for(i=5;i>0;i--)
for(j=120;j>0;j--);
}
3.4.2 延时程序设计
图8 延时程序流程图
3.5 按键扫描程序
3.5.1 按键程序设计
我们引入了矩阵键盘的应用,采用四条I/O线作为行线,四条I/O线作为列线组成键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4个,这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。
3.5.2 按键程序设计流程图
图9 按键扫描程序流程图
4. 调试
4.1 检查硬件连接
在PROTUES检查各硬件管脚是否连接正确,线路逻辑是否正确,例如:晶振电路的连接,复位电路是否设计正确。
4.2 检查软件系统
1.根据系统的原理结构检查各流程图是否正确,再根据流程图来检查程序是否也正确。
2.将所有程序组织起来,在软件环境下运行,检查程序是否正确。通过对硬件和软件系统的认真检查,反复测试,如果没有出现问题即可把源程序编译成HEX文件装载到单片机中,对硬件进行仿真。
5. 设计总结
通过这次毕业设计,使我得到了一次用专业知识、专业技能分析和解决问题全面系统的锻炼。使我在单片机的基本原理、单片机应用系统开发过程,以及在常用编程设计思路技巧的掌握方面都能向前迈了一大步,为日后成为合格的应用型人才打下良好的基础。
在这次设计中,我们完成了一个基于单片机的音乐播放器设计,尽管结果不是完美,但是努力了,获得了丰富的知识和理论的仿学习。我从资料的收集中,掌握了很多单片机的知识,不过还是遇到很多的问题。经过这次的设计是我们不断巩固和提高,并且让我对当今单片机的最新发展技术有所了解。在整个过程中,我学到了新知识,增长了见识。当然,通过本次设计,也发现了我在许多知识上的欠缺。通过实训设计,我们不单单是完成了我们的设计题目,而且了解到了设计的方法和思路。在今后的日子里,我仍然要不断地充实自己,争取在所学领域有所作为。
在这个过程中,有很多值得总结的地方。尤其在应用Altium Designer画图的过程中,需要对细节性的东西比较清楚,对于元件一定要认好它的封装,这样返工的几率才会比较少。做设计的时候,我们应该要有平和的心态,遇见问题是非常正常的,要做的就是多做比较和分析,逐步的排除可能的原因,要坚信“凡事都是有办法解决的”和“问题出现一定有它的原因”,这样最后一定能设计成功。
脚踏实地,认真严谨,实事求是的学习态度,不怕困难、坚持不懈的精神是我在这次设计中最大的收益。我想这是一次意志的磨练,会对我的学习和工作有很大的帮助。
6. 参考文献
[1] 赵亮.液晶显示模块LCD1602应用[J].电子制作,2007(3):58-59.
[2] 李朝青.单片机原理及接口技术[M].北京:北京航空航天大学出版社,2005:374-378.
[3] 王恩荣.MCS-51单片机应用技术实训指导[M].北京:化学工业出版社,2007.
[4] 吴金戌,沈庆阳,郭庭吉.8051单片机实践与应用[M].北京:清华大学出版社,2002.
[5] 张红梅,王磊杰.AT89S52与LED驱动S6B0724的应用[J].电子质量,2008(5):13-16.
[6] 楼然笛.单片机开发[M].北京:人民邮电出版社,1994.32-66
[7] 付家才.单片机控制工程实践技术[M].北京:化学工业出版社 2004.3.54-80
[8] 李光才.单片机课程设计 实例指导[M]. 北京:北京航空航天大学出版社, 2004.45-70
[9] 朱定华.单片机原理及接口技术实验[M].北京:北方交通大学出版社2002.11.110-125
[10] 刘湘涛,江世明.单片机原理与应用[M]. 北京: 电子工业出版社,2006.30-65
附 录
附录1 电路原理图
附录2 PCB图
附录3 源程序
#include <reg52.h>
#define key P1
sbit P3_2=P3^2;
sbit speaker = P3^0;
unsigned char w;
unsigned char flag;
unsigned char flag2=0;
Unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsigned char table2[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80} ;
unsigned char timer0h, timer0l, time;
//--------------------------------------
//单片机晶振采用11.0592MHz
// 频率-半周期数据表 高八位 本软件共保存了四个八度的28个频率数据
code unsigned char FREQH[] = {
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
// 频率-半周期数据表 低八位
code unsigned char FREQL[] = {
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
//--------------------------------------
//世上只有妈妈好数据表 要想演奏不同的乐曲, 只需要修改这个数据表
code unsigned char sszymmh[] = {
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};
/**********乡间小路数据表********************/
code unsigned char xjxl[]={
3,1,2, 3,1,1, 3,1,1, 6,0,1, 6,0,1, 1,1,2, 6,0,1, 5,0,1, 6,0,4, 6,0,2, 6,0,1, 6,0,1, 6,0,2,
1,1,1, 2,1,2, 2,1,1, 3,1,1, 2,1,4, 3,1,1, 3,1,1, 3,1,1, 2,1,1, 4,1,2, 4,1,2, 3,1,2, 2,1,1,
2,1,4, 7,0,1, 7,0,1, 7,0,1, 6,0,1, 5,0,1, 5,0,1, 6,0,1, 7,0,1, 7,0,1, 6,0,1, 5,0,1, 6,0,4,
3,1,1, 6,1,1, 7,1,1, 6,1,1, 5,1,1, 5,1,2, 5,1,1, 2,1,1, 5,1,1, 6,1,1, 5,1,1, 4,1,1, 4,1,2,
3,1,1, 2,1,2, 1,1,1, 2,1,1, 3,1,1, 2,1,1, 1,1,1, 2,1,1, 3,1,4, 6,1,2, 3,1,1, 6,1,1, 7,1,1,
5,1,1, 5,1,2, 2,1,1, 5,1,1, 6,1,1, 5,1,1, 4,1,1, 4,1,2, 4,1,1, 5,1,1, 6,1,1, 4,1,1, 3,1,1,
2,1,2, 5,1,4, 0,0,0};
/*************送别数据表**********************/
code unsigned char songbie[]={
5,1,2, 3,1,3, 5,1,1, 1,2,3, 6,1,2, 1,2,2, 5,1,4,
5,1,2, 1,1,1, 2,1,1, 3,1,2, 2,1,1, 1,1,1, 2,1,4,
5,1,2, 3,1,1, 5,1,1, 1,2,2, 7,1,1, 6,1,2,
1,2,2, 5,1,4, 5,1,2, 2,1,1, 3,1,1, 4,1,2, 7,0,1,
1,1,4, 6,1,2, 1,2,2, 1,2,4, 7,1,2, 6,1,1, 7,1,1,
1,2,4, 6,1,1, 7,1,1, 1,2,1, 6,1,1, 6,1,1, 5,1,1,
3,1,1, 1,1,1, 2,1,8, 5,1,2, 3,1,1, 5,1,1, 1,2,2,
7,1,1, 6,1,2, 1,2,2, 5,1,4, 5,1,2, 2,1,1, 3,1,1,
4,1,2, 7,0,2, 1,1,4, 0,0,0};
/************ 一辈子的孤单数据表****************/
code unsigned char ybzdgd[]={
5,0,1, 5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 3,1,1, 3,1,1, 2,1,1, 2,1,4,
5,0,1, 5,0,1, 3,1,1, 2,1,1, 2,1,1, 2,1,1, 1,1,1,
2,1,1, 3,1,1, 3,1,4, 5,0,1, 5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 3,1,1, 3,1,1, 2,1,1, 2,1,4, 2,1,1, 1,1,1, 3,1,1, 2,1,1,
1,1,1, 2,1,1, 1,1,1, 1,1,8, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 1,1,1, 2,1,1, 2,1,6, 3,1,1, 2,1,2, 1,1,1, 1,1,1, 5,0,1, 6,0,1,
5,0,1, 5,0,6, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 1,1,1, 2,1,1, 2,1,6, 5,0,1, 3,1,1, 2,1,2, 1,1,1, 2,1,2, 3,1,1, 3,1,4,
5,0,1, 3,1,1, 5,1,2, 6,1,1, 3,1,1, 2,1,1, 2,1,6, 5,0,1, 3,1,1, 2,1,2, 1,1,1, 2,1,2, 3,1,1, 3,1,4,
5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 3,1,1, 2,1,1, 2,1,4, 2,1,1, 1,1,1, 3,1,1, 2,1,1, 1,1,1, 2,1,1, 1,1,1, 1,1,1, 1,1,0,
3,1,1, 2,1,1, 2,1,1, 1,1,1, 3,1,1, 2,1,1, 2,1,6, 5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 2,1,1, 3,1,1, 3,1,6,
5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 3,1,1, 2,1,1, 2,1,6, 5,0,1, 3,1,1, 2,1,1, 2,1,1, 1,1,1, 2,1,1, 3,1,1, 3,1,6, 0,0,0};
void delay_5ms()
{
unsigned int i,j;
for(i=5;i>0;i--)
for(j=120;j>0;j--);
}
//--------------------------------------
void t0int() interrupt 1 //T0中断程序,控制发音的音调
{
TR0 = 0; //先关闭T0
speaker = !speaker; //输出方波, 发音
TH0 = timer0h; //下次的中断时间, 这个时间, 控制音调高低
TL0 = timer0l;
TR0 = 1; //启动T0
}
//--------------------------------------
void delay(unsigned char t) //延时程序,控制发音的时间长度
{
unsigned char t1;
unsigned long t2;
for(t1 = 0; t1 < t; t1++) //双重循环, 共延时t个半拍
for(t2 = 0; t2 < 8000; t2++); //延时期间, 可进入T0中断去发音
TR0 = 0; //关闭T0, 停止发音
}
//--------------------------------------
void song() //演奏一个音符
{
TH0 = timer0h; //控制音调
TL0 = timer0l;
TR0 = 1; //启动T0, 由T0输出方波去发音
delay(time); //控制时间长度
}
//--------------------------------------
void delay2(int x)
{
unsigned char i;
while(x--)
{
for(i=0; i<=120; i++);
}
}
/*******************按键扫描程序***********************/
void key_scan()
{
unsigned char w1,w2;
key=0x0f;
w1=key&0x0f;
if(w1!=0x0f)
{
delay2(10);
key=0xf0;
w2=key&0xf0;
w=(w1|w2);
while(key!=0xf0);
}
else
w=0xff;
}
void key_tran()
{
switch(w)
{
case 0xee:P2=table2[0];P0=table[1];flag=1;break;
case 0xed:P2=table2[0];P0=table[2]; flag=2;break;
case 0xeb:P2=table2[0];P0=table[3];flag=3;break;
case 0xe7:P2=table2[0];P0=table[4];flag=4;break;
case 0xde: break;
case 0xdd: break;
case 0xdb: break;
case 0xd7: break;
case 0xbe: break;
case 0xbd: break;
case 0xbb: break;
case 0xb7: break;
case 0x7e: break;
case 0x7d: break;
case 0x7b: break;
case 0x77: break;
default: break;
}
}
void main(void)
{
unsigned char k, i;
TMOD = 0x01; //置T0定时工作方式1
IT0=1;
EA = 1;
EX0=1; //开CPU中断
ET0 = 1; //开T0中断
P1=0X0F;
P0=0XFF;
P3_2=1 ;
while(1)
{
// key_scan();
// key_tran();
i = 0;
time = 1;
/***************key1控制第一首歌《世上只有妈妈好》********************/
if(flag==1&flag2==1)
{
delay_5ms();
if(flag==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(); //发出一个音符 控制音调
}
while(flag==1);
}
}
/***************key2控制第二首歌《乡间小路》*****************************/
if(flag==2&flag2==2)
{
delay_5ms();
if(flag==2)
{ while(time)
{
k = xjxl[i] + 7 * xjxl[i + 1] - 1; //第i个是音符, 第i+1个是第几个八度
timer0h = FREQH[k]; //从数据表中读出频率数值
timer0l = FREQL[k]; //实际上, 是定时的时间长度
time = xjxl[i + 2]; //读出时间长度数值
i += 3;
song(); //发出一个音符
}
while(flag==2);
}
}
/***************key2控制第三首歌《送别》******************************/
if(flag==3&flag2==3)
{
delay_5ms();
if(flag==3)
{ while(time)
{
k = songbie[i] + 7 * songbie[i + 1] - 1; //第i个是音符, 第i+1个是第几个八度
timer0h = FREQH[k]; //从数据表中读出频率数值
timer0l = FREQL[k]; //实际上, 是定时的时间长度
time = songbie[i + 2]; //读出时间长度数值
i += 3;
song(); //发出一个音符
}
while(flag==3);
}
}
/***************key2控制第四首歌《一辈子的孤单》******************************/
if(flag==4&flag2==4)
{
delay_5ms();
if(flag==4)
{ while(time)
{
k = ybzdgd[i] + 7 * ybzdgd[i + 1] - 1; //第i个是音符, 第i+1个是第几个八度
timer0h = FREQH[k]; //从数据表中读出频率数值
timer0l = FREQL[k]; //实际上, 是定时的时间长度
time = ybzdgd[i + 2]; //读出时间长度数值
i += 3;
song(); //发出一个音符
}
while(flag==4);
}
}
}
}
/*************************中断程序******************************************/
void zd() interrupt 0
{
lag2++;
if(flag2>4)
{
flag2=0;
}
TR0=0;
EX0=0;
key_scan();
key_tran();
P1=0X0F; //P1中断之后一定要赋初值每个地方都要赋0X0F
EX0=1;
TR0=1;
}
19
展开阅读全文