摘 要
单片机技术是一门不可或缺的技术,对我们将来的工作以及生活和学习都有很密切的联系。近年来,随着电子技术和微机计算机的迅速发展,单片机的档次不断提高,其应用领域也在不断的扩大,已在工业控制、尖端科学、智能仪器仪表、日用家电、汽车电子系统、办公自动化设备、个人信息终端及通信产品中得到了广泛的应用,成为现代电子系统中最重要的智能化的核心部件。 本设计使用AT89C52芯片,利用P0的8个端口连接8个发光二极管,P1的8个端口连接8个发光二极管,通过P0.0到P0.7的值和P1.0到P1.7的值控制“跑马灯”的亮灭,以达到显示效果。设计的中断程序要对多个按键动作进行响应,灯光变换的花样有15种,用模式按钮切换。按下模式按钮键,程序将按十五种模式切换,每按一次模式按钮键,切换一次跑马灯模式,而加速按钮和减速按钮可以改变闪烁速度;最后一种模式为音乐模式,加速按钮可切换音乐。
在单片机运行时,可以在不同状态下让跑马灯显示不同的组合,作为单片机系统正常的指示。当单片机系统出现故障时,可以利用跑马灯显示当前的故障码,对故障做出诊断。此外,跑马灯在单片机的调试过程中也非常有用,可以在不同时候将需要的寄存器或关键变量的值显示在跑马灯上,提供需要的调试信息。
关键词:音乐跑马灯;AT89C52单片机;74LS245驱动芯片;LED发光二极管
1 设计概述 ............................................................................................................................. 1
1.1设计目的 ................................................................................................................... 1 1.2设计作用 ................................................................................................................... 1 1.3设计要求 ................................................................................................................... 1 1.4系统设计框图 ........................................................................................................... 1 2元器件介绍 .......................................................................................................................... 3
2.1AT89C52单片机 ....................................................................................................... 3 2.2驱动芯片74LS245 ................................................................................................... 3 2.3其他元件及功能 ....................................................................................................... 4 3 硬件电路设计 ..................................................................................................................... 6
3.1单片机最小系统 ....................................................................................................... 6 3.2LED显示部分 ........................................................................................................... 7 3.3按钮控制部分 ........................................................................................................... 7 3.4数码管显示电路 ....................................................................................................... 8 3.5蜂鸣器部分 ............................................................................................................... 8
3.6系统总电路图 ........................................................................................................... 9
4 软件设计 ........................................................................................................................... 10
4.1 程序流程图 ............................................................................................................ 10 4.2 程序设计 ................................................................................................................ 10 5 结束语 ............................................................................................................................... 32 参考文献 ............................................................................................................................... 33
1 设计概述
1.1设计目的
利用所学单片机的理论知识进行软硬件整体设计,培养学生分析、解决问题的能力,锻炼学生理论联系实际、综合应用的能力。通过实践动手制作硬件和软件,综合应用本学期所学的单片机知识,达到加深学习该专业知识的目的。
1.2设计作用
跑马灯是一种能像马儿一样跑的灯,就是利用单片机控制LED灯的闪烁方式使其就像马儿奔跑时马蹄的起落。音乐跑马灯,就是在普通跑马灯的基础上加入了音乐,并通过喇叭将其在适当的时刻播放出来。
单片机的音乐跑马灯由16个LED发光二极管组成,在单片机系统中一般用来指示和显示单片机的运行状态。通过程序控制使得单片机不同状态下的16个LED发光二级管显示不同的组合,以此显示单片机的工作状态,也可检查单片机是否发生故障。当然,在实际生活中音乐跑马灯还有许多用处,其可以应用于各种建筑物、大楼、酒吧、KTV和夜总会等娱乐场所,可以制作出各种各样的炫目多彩的霓虹灯,为夜晚带来不一样的光彩。
1.3设计要求
⑴有16个发光二极管做跑马灯,其中跑马灯有16种灯亮模式。
⑵有专门的键盘用以切换跑马灯的模式,并且对于任何一种跑马灯模式都可以对亮灯速度进行控制。
⑶每一种跑马灯模式用LED数码管进行显示。
⑷当跑马灯处于一种模式时,伴随的音乐响起,音乐有3首,并可以对其进行切换。
1.4系统设计框图
基于AT89C52单片机的多模式带音乐的跑马灯控制系统由电路电源、单片机主控电路、模式切换以及调速按键控制电路、LED数码管显示电路和十六个发光二极管的跑马的电路几部分组成,系统框图如图1.1所示。
1
图1.1系统设计框图
电源电路LED数码管显示电路复位电路AT89S52单片机晶振电路16个发光二极管做跑马灯模式切换按键以及速度调节按键
2
2元器件介绍
2.1AT89C52单片机
AT89C52是51系列单片机的一个型号,它是ATMEL公司生产的。
AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的AT89C52单片机可为您提供许多较复杂系统控制应用场合。
AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,AT89C52可以按照常规方法进行编程,也可以在线编程。其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。AT89C52单片机如图2.1所示。
图2.1 AT89C52单片机
2.2驱动芯片74LS245
74LS245是我们常用的芯片,用来驱动LED或者其他的设备,它是8路同相三态双向总线收发器,可双向传输数据。
74LS245还具有双向三态功能,既可以输出,也可以输入数据。
3
当AT89C52单片机的P0口总线负载达到或超过P0最大负载能力时,必须接入74LS245等总线驱动器。 当片选端CE低电平有效时,BA=“0”,信号由 B 向 A 传输;AB=“1”,信号由 A 向 B 传输;(发送)当CE为高电平时,A、B均为高阻态。 由于P2口始终输出地址的高8位,接口时74LS245的三态控制端1G和2G接地,P2口与驱动器输入线对应相连。P0口与74LS245输入端相连, CE端接地,保证数据线畅通。8051的RD和PSEN相与后接AB/BA,使得RD和PSEN有效时,74LS245输入(P0.1←D1),其它时间处于输出(P0.1→D1)。74LS245驱动芯片如图2.2所示。 图2.2 74LS245驱动芯片
2.3其他元件及功能
⑴ LED发光二极管:指示和显单片机状态。 ⑵ 扬声器:播放歌曲。
⑶ 按钮:模式按钮用于切换单片机工作模式,加速按钮用于加快LED灯的闪烁频率,减速按钮用于减缓LED灯的闪烁频率,复位按钮用于人工复位。 ⑷ 数码管:用于显示单片机当前处于何种模式。 ⑸ 晶体振荡器:用于构成单片机的复位电路。 ⑹ 电容:用于构成单片机的复位电路。
⑺ 电阻:限流分压作用,是电路正常工作并保护电路。
4
元件清单如表2.1所示。
表2.1 元件清单
元 件 AT89C52 74LS245 LED发光二极管 扬声器 按钮 数码管 晶体振荡器 电容30pF 数 量 1 3 16 1 4 1 1 2 元 件 电容20µF 电阻470Ω 电阻100Ω 电阻480Ω 电源+5V 数 量 1 16 7 1 8
5
3 硬件电路设计
3.1单片机最小系统
单片机最小系统或者称为最小应用系统,素质用最少的元件组成的单片机可以工作的系统,对51系列单片机来说,最小系统一般应该包括:单片机、复位电路、晶振电路。
复位电路:该复位电路采用手动复位和按键复位,所谓手动复位,是指通过接通一按钮开关,使单片机进入复位状态,使RST获得高电平,该方法可实现比较快速的复位。当然,若不按下按钮,需等待电容充完电后使得RST获得高电平复位,复位电路如图3.1所示。
图3.1复位电路
晶振电路:8051单片机的时钟信号通常用两种电路形式电路得到:内部震荡方式和外部中断方式。在引脚XTAL1和XTAL2外部接晶振电路器(简称晶振)或陶瓷晶振器,就构成了内部晶振方式。由于单片机内部有一个高增益反相放大器,当外接晶振后,就构成了自激振荡器并产生振荡时钟脉冲。内部振荡方式的外部电路如下图所示。其电容值一般在5~30pF,晶振频率的典型值为12MHz,采用6MHz的情况也比较多。内部振荡方式所得的时钟信号比较稳定,实用电路使用较多。晶振电路图如图3.2所示。
6
图3.2 晶振电路
3.2LED显示部分
显示部分,用十六个发光二极管通过总线和74LS245驱动芯片分别接到了AT89C52单片机的P0和P1口。通过程序控制P0和P1的十六个端口按一定方式一次为低电平点亮端口LED。若把P0口当作了通用的I/O口,则需要加上拉电阻,可是我们所采用的是使用总线方式输出因此不需要上拉电阻。本设计采用的是发光二极管阳极接电源,因此要求P0口P1口输出低电平时,二极管才会发光。LED显示部分如图3.3所示。
图3.3 LED显示部分
3.3按钮控制部分
用一个按钮进行模式的切换,即用该按钮控制多种不同的亮灯模式,分别有16种模式,从模式“0”至模式“F”,开启模式“F”是有音乐放出。用一个按钮(加速按钮)进行发光二极管亮灯加速的调节,在第“F”模式时该按钮则可进行歌曲的切换。用一个按钮(减速按钮)进行发光二极管亮灯减速的调节,在第9模式时该按钮则可进行歌曲的切换。按钮控制部分如图3.4所示。
7
图按
控制部分
3.4 钮
3.4数码管显示电路
数码管上分别显示0~F十六个数字,分别代表十六种模式。采用共阳极连接,即数码管的a~f端要输入低电平时内部二极管才导通。在数码管每个端口与74LS24 5驱动芯片与数码管之间连上100Ω的电阻。数码管显示电路的具体硬件设计如图3.5所示。
图3.5 数码管显示电路
3.5蜂鸣器部分
蜂鸣器是一种将电信号转换成声音信号的电声元件。确切的说,蜂鸣器工作实际上是把一定范围内的音频电功率讯号通过换能方式转变失真小并且有足够声压级的可听声音。本课程设计直接将蜂鸣器街道单片机的P2.6端口,蜂鸣器具体电路如图3.6所示。
8
图3.6 蜂鸣器电路
3.6系统总电路图
音乐跑马灯的总电路图如3.7所示。
图3.7 音乐跑马灯总电路
3.7操作说明
在仿真软件中,按下屏幕左下角开始按键时,数码管显示为“0”,发光二极管以一定方式开始闪烁,此时按下模式按钮使得数码管显示为“1”时,发光二极管以一另种方式开始闪烁。此时,若按加速按钮,则加快了发光二极管的闪烁速度,有4种不同的速度。当加速到最大速度时,再按加速按钮则无法继续加速,此时可以按减速按钮进行减速。以此类推,模式“1”到模式“E”,每种模式都给有一种闪烁方式。当继续按模式按钮使的模式转换为模式“F”时,蜂鸣器开始放歌,发光二极管按照音乐音调变动闪烁。此时的加速按钮可以进行歌曲的切换,按一次按钮换一首歌。
9
4 软件设计
4.1 程序流程图
该程序采用两个程序编写:第一个位单片机主程序,作用是使单片机完成相应上电功能;第二个是音乐产生程序,在第一个程序中包含第二个程序的头文件即可。程序流程图如图4.1及4.2所示。
图4.1 主程序 开始I/O初始化模式键被按下NY模式加1,等于9YN送LED和跑马灯播放音乐结束
4.2 程序设计
#include //#include void Delay1ms(unsigned int Count) { unsigned int i,j; 图4.2 音乐程序流程图 设定跑马灯初值检查按键开关Y加速键被按下?减少时间,使跑马灯加速N减速键被按下?Y增加时间,使跑马灯减速NLED跑马灯//包括一个52标准的内核头文件 //延时子程序 1 0 for(i=0;i 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff}; //LED数码管 void Display(unsigned char Value) { P3=LEDDisplayCode [Value]; } void LEDFlash(unsigned char Count) { unsigned char i; bit Flag; for(i=0;i Display(RunMode); else Display(0x10); Delay1ms(100); } Display(RunMode); } unsigned char GetKey(void) { unsigned char KeyTemp,CheckValue,Key=0x00; CheckValue=P2&0x32; 1 1 //数值输出至LED //判断按键是否按下 if(CheckValue==0x32) return 0x00; Delay1ms(10); //调用延时 KeyTemp=P2&0x32; if(KeyTemp==CheckValue) return 0x00; if(!(CheckValue&0x02)) Key|=0x01; if(!(CheckValue&0x10)) Key|=0x02; if(!(CheckValue&0x20)) Key|=0x04; return Key; } unsigned int Timer0Count,SystemSpeed,SystemSpeedIndex; void InitialTimer2(void) { T2CON=0x00; TH2=RCAP2H=0xfc; ET2=1; TR2=1; EA=1; } unsigned int code SpeedCode[]={1,100,500,1000}; void SetSpeed(unsigned char Speed) { SystemSpeed=SpeedCode[Speed]; } void LEDShow(unsigned int LEDStatus) { P1=~(LEDStatus&0x00ff); P0=~((LEDStatus>>8)&0x00ff); } 12 //定时器2中断允许 //定时器2启动 //跑马灯速度控制 //跑马灯的输出 void InitialCPU(void) { RunMode=0x00; Timer0Count=0; SystemSpeedIndex=4; P1=0x00; P0=0x00; P2=0xff; P3=0x00; Delay1ms(500); P1=0xff; P0=0xff; P2=0xff; P3=0xff; SetSpeed(SystemSpeedIndex); Display(RunMode); } unsigned int LEDIndex=0; bit LEDDirection=1,LEDFlag=1; void Mode_0(void) { LEDShow(0x0001< LEDShow(0x8000>>LEDIndex); LEDIndex=(LEDIndex+1)%16; } 1 3 void Mode_2(void) { if(LEDDirection) LEDShow(0x0001< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%16; } void Mode_3(void) { if(LEDDirection) LEDShow(~(0x0001< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%16; } void Mode_4(void) { if(LEDDirection) { if(LEDFlag) LEDShow(0xfffe< 1 4 else { if(LEDFlag) LEDShow(0x7fff>>LEDIndex); else LEDShow(~(0xfffe< LEDDirection=!LEDDirection; if(LEDDirection) LEDFlag=!LEDFlag; } LEDIndex=(LEDIndex+1)%16; } void Mode_5(void) { if(LEDDirection) LEDShow(0x000f< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%16; } void Mode_6(void) { if(LEDDirection) LEDShow(~(0x000f< else LEDShow(~(0xf000>>LEDIndex)); if(LEDIndex==15) LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%16; } void Mode_7(void) { if(LEDDirection) LEDShow(0x003f< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%10; } void Mode_8(void) { LEDShow(++LEDIndex); } void Mode_9(void) { LEDShow(0x0003< LEDShow(0xc000>>LEDIndex); LEDIndex=(LEDIndex+1)%16; 1 6 } void Mode_b(void) { if(LEDDirection) LEDShow(0x0003< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%16; } void Mode_C(void) { if(LEDDirection) LEDShow(0x8080>>LEDIndex); else LEDShow(0x0101< void Mode_d(void) { if(LEDDirection) LEDShow(0x1111< LEDDirection=!LEDDirection; 1 7 LEDIndex=(LEDIndex+1)%4; } void Mode_E(void) { if(LEDDirection) LEDShow(0x5555< LEDDirection=!LEDDirection; LEDIndex=(LEDIndex+1)%4; } void timer0eventrun(void) { if(RunMode==0x00) {Mode_0();} else if(RunMode==0x01) {Mode_1();} else if(RunMode==0x02) {Mode_2();} else if(RunMode==0x03) {Mode_3();} else if(RunMode==0x04) {Mode_4();} else if(RunMode==0x05) {Mode_5();} else if(RunMode==0x06) {Mode_6();} else if(RunMode==0x07) {Mode_7();} else if(RunMode==0x08) {Mode_8();} else if(RunMode==0x09) {Mode_9();} else if(RunMode==0x0a) {Mode_A();} //模式选择 else if(RunMode==0x0b) {Mode_b();} else if(RunMode==0x0c) {Mode_C();} else if(RunMode==0x0d) {Mode_d();} else if(RunMode==0x0e) {Mode_E();} 18 } void Timer2(void) interrupt 5 using 3 { TF2=0; if(++Timer0Count>=SystemSpeed) { Timer0Count=0; timer0eventrun(); } } unsigned char MusicIndex=0; int MUSICNUMBER=3; void KeyDispose(unsigned char Key) { if(Key&0x01) { LEDDirection=1; LEDIndex=0; LEDFlag=1; RunMode=(RunMode+1)%16; Display(RunMode); if(RunMode==0x0f) TR2=0; else TR2=1; } if(Key&0x02) { if(RunMode==0x0f) 1 9 {MusicIndex=(MusicIndex+MUSICNUMBER-1)%MUSICNUMBER;} else { if(SystemSpeedIndex>0) { --SystemSpeedIndex; SetSpeed(SystemSpeedIndex); } else {LEDFlash(6);} } } if(Key&0x04) { if(RunMode==0x0f) {MusicIndex=(MUSICNUMBER+1)%MUSICNUMBER;} else { if(SystemSpeedIndex<3) { ++SystemSpeedIndex; SetSpeed(SystemSpeedIndex); } else {LEDFlash(6);} } } } unsigned char code Music_1[]={ 20 0x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x15,0x03, 0x16,0x03,0x17,0x03,0x17,0x03,0x17,0x03,0x18,0x03, 0x19,0x02,0x16,0x03,0x17,0x03,0x18,0x02,0x18,0x03, 0x17,0x03,0x15,0x02,0x18,0x03,0x17,0x03,0x18,0x02, 0x10,0x03,0x15,0x03,0x16,0x02,0x15,0x03,0x16,0x03, 0x17,0x02,0x17,0x03,0x18,0x03,0x19,0x02,0x1a,0x03, 0x1b,0x03,0x1f,0x03,0x1f,0x03,0x17,0x03,0x18,0x03, 0x19,0x02,0x16,0x03,0x17,0x03,0x18,0x03,0x17,0x03, 0x18,0x03,0x1f,0x03,0x1f,0x02,0x16,0x03,0x17,0x03, 0x18,0x03,0x17,0x03,0x18,0x03,0x20,0x03,0x20,0x02, 0x1f,0x03,0x1b,0x03,0x1f,0x66,0x20,0x03,0x21,0x03, 0x20,0x03,0x1f,0x03,0x1b,0x03,0x1f,0x66,0x1f,0x03, 0x1b,0x03,0x19,0x03,0x1b,0x03,0x15,0x03,0x1a,0x66, 0x1a,0x03,0x19,0x03,0x15,0x03,0x15,0x03,0x17,0x03, 0x16,0x66,0x17,0x04,0x18,0x04,0x18,0x03,0x19,0x03, 0x1f,0x03,0x1b,0x03,0x1f,0x66,0x20,0x03,0x21,0x03, 0x20,0x03,0x1f,0x03,0x1b,0x03,0x1f,0x66,0x1f,0x03, 0x1b,0x03,0x19,0x03,0x19,0x03,0x15,0x03,0x1a,0x66, 0x1a,0x03,0x19,0x03,0x19,0x03,0x1f,0x03,0x1b,0x03, 0x1f,0x00,0x1a,0x03,0x1a,0x03,0x1a,0x03,0x1b,0x03, 0x1b,0x03,0x1a,0x03,0x19,0x03,0x19,0x02,0x17,0x03, 0x15,0x17,0x15,0x03,0x16,0x03,0x17,0x03,0x18,0x03, 0x17,0x04,0x18,0x0e,0x18,0x03,0x17,0x04,0x18,0x0e, 0x18,0x66,0x17,0x03,0x18,0x03,0x17,0x03,0x18,0x03, 0x20,0x03,0x20,0x02,0x1f,0x03,0x1b,0x03,0x1f,0x66, 0x20,0x03,0x21,0x03,0x20,0x03,0x1f,0x03,0x1b,0x03, 0x1f,0x66,0x1f,0x04,0x1b,0x0e,0x1b,0x03,0x19,0x03, 0x19,0x03,0x15,0x03,0x1a,0x66,0x1a,0x03,0x19,0x03, 0x15,0x03,0x15,0x03,0x17,0x03,0x16,0x66,0x17,0x04, 21 0x18,0x04,0x18,0x03,0x19,0x03,0x1f,0x03,0x1b,0x03, 0x1f,0x66,0x20,0x03,0x21,0x03,0x20,0x03,0x1f,0x03, 0x1b,0x03,0x1f,0x66,0x1f,0x03,0x1b,0x03,0x19,0x03, 0x19,0x03,0x15,0x03,0x1a,0x66,0x1a,0x03,0x19,0x03, 0x19,0x03,0x1f,0x03,0x1b,0x03,0x1f,0x00,0x18,0x02, 0x18,0x03,0x1a,0x03,0x19,0x0d,0x15,0x03,0x15,0x02, 0x18,0x66,0x16,0x02,0x17,0x02,0x15,0x00,0x00,0x03}; unsigned char code Music_2[]={ 0x0f,0x01,0x15,0x02,0x16,0x02,0x17,0x66,0x18,0x03, 0x17,0x02,0x15,0x02,0x16,0x01,0x15,0x02,0x10,0x02, 0x15,0x00,0x0f,0x01,0x15,0x02,0x16,0x02,0x17,0x02, 0x17,0x03,0x18,0x03,0x19,0x02,0x15,0x02,0x18,0x66, 0x17,0x03,0x19,0x02,0x16,0x03,0x17,0x03,0x16,0x00, 0x17,0x01,0x19,0x22,0x1b,0x02,0x1b,0x70,0x1a,0x03, 0x1a,0x01,0x19,0x02,0x19,0x03,0x1a,0x03,0x1b,0x02, 0x1a,0x0d,0x19,0x03,0x17,0x00,0x18,0x66,0x18,0x03, 0x19,0x02,0x1a,0x03,0x19,0x0c,0x18,0x0d,0x17,0x03, 0x16,0x01,0x11,0x02,0x11,0x03,0x10,0x03,0x0f,0x0c, 0x10,0x02,0x15,0x00,0x1f,0x01,0x1a,0x01,0x18,0x66, 0x19,0x03,0x1a,0x01,0x1b,0x02,0x1b,0x03,0x1b,0x03, 0x1b,0x0c,0x1a,0x0d,0x19,0x03,0x17,0x00,0x1f,0x01, 0x1a,0x01,0x18,0x66,0x19,0x33,0x1a,0x01,0x10,0x02, 0x10,0x03,0x10,0x03,0x1a,0x0c,0x18,0x0d,0x17,0x03, 0x16,0x00,0x0f,0x01,0x15,0x02,0x16,0x02,0x17,0x70, 0x18,0x03,0x17,0x02,0x15,0x03,0x15,0x03,0x16,0x66, 0x16,0x03,0x16,0x02,0x16,0x03,0x15,0x03,0x10,0x02, 0x10,0x01,0x11,0x01,0x11,0x66,0x10,0x03,0x0f,0x0c, 0x1a,0x02,0x19,0x02,0x16,0x03,0x16,0x03,0x18,0x66, 0x18,0x03,0x18,0x02,0x17,0x03,0x16,0x03,0x19,0x00, 22 0x00,0x00}; unsigned char code Music_3[]={ 0x17,0x03,0x16,0x03,0x17,0x01,0x16,0x03,0x17,0x03, 0x16,0x03,0x15,0x01,0x10,0x03,0x15,0x03,0x16,0x02, 0x16,0x0d,0x17,0x03,0x16,0x03,0x15,0x03,0x10,0x03, 0x10,0x0e,0x15,0x04,0x0f,0x01,0x17,0x03,0x16,0x03, 0x17,0x01,0x16,0x03,0x17,0x03,0x16,0x03,0x15,0x01, 0x10,0x03,0x15,0x03,0x16,0x02,0x16,0x0d,0x17,0x03, 0x16,0x03,0x15,0x03,0x10,0x03,0x15,0x03,0x16,0x01, 0x17,0x03,0x16,0x03,0x17,0x01,0x16,0x03,0x17,0x03, 0x16,0x03,0x15,0x01,0x10,0x03,0x15,0x03,0x16,0x02, 0x16,0x0d,0x17,0x03,0x16,0x03,0x15,0x03,0x10,0x03, 0x10,0x0e,0x15,0x04,0x0f,0x01,0x17,0x03,0x19,0x03, 0x19,0x01,0x19,0x03,0x1a,0x03,0x19,0x03,0x17,0x01, 0x16,0x03,0x16,0x03,0x16,0x02,0x16,0x0d,0x17,0x03, 0x16,0x03,0x15,0x03,0x10,0x03,0x10,0x0d,0x15,0x00, 0x19,0x03,0x19,0x03,0x1a,0x03,0x1f,0x03,0x1b,0x03, 0x1b,0x03,0x1a,0x03,0x17,0x0d,0x16,0x03,0x16,0x03, 0x16,0x0d,0x17,0x01,0x17,0x03,0x17,0x03,0x19,0x03, 0x1a,0x02,0x1a,0x02,0x10,0x03,0x17,0x0d,0x16,0x03, 0x16,0x01,0x17,0x03,0x19,0x03,0x19,0x03,0x17,0x03, 0x19,0x02,0x1f,0x02,0x1b,0x03,0x1a,0x03,0x1a,0x0e, 0x1b,0x04,0x17,0x02,0x1a,0x03,0x1a,0x03,0x1a,0x0e, 0x1b,0x04,0x1a,0x03,0x19,0x03,0x17,0x03,0x16,0x03, 0x17,0x0d,0x16,0x03,0x17,0x03,0x19,0x01,0x19,0x03, 0x19,0x03,0x1a,0x03,0x1f,0x03,0x1b,0x03,0x1b,0x03, 0x1a,0x03,0x17,0x0d,0x16,0x03,0x16,0x03,0x16,0x03, 0x17,0x01,0x17,0x03,0x17,0x03,0x19,0x03,0x1a,0x02, 0x1a,0x02,0x10,0x03,0x17,0x0d,0x16,0x03,0x16,0x01, 23 0x17,0x03,0x19,0x03,0x19,0x03,0x17,0x03,0x19,0x03, 0x1f,0x02,0x1b,0x03,0x1a,0x03,0x1a,0x0e,0x1b,0x04, 0x17,0x02,0x1a,0x03,0x1a,0x03,0x1a,0x0e,0x1b,0x04, 0x17,0x16,0x1a,0x03,0x1a,0x03,0x1a,0x0e,0x1b,0x04, 0x1a,0x03,0x19,0x03,0x17,0x03,0x16,0x03,0x0f,0x02, 0x10,0x03,0x15,0x00,0x00,0x00}; unsigned char * SelectMusic(unsigned char SoundIndex) { unsigned char * MusicAddress=0; switch(SoundIndex) { case 0x00:MusicAddress=&Music_1[0];break; case 0x01:MusicAddress=&Music_2[0];break; case 0x02:MusicAddress=&Music_3[0];break; case 0x03:break; case 0x04:break; case 0x05:break; default:break; } return MusicAddress; } #ifndef __SOUNDPLAY_H_REVISION_FIRST__ #define __SOUNDPLAY_H_REVISION_FIRST__ #define SYSTEM_OSC 12000000 #define SOUND_SPACE 4/5 //定义普通音符演奏长度分率,每四分音符间隔 #define MUSICNUMBER 3 sbit BeepIO=P2^6; //歌曲的数目 //定义输出引脚 //定义晶振频率 extern void LEDShow(unsigned int LEDStatus); 24 extern unsigned char GetKey(void); extern void KeyDispose(unsigned char Key); extern void Delay1ms(unsigned int count); extern unsigned char MusicIndex; unsigned int code FreTab[12]= {262,277,294,311,330,349,369,392,415,440,466,494}; //原始频率表 unsigned char code SignTab[7]= {0,2,4,5,7,9,11}; //1~7在频率表中的位置 unsigned char code LengthTab[7]= {1,2,4,8,16,32,64}; unsigned char Sound_Temp_TH0,Sound_Temp_TL0; //音符定时器初值暂存 unsigned char Sound_Temp_TH1,Sound_Temp_TL1; //音长定时器初值暂存 void InitialSound(void) { BeepIO=0; Sound_Temp_TH1=(65535-(1/1200)*SYSTEM_OSC)/256; //计算TL1应装入的初值 Sound_Temp_TL1=(65535-(1/1200)*SYSTEM_OSC)%256; //计算TH1应装入的初值 TH1=Sound_Temp_TH1; TL1=Sound_Temp_TL1; TMOD|=0x11; ET0=1; ET1=0; TR0=0; TR1=0; EA=1; } void BeepTimer0(void) interrupt 1 //音符发生中断 25 { BeepIO=!BeepIO; TH0=Sound_Temp_TH0; TL0=Sound_Temp_TL0; } void Play(unsigned char *Sound,unsigned char Signature,unsigned int Octachord,unsigned int Speed) { unsigned int NewFreTab[12]; //新的频率表 unsigned char i,j; unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength; unsigned char TONE,Length,SL,SH,SM,SLen,XG,FD,Key,LEDFlash,OFFSet; for(i=0;i<12;i++) { j=i+Signature; if(j>11) { j=j-12; NewFreTab[i]=FreTab[j]*2; } else NewFreTab[i]=FreTab[j]; if(Octachord==1) NewFreTab[i]>>=2; else if(Octachord==3) NewFreTab[i]<<=2; } SoundLength=0; while(Sound[SoundLength]!=0x00) //根据调号及升降8度来生成新的频率表 26 //计算歌曲长度 { SoundLength+=2; } Point=0; TONE=Sound[Point]; Length=Sound[Point+1]; LDiv0=12000/Speed; LDiv4=LDiv0/4; //读出第一个音符和它的时值 //算出1分音符的长度 //算出4分音符的长度 //普通音最长间隔标准 LDiv4=LDiv4-LDiv4*SOUND_SPACE; TR0=0; TR1=1; while(Point //计算出音符 //计算出高低音 //计算是否升半 SM=TONE/10%10; SH=TONE/100; LEDFlash=SM*((SL/2)+1)+2; LEDShow(~(0xFFFE< if(SM==1)CurrentFre>>=2; if(SM==3)CurrentFre<<=2; //低音 //高音 Temp_T=65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC); //计算计数器初值 Sound_Temp_TH0=Temp_T/256; Sound_Temp_TL0=Temp_T%256; TH0=Sound_Temp_TH0; 27 TL0=Sound_Temp_TL0+6; } //对中断延时补偿 SLen=LengthTab[Length%10]; XG=Length/10%10; FD=Length/100; LDiv=LDiv0/SLen; if(FD==1) LDiv=LDiv+LDiv/2; if(XG!=1) if(XG==0) if(SLen<=4) LDiv1=LDiv-LDiv4; else //算出是几分音符 //算出音符类型 //算出连音音符演奏的长度 //算出普通音符演奏的长度 LDiv1=LDiv*SOUND_SPACE; else LDiv1=LDiv/2; else LDiv1=LDiv; if(SL==0) {LDiv1=0;LDiv2=LDiv-LDiv1;} if(SL!=0) { TR0=1; for(i=LDiv1;i>0;i--) { OFFSet=(OFFSet+1)%5; LEDShow(~(0xFFFE<<(LEDFlash+OFFSet-2))); while(TF1==0) { 28 //算出顿音的演奏长度 //算出不发音的长度 //发规定长度的音 Key=GetKey(); if(Key!=0x00) { KeyDispose(Key); TR0=0; TR1=0; BeepIO=0; return; } } TH1=Sound_Temp_TH1; TL1=Sound_Temp_TL1; TF1=0; } } if(LDiv2!=0) { TR0=0;BeepIO=0; for(i=LDiv2;i>0;i--) { OFFSet=(OFFSet+1)%5; LEDShow(~(0xFFFE<<(LEDFlash+OFFSet-2))); while(TF1==0) { Key=GetKey(); if(Key!=0x00) { KeyDispose(Key); TR0=0; 29 //音符间的间隔 TR1=0; BeepIO=0; return; } } TH1=Sound_Temp_TH1; TL1=Sound_Temp_TL1; TF1=0; } } Point+=2; TONE=Sound[Point]; Length=Sound[Point+1]; } BeepIO=0; MusicIndex=(MusicIndex+1)%MUSICNUMBER; LEDShow(0x0001); Delay1ms(300); } void PlayMusic(void) { Delay1ms(200); Play(SelectMusic(MusicIndex),0,3,360); } void main() { unsigned char Key; InitialCPU(); 30 InitialSound(); InitialTimer2(); while(1) { Key=GetKey(); if(RunMode==0x0f) {PlayMusic();} if(Key!=0x00) {KeyDispose(Key);} } } #endif 3 1 5 结束语 通过单片机课程设计,我不仅加深了对单片机理论的理解,将理论很好地应用到实际当中去,而且我还学会了如何去培养我们的创新精神,从而不断地战胜自己,超越自己。创新,是要我们学会将理论很好地联系实际,并不断地去开动自己的大脑,从为人类造福的意愿出发,做自己力所能及的,别人却没想到的事。使之不断地战胜别人,超越前人。同时,更重要的是,我在这一设计过程中,学会了坚持不懈,不轻易言弃。设计过程,也好比是我们人类成长的历程,常有一些不如意,也许这就是在对我们提出了挑战,勇敢过,也战胜了,胜利的钟声也就一定会为我们而敲响。 本人深知自己做的工作还很不够,由于软件和硬件的各方面原因,系统的应用讨论不够,精度还有待于进一步提高。由于时间的原因,设备的原因,实验做的不好不够,相关验证性的数据、信息不够丰富。可以肯定,随着技术的不断发展,步进电机的控制应用前景将越来越宽阔,而其控制系统也将向着智能化和网络化的方向发展。本论文的研究和探讨还远远不够,我们要在现在的基础上,不断吸取新的技术和方法,并将它们应用于本课题的研究上来,进一步深化我们的研究深度,争取有更多的收获。 32 参考文献 [1] 李泉溪.单片机原理与应用实例仿真[M].北京:北京航空航天大学出版社,2006. [2] 杨欣,王玉凤,刘湘黔.51单片机应用从零开始[M].北京:清华大学出版社,2008. [3] 潘新民,王燕芳.微型计算机控制技术[M].北京:电子工业出版社,2000. [4] 杨居义.单片机课程设计指导[M].北京:清华大学出版社,2008. [5] 雷伏容,张小林,崔浩.51单片机常用模块设计查询手册[M].北京:清华大学出版社,2003. 33 因篇幅问题不能全部显示,请点此查看更多更全内容