您现在的位置:首页 > >

基于AT89S51的电子琴设计报告_图文


一实训目的 通过本课程的实训,旨在使学生在掌握先修课程的基础上,一方面能综合应用 这些课程的理论知识,更重要的一方面,是让学生亲自动手,参与到工程实践训 练中。使学生在之前掌握的电路.模电.数电等知识,以及单片机知识的基础上, 进一步掌握电子产品设计以及开发调试的全过程,尤其包括掌握 PCB 板的设计. 印刷,元器件的安装.电路调试.程序调试.程序下载等实践实训部分,真正培养学 生理论联系实际.分析解决一般性技术问题以及实际动手的能力。 二.设计原理 电子琴由以下几个部件组成:单片机 89S51、电源、4*4 的 16 个按钮矩阵、 音频放大模块、复位模块,数码管,LED 显示模块、晶振模块。 (1)AT89S51 单片机及其引脚说明 AT89S51 是一个低功耗,高性能 CMOS 8 位单片机,片内含 4k Bytes ISP(In-system programmable)的可反复擦写 1000 次的 Flash 只读程序存储器, 器件采用 ATMEL 公司的高密度、非易失性存储技术制造,兼容标准 MCS-51 指令 系统及 80C51 引脚结构,芯片内集成了通用 8 位中央处理器和 ISP Flash 存储单 元,功能强大的微型计算机的 AT89S51

1.主要特性: · 8031 CPU 与 MCS-51 兼容 · 4K 字节可编程 FLASH 存储器(寿命:1000 写/擦循环) · 全静态工作:0Hz-24KH· 三级程序存储器保密锁定 · 128*8 位内部 RAM · 32 条可编程 I/O 线 · 两个 16 位定时器/计数器 · 6 个中断源 · 可编程串行通道

· 低功耗的闲置和掉电模式 · 片内振荡器和时钟电路 (2)主要管脚说明: 主要管脚说明: 管脚说明 P0 口:P0 口为一个 8 位漏级开路准双向 I/O 口,每脚可吸收 8TTL 门电流。 P0 能够用于外部程序数据存储器, 它可以被定义为数据/地址的第八位。 FIASH 在 编程时,P0 口作为原码输入口,当 FIASH 进行校验时,P0 输出原码,此时 P0 外部必须被拉高。 P1 口:P1 口是一个内部提供上拉电阻的 8 位双向 I/O 口,P1 口缓冲器能接 收输出 4TTL 门电流。P1 口管脚写入 1 后,被内部上拉为高,可用作输入,P1 口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在 FLASH 编程和校验时,P1 口作为第八位地址接收。 P2 口:P2 口为一个内部上拉电阻的 8 位双向 I/O 口,P2 口缓冲器可接收, 输出 4 个 TTL 门电流,当 P2 口被写“1”时,其管脚被内部上拉电阻拉高,且作 为输入。P2 口当用于外部程序存储器或 16 位地址外部数据存储器进行存取时, P2 口输出地址的高八位。 P3 口:P3 口管脚是 8 个带内部上拉电阻的双向 I/O 口,可接收输出 4 个 TTL 门电流。当 P3 口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输 入,由于外部下拉为低电平,P3 口将输出电流(ILL)这是由于上拉的缘故。 P3 口也可作为 AT89C51 的一些特殊功能口,如下表所示: P3 口引脚 P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7 特殊功能 RXD(串行输入口) TXD(串行输出口) (外部中断 0) (外部中断 1) T0(定时器 0 外部输入) T1(定时器 1 外部输入) WR(外部数据存储器写选通) RD(外部数据存储器读先通)

P3 口同时为闪烁编程和编程校验接收一些控制信号。 1.音乐产生的方法 音乐产生的方法 一首音乐是许多不同的音阶组成的,而每个音阶对应着不同的频率,这样我 们就可以利用不同的频率的组合,即可构成我们所想要的音乐了,当然对于单片 机来产生不同的频率非常方便, 我们可以利用单片机的定时/计数器 T0 来产生这 样方波频率信号,因此,我们只要把一首歌曲的音阶对应频率关系弄正确即可。 若要产生音频脉冲,只要算出某一音频的周期(1/频率) ,再将此周期除以 2,即为半周期的时间。利用定时器计时半周期时间,每当计时终止后就将 P0.0 反相,然后重复计时再反相。就可在 P0.0 引脚上得到此频率的脉冲。

利用 AT89S51 的内部定时器使其工作计数器模式(MODE1)下,改变计数值 TH0 及 TL0 以产生不同频率的方法产生不同音阶,例如,频率为 523Hz,其周期 T=1/523=1912μs,因此只要令计数器计时 956μs/1μs=956,每计数 956 次 时将 I/O 反相,就可得到中音 DO(523Hz) 。 计数脉冲值与频率的关系式(如式 2-1 所示)是: N=fi÷2÷fr 2-1 式中,N 是计数值;fi 是机器频率(晶体振荡器为 12MHz 时,其频率为 1MHz) ; fr 是想要产生的频率。 其计数初值 T 的求法如下: T=65536-N=65536-fi÷2÷fr 例如:设 K=65536,fi=1MHz,求低音 DO(261Hz) 、中音 DO(523Hz) 、高 音 DO(1046Hz)的计数值。 T = 65536 - N = 65536 - fi÷2÷fr = 65536 - 1000000÷2÷fr = 65536 - 500000/fr 低音 DO 的 T=65536-500000/262=63627 中音 DO 的 T=65536-500000/523=64580 高音 DO 的 T=65536-500000/1046=65059 单片机 12MHZ 晶振,高中低音符与计数 T0 相关的计数值如表 2-2 所示 表 2-2 音符频率表 音符 频率(HZ) 简谱码 值) (T 音符 频率(HZ) 简谱码 值) (T 低 1 DO 262 63628 # 4 FA# 740 64860 #1 DO# 277 63731 中 5 SO 784 64898 低 2 RE 294 63835 # 5 SO# 831 64934 #2 RE# 311 63928 中 6 LA 880 64968 低 3 M 330 64021 # 6 932 64994 低 4 FA 349 64103 中 7 SI 988 65030 # 4 FA# 370 64185 高 1 DO 1046 65058 低 5 SO 392 64260 # 1 DO# 1109 65085 # 5 SO# 415 64331 高 2 RE 1175 65110 低 6 LA 440 64400 # 2 RE# 1245 65134 # 6 466 64463 高 3 M 1318 65157 低 7 SI 494 64524 高 4 FA 1397 65178 中 1 DO 523 64580 # 4 FA# 1480 65198 # 1 DO# 554 64633 高 5 SO 1568 65217 中 2 RE 587 64684 # 5 SO# 1661 65235 # 2 RE# 622 64732 高 6 LA 1760 65252 中 3 M 659 64777 # 6 1865 65268 中 4 FA 698 64820 高 7 SI 1967 65283 我们要为这个音符建立一个表格, 单片机通过查表的方式来获得相应的数据 低音 0-19 之间,中音在 20-39 之间,高音在 40-59 之间 TABLE: DW 0, 63628, 63835, 64021, 64103, 64260, 64400, 64524, 0, 0 DW 0, 63731, 63928, 0, 64185, 64331, 64463, 0, 0, 0

DW 0, 64580, 64684, 64777, 64820, 64898, 64968, 65030, 0, 0 DW 0, 64633, 64732, 0, 64860, 64934, 64994, 0, 0, 0 DW 0, 65058, 65110,65157, 65178, 65217, 65252, 65283, 0, 0 DW 0, 65085, 65134, 0, 65198, 65235, 65268, 0, 0, 0 DW 0 音乐的音拍,一个节拍为单位(C 调) (如表 2-3 所示) 表 2-3 曲调值表 曲调值 DELAY 曲调值 DELAY 调 4/4 125ms 调 4/4 62ms 调 3/4 187ms 调 3/4 94ms 调 2/4 250ms 调 2/4 125ms 对于不同的曲调我们也可以用单片机的另外一个定时/计数器来完成。 琴键处理程序,根据检测到得按键值,查询音律表,给计时器赋值,发出相应频率的声 音。对音调的控制:根据不同的按键,对定时器 T1 送入不同的初值,调节 T1 的溢出时 间,这样就可以输出不同音调频率的方波。不同音调下各个音阶的定时器。在这个程序 中用到了两个定时/计数器来完成的。其中 T0 用来产生音符频率,T1 用来产生音拍。 2.4X4 2.4X4 行列式键盘识别及显示 组成键盘的按键有机械式、电容式、导电橡胶式、薄膜式多种,但不管什么 形式,其作用都是一个使电路接通与断开的开关。目前微机系统中使用的键盘按 其功能不同,通常可分为编码键盘和非编码键盘两种基本类型。 编码键盘:键盘本身带有实现接口主要功能所需的硬件电路。不仅能自动检 测被按下的键,并完成去抖动、防串键等功能,而且能提供与被按键功能对应的 键码(如 ASCII 码)送往 CPU。所以,编码键盘接口简单、使用方便。但由于硬 件电路较复杂,因而价格较贵。 非编码键盘:键盘只简单地提供按键开关的行列矩阵。有关按键的识别、键 码的确定与输入、去抖动等功能均由软件完成。目前微机系统中,一般为了降低 成本大多数采用非编码键盘。 键盘接口必须具有去抖动、防串键、按键识别和键码产生 4 个基本功能。 (1)去抖动:每个按键在按下或松开时,都会产生短时间的抖动。抖动的持 续时间与键的质量相关,一般为 5—20mm。所谓抖动是指在识别被按键是必须避 开抖动状态,只有处在稳定接通或稳定断开状态才能保证识别正确无误。去抖问 题可通过软件延时或硬件电路解决。 (2)防串键:防串键是为了解决多个键同时按下或者前一按键没有释放又 有新的按键按下时产生的问题。常用的方法有双键锁定和 N 键轮回两种方法。双 键锁定,是当有两个或两个以上的按键按下时,只把最后释放的键当作有效键并 产生相应的键码。N 键轮回,是当检测到有多个键被按下时,能根据发现它们的 顺序依次产生相应键的键码。 (3)被按键识别:如何识别被按键是接口解决的主要问题,一般可通过软 硬结合的方法完成。常用的方法有行扫描法和线反转法两种。行扫描法的基本思 想是,由程序对键盘逐行扫描,通过检测到的列输出状态来确定闭合键,为此, 需要设置入口、输出口一个,该方法在微机系统中被广泛使用。线反转法的基本 思想是通过行列颠倒两次扫描来识别闭合键, 为此需要提供两个可编程的双向输 入/输出端口。 (4)键码产生:为了从键的行列坐标编码得到反映键功能的键码,一般在

内存区中建立一个键盘编码表,通过查表获得被按键的键码。 用 AT89S51 的并行口 P0 接 4×4 矩阵键盘, P0.0-P0.3 作输入线, P0.4 以 以 -P0.7 作输出线;在数码管上显示每个按键的“0-F”序号。 3.LED 数码显示原理: 3.LED 数码显示原理: (1)七段 LED 显示器内部由七个条形发光二极管和一个小圆点发光二极管 组成,根据各管的极管的接线形式,可分成共阴极型和共阳极型。 LED 数码管 的 g~a 七个发光二极管因加正电压而发亮,因加零电压而不以发亮,不同亮暗的 组合就能形成不同的字形,这种组合称之为字形码,下面给出共阴极的字形码表 (如表 2-1 所示) “0” 3FH “8” 7FH “1” “2” “3” “4” “5” “6” “7” 06H 5BH 4FH 66H 6DH 7DH 07H “9” “A” “b” “C” “d” “E” “F” 6FH 77H 7CH 39H 5EH 79H 71H

表 2-1 字形码表 (2)由于显示的数字 0-9 的字形码没有规律可循,只能采用查表的方式来完 成我们所需的要求了。这样我们按着数字 0-9 的顺序,把每个数字的笔段代码 按顺序排好!建立的表格如下所示:TABLEDB 3FH,06H,5BH,4FH,66H,6DH, 7DH,07H,7FH,6FH。 4.电子琴实现原理 4.电子琴实现原理 1. 电源部分:是由 220V 的市电通过变压、整流稳压利用 7805 来得到+5V 电压, 维持系统的正常工作;把 7805 的 3 脚输出接到 89S51 的 40 引脚上

2 .4*4 的 16 个按钮矩阵: 4*4 行列式键盘识别;行线接 P0 口的 P0.0~P0.3,列 线 P0.4~P0.7,行值和列值的组合就是识别这个按键的编码。每个按键的状态同 样需变成数字量“0”和“1”,开关的一端(列线)通过电阻接 VCC,而接地是 通过程序输出数字“0”实现的。

3. 晶振模块:用 12MHZ 的晶振,及两个 30pf 的电容,接到单片机的 18,19,20 脚,电路如图(a)所示

(a)

(b)

4. 复位模块:利用开关和一个 10uf 的极性电容并联接单片机 9 脚“reset”脚, 电路如图(b)所示 5. 音频放大模块:利用三极管将信号放大,由扬声器放出,信号由单片机的 17 脚“P3.7”口读出,电路如图(c)所示

(c)

(d)

6. 数码管:利用 AT89S51 单片机的 P2 端口的 P2.0-P2.7 连接到一个七段 数码管的 a-h 的笔段上,数码管的公共端接地。在数码管上循环显 示 0-7 数字,时间间隔 0.2 秒。

三.硬件电路

图 3.1 硬件电路原理图 Protel

图 3.2 硬件电路 PCB 四.系统程序设计流程图

五.Proteus 仿真电路

图 4.1 Proteus 仿真电路图 六.源程序
调用程序: (1)Soundplay 调用程序:

/*说明************************************************************************** /*说明************************************************************************** 说明 MusicName{音高 音长,音高,音长...., 音高, 曲谱存贮格式 unsigned char code MusicName{音高,音长,音高,音长...., 0,0}; 示结束(Important) 示结束(Important) 末 尾 :0,0 表

音高由三位数字组成: 音高由三位数字组成: 个位是表示 1~7 这七个音符 十位是表示音符所在的音区:1-低音, 中音, 高音; 十位是表示音符所在的音区:1-低音,2-中音,3-高音; :1 百位表示这个音符是否要升半音: 0-不升, 升半音。 百位表示这个音符是否要升半音: 0-不升,1-升半音。 音长最多由三位数字组成: 音长最多由三位数字组成: 个位表示音符的时值,其对应关系是: 个位表示音符的时值,其对应关系是: |数值(n): |0 |1 |2 |3 | 4 | 5 | 6 数值(n): |几分音符: |1 |2 |4 |8 |16 |32 |64 几分音符: 音符=2^n 音符=2^n

十位表示音符的演奏效果(00-普通, 连音, 十位表示音符的演奏效果(0-2): 0-普通,1-连音,2-顿音 (0 百位是符点位: 0-无符点, 百位是符点位: 0-无符点,1-有符点 调用演奏子程序的格式 Play(乐曲名,调号,升降八度,演奏速度); Play(乐曲名,调号,升降八度,演奏速度); 乐曲名 速度 |乐曲名 |调号(0-11) 调号(0(0 |升降八度(1-3) 升降八度(1(1 |演奏速度(1-12000): 演奏速度(1(1 要播放的乐曲指针,结尾以(0,0)结束; (0,0)结束 : 要播放的乐曲指针,结尾以(0,0)结束; : 是指乐曲升多少个半音演奏; 是指乐曲升多少个半音演奏; 1:降八度 2:不升不降 3:升八度 降八度, 不升不降, 升八度; : 1:降八度, 2:不升不降, 3:升八度; 值越大速度越快; 值越大速度越快;

***************************************************************************/ __SOUNDPLAY_H_REVISION_FIRST__ #ifndef __SOUNDPLAY_H_REVISION_FIRST__ #define __SOUNDPLAY_H_REVISION_FIRST__

//**************************************************************************

#define SYSTEM_OSC #define SOUND_SPACE sbit BeepIO = 4/5

//定义晶振频率 12000000 //定义晶振频率 12000000HZ //定义普通音符演奏的长度分率,//每 //定义普通音符演奏的长度分率,//每 4 分音符间隔 定义普通音符演奏的长度分率,// //定义输出管脚 //定义输出管脚 定义

P3^7;

//原始 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 }; Sound_Temp_TH0,Sound_Temp_TL0; unsigned char Sound_Temp_TH0,Sound_Temp_TL0; unsigned char Sound_Temp_TH1,Sound_Temp_TL1; //音符定时器初值暂存 //音符定时器初值暂存 //音长定时器初值暂存 //音长定时器初值暂存

//************************************************************************** void InitialSound(void)

{ BeepIO = 1; (65535-(1/1200)*SYSTEM_OSC)/256; Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256; // 计算 TL1 应装入的初值 初装值) 初装值) (65535Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256; // 计算 TH1 应装入的初值 TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TMOD= 0x11; ET0 ET1 TR0 TR1 EA } = 1; = 0; = 0; = 0; = 1; (10ms 的

BeepTimer0(void) void BeepTimer0(void) interrupt 1 { BeepIO = 0; BeepIO = !BeepIO; TH0 TL0 } = Sound_Temp_TH0; = Sound_Temp_TL0;

//音符发生中断 //音符发生中断

//************************************************************************** Signature,unsigned void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed) {BeepIO = 0; 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; for(i=0;i<12;i++) { j = i + Signature; if(j > 11) { jj = 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 SoundLength = 0; while(Sound[SoundLength] != 0x00) { SoundLength+=2; } //计算歌曲长度 //计算歌曲长度

Point = 0; Tone = Sound[Point]; // 读出第一个音符和它时时值

Length = Sound[Point+1];

LDiv0 = 12000/Speed; LDiv4 = LDiv0/4; LDiv4LDiv4 = LDiv4-LDiv4*SOUND_SPACE; TR0 TR1 = 0; = 1;

分音符的长度( // 算出 1 分音符的长度(几个 10ms) // 算出 4 分音符的长度 // 普通音最长间隔标准

while(Point < SoundLength) { SL=Tone%10; SM=Tone/10%10; SH=Tone/100; NewFreTab[SignTab[SLCurrentFre = NewFreTab[SignTab[SL-1]+SH]; if(SL!=0) { if (SM==1) CurrentFre >>= 2; if (SM==3) CurrentFre <<= 2; //低音 //低音 //高音 //高音 //计算出音符 //计算出音符 //计算出高低音 //计算出高低音 //计算出是否升半 //计算出是否升半 //查出对应音符的频率 //查出对应音符的频率

65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值 Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值 Sound_Temp_TH0 = Temp_T/256; Sound_Temp_TL0 = Temp_T%256; Sound_Temp_TH0; TH0 = Sound_Temp_TH0; //加 TL0 = Sound_Temp_TL0 + 12; //加 12 是对中断延时的补偿 } //算出是几分音符 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(XG==0) if (SLen<=4) LDiv1=LDivLDiv1=LDiv-LDiv4; else LDiv1=LDiv*SOUND_SPACE; //算出普通音符的演奏长度 //算出普通音符的演奏长度 //算出连音音符演奏的长度( //算出连音音符演奏的长度(多少个 10ms) 算出连音音符演奏的长度 //算出音符类型(0 顿音) //算出音符类型(0 普通 1 连音 2 顿音) 算出音符类型

else LDiv1=LDiv/2; else LDiv1=LDiv; if(SL==0) LDiv1=0; LDiv2=LDivLDiv2=LDiv-LDiv1; if (SL!=0) { TR0=1; for(i=LDiv1;i>0;i--) for(i=LDiv1;i>0;i--) (i=LDiv1;i>0;i-{ while(TF1==0); TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TF1=0; } } if(LDiv2!=0) { TR0=0; BeepIO=0; for(i=LDiv2;i>0;i--) for(i=LDiv2;i>0;i--) -{ while(TF1==0); TH1 = Sound_Temp_TH1; TL1 = Sound_Temp_TL1; TF1=0; } } Point+=2; Tone=Sound[Point]; Length=Sound[Point+1]; } BeepIO = 0; } //************************************************************************** #endif (2)主程序 #include <REG52.H> #include "SoundPlay.h" #include<intrins.h> #include<intrins.h> #include<math.h> #define uchar unsigned char #define uint unsigned int int shang,key; //音符间的间隔 //音符间的间隔 //发规定长度的音 //发规定长度的音 //算出不发音的长度 //算出不发音的长度 //算出顿音的演奏长度 //算出顿音的演奏长度

sbit w=P3^2; sbit k = P3^0; //定义输出管脚 //定义输出管脚

void delay(unsigned int t) { unsigned int i, j; for (i = 0;i < t;i++) for (j = 0;j < 10;j++) ; } unsigned unsigned char code table[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71 }; //*****************************Music****************************************************** //*****************************Music****************************************************** //挥着翅膀的女孩 //挥着翅膀的女孩 unsigned char code Music_Girl[]={ 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, 0x19,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, 0x00, 0x00,0x00}; //同一首歌 //同一首歌 同一 unsigned char code Music_Same[]={ 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x66, 0x18,0x03, 0x17,0x02, 0x15,0x02, 0x16,0x01, 0x15,0x02, 0x10,0x02, 0x16,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, 0x1B,0x02, 0x17,0x01, 0x19,0x02, 0x1B,0x02, 0x1B,0x70, 0x1A,0x03, 0x19,0x00, 0x00,0x00 }; //两只蝴蝶 //两只蝴蝶 unsigned char code Music_Two[] ={ 0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03, 0x16,0x03, 0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02, //0,1,2,3//

//4,5,6,7// //8,9,a,b// //c,d,e,f//

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, 0x10,0x03, 0x15,0x00, 0x00,0x00 }; //*********************************************************************************** //*********************************************************************************** unsigned char code Music_Gir2[]={ 0x25,0x02,0x00,0x00}; unsigned char code Music_Gir3[]={ 0x57,0x02,0x00,0x00}; unsigned char code Music_Gir4[]={ 0x84,0x02,0x00,0x00}; Music_Gir5[]={ unsigned char code Music_Gir5[]={ 0x98,0x02,0x00,0x00}; unsigned char code Music_Gir6[]={ 0xc0,0x02,0x00,0x00}; unsigned char code Music_Gir7[]={ 0x15,0x02,0x00,0x00}; unsigned char code Music_Gir8[]={ 0x17,0x02,0x00,0x00}; 0x16,0x02,0x00,0x00}; unsigned char code Music_Gir9[]={ 0x16,0x02,0x00,0x00}; unsigned char code Music_Gir10[]={ 0x1A,0x02,0x00,0x00}; unsigned char code Music_Gir11[]={ 0x1B,0x02,0x00,0x00}; unsigned char code Music_Gir12[]={ 0x0E,0x02,0x00,0x00}; unsigned char code Music_Gir13[]={ 0x19,0x02,0x00,0x00}; Music_Gir14[]={ unsigned char code Music_Gir14[]={ 0x17,0x02,0x00,0x00}; //键盘按键程序 //键盘按键程序 void scan() { uchar hao[4]={0x0e,0x0d,0x0b,0x07}; //决定了键盘按键布局 uchar key_[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //决定了键盘按键布局 uchar temp,h,j,i,high,low; bit find=0; P0=0xf0; temp=P0; if(temp!=0xf0) { delay(20); //去抖 //去抖 //行低电平 //行低电平 列高电平 //检测是否有键按下 //检测是否有键按下 //定义位 find //定义位 find 标志 并赋值零 // 键盘扫描程序

//确定有键按下 if(temp!=0xf0) //确定有键按下 { find=1; //标志有键按下 //标志有键按下

//将列的状态存入 high=(temp>>4); //将列的状态存入 high P0=0x0f; temp=P0; //翻转行列电平 //翻转行列电平 //再次读取 //再次读取 P0

//将行的状态存入 low=(temp&0x0f); //将行的状态存入 low

//确定按键的坐标 for(i=0;i<4;i++) //确定按键的坐标 { if(hao[i]==high){j=i;} if(hao[i]==low){h=i;} } }

} if(find==0){key=16;} else key=4*h+j; shang=key; } keydown()//判断按键是否按下 void keydown()//判断按键是否按下 { P0=0xF0 ; if(P0!=0xF0) { scan() ; } } main() {k=1;w=0; InitialSound(); while(1) {shang=20; keydown(); if(shang==13) {P2=table[13]; k=0; delay(200);Play(Music_Girl,0,3,360);k=1;} if(shang==14) {P2=table[14];k=0;delay(200);Play(Music_Same,0,3,360);k=1;} {P2=table[15];k=0;delay(200);Play(Music_Two,0,3,360);k=1;} if(shang==15) {P2=table[15];k=0;delay(200);Play(Music_Two,0,3,360);k=1;} if(shang==0) {shang=20;Play(Music_Gir2,0,3,360);P2=table[0];k=0;delay(600);k=1;} if(shang==1) {shang=20;Play(Music_Gir3,0,3,360);P2=table[1];k=0;delay(600);k=1;} {shang=20;Play(Music_Gir4,0,3,360);P2=table[2];k=0;delay(600);k=1;} if(shang==2) {shang=20;Play(Music_Gir4,0,3,360);P2=table[2];k=0;delay(600);k=1;} if(shang==3) {shang=20;Play(Music_Gir5,0,3,360);P2=table[3];k=0;delay(600);k=1;} if(shang==4) {shang=20;Play(Music_Gir6,0,3,360);P2=table[4];k=0;delay(600);k=1;} if(shang==5) {shang=20;Play(Music_Gir7,0,3,360);P2=table[5];k=0;delay(600);k=1;} if(shang==6) if(shang==6) {shang=20;Play(Music_Gir8,0,3,360);P2=table[6];k=0;delay(600);k=1;} if(shang==7) {shang=20;Play(Music_Gir9,0,3,360);P2=table[7];k=0;delay(600);k=1;} if(shang==8) {shang=20;Play(Music_Gir10,0,3,360);P2=table[8];k=0;delay(600);k=1;} if(shang==9) {shang=20;Play(Music_Gir11,0,3,360);P2=table[9];k=0;delay(600);k=1;} if(shang==10) {shang=20;Play(Music_Gir12,0,3,360);P2=table[10];k=0;delay(600);k=1;} if(shang==11) {shang=20;Play(Music_Gir13,0,3,360);P2=table[11];k=0;delay(600);k=1;} {shang=20;Play(Music_Gir14,0,3,360);P2=table[12];k=0;delay(600);k=1;} if(shang==12) {shang=20;Play(Music_Gir14,0,3,360);P2=table[12];k=0;delay(600);k=1;} } }

七.元件清单 1 AT89S51 芯片 2 二极管 3 极性电容 4 5 6 电容 电阻排 电阻

7 8 9 10 11 12 13 14 15 16

晶振 红色发光 LED 7 段数码管 共阴 开关 喇叭 变压器 下载线 LM7805 9015 PNP 9013 NPN

IN4004 220uf/50V 10uf 105 30pf 1K 500 1K 5.1K 10K 12MHZ

1个 4 个(电桥) 2个 1个 2个 2个 1个 1个 9个 1个 1个 1个 1个 1个 17 个 1个 1个 1根 1个 1个 1个

八.设计心得与体会 设计心得与体会 在为期一周的单片机课程设计中,我在增长知识、提高能力的同时,产生了 很深的感触。从初步定下方案到编出程序,从不断的运行排错到调试成功,在整 个设计过程中,着实受益匪浅,不仅可以巩固以前所学过的知识,而且学到了很 多在书本上所没有学到过的东西。 我懂得了理论与实际相结合是很重要的,眼高手低的现象常常难以避免。只 有把所学的理论知识与实践相结合起来,从理论中得出结论,才能提高自己的实 际动手能力和独立思考的能力。 在设计的过程中难免会遇到各种各样的问题,但是在这重重困难之中我了解 到自己的真实水平,并努力提高自己。同时我明白,对于想要成功的人来说更重 要的不是知识或技能,而是克服困难的信心。实践证明看似“莫名其妙”的错误只 要坚持尝试必定有办法解决,应灵活地从各方面找原因而不是一味归咎于实验仪 器或软件平台。 同时我意识到合作的精神是非常重要的。有目的的分工可以提高课程设计的 质量和效率,互帮互助的学风可以使每个成员走最少的弯路而增长最多的知识。 通过这次的课程设计作品的制作让我对单片机的理论有了更加深入的了解, 同时在具体的制作过程中我们发现现在书本上的知识与实际的应用存在着不小 的差距,书本上的知识很多都是理想化后的结论,忽略了很多实际的因素,或者 涉及的不全面,可在实际的应用时这些是不能被忽略的,我们不得不考虑这方的

问题,这让我们无法根据书上的理论就轻易得到预想中的结果,有时结果甚至很 差别很大。通过这次实训,基本掌握了 Protel99SE 原理图的画法,并画出 PCB 图,如何利用 protues 进行仿真,利用 keil 生成 hex 文件。通过开发板的设计 和硬件搭建的过程,使我对 51 系单片机的接口有了更深层次的理解,熟悉了一 些单片机常用的外围电路引脚和连接方法。我熟悉了 51 系列单片机内部的寄存 器和编程规则,以及如何控制外围电路,在编程的过程中,也了解到 C 语言与汇 编语言的不同。



友情链接: 医学资料大全 农林牧渔 幼儿教育心得 小学教育 中学 高中 职业教育 成人教育 大学资料 求职职场 职场文档 总结汇报