郑州科技学院
专科毕业设计(论文)
题 目 ____________________
____________________
学生姓名
专业班级
学 号
所 在 系
指导教师
完成时间 年 月
日
目 录
1 引言............................................................. 1
2 整体设计思路..................................................... 3
3 主要元件的使用方法............................................... 4
3.1 AT89C51单片机: ................................................ 4
3.2 7407驱动器: ................................................... 5
3.3数码管: ........................................................ 6
4 电路设计......................................................... 7
4.1整体设计 ........................................................ 7
4.2 分块设计........................................................ 7
4.2.1 输入部分..................................................... 7
4.2.2 输出部分(显示电路)......................................... 8
4.2.3 晶振与复位电路:............................................. 9
5 程序设计......................................................... 9
5.1程序思路 ........................................................ 9
5.2程序设计步骤 ................................................... 10
5.3程序的主要模块 ................................................. 11
5.3.1延迟程序 ..................................................... 11
5.3.2 中断服务子程序:............................................. 11
5.3.3 主程序....................................................... 13
5.3.4显示程序 ..................................................... 13
5.3.5 闹铃程序和定时程序........................................... 14
5.4程序调试 ....................................................... 14
6 功能仿真........................................................ 15
6.1 软件介绍....................................................... 15
6.1.1PROTEUS....................................................... 15
6.1.2MedWin........................................................ 15
6.2仿真过程: ..................................................... 16
6.2.1仿真图的绘制 ................................................. 16
6.2.2功能的实现 ................................................... 17
7 实际电路的实现.................................................. 18
8 日历功能的实现.................................................. 20
9 电子钟设计中遇到的问题及其解决方法.............................. 23
结论............................................................... 25
参考文献........................................................... 26
致谢............................................................... 28
附录A 整体电路图 .................................................. 29
附录B 完整程序 .................................................... 30
1 引言
单片机因将其主要组成部分集成在一个芯片上而得名,就是把中央处理器、随机存储器、只读存储器、中断系统、定时器/计数器以及I/O接口电路等部件集成在一个芯片上[1]。
单片机自20世纪70年代问世以来,以其极高的性能价格比,受到人们的重视和关注,应用很广、发展很快。单片机具有体积小、功能多、价格低廉、使用方便、系统设计灵活等优点[2]。因此,它应用广泛前景美好,它的实用性大大地提高了我对毕业设计的兴趣。
在我国,单片机的开发应用已有15年左右,已经形成一支庞大的技术开发队伍,为我国单片机应用积累了丰富的经验。随着电子技术、计算机芯片技术和微电子技术的飞速发展促进了单片机技术一日千里的变化[3]。
随着半导体技术的飞速发展,以及移动通信、网络技术、多媒体技术在嵌入式系统设计中的应用,单片机从4位、8位、16位到32位,其发展历程一直受到广大电子爱好者的极大关注。单片机功能越来越强大,价格却不断下降的优势无疑成为嵌入式系统方案设计的首选,同时单片机应用领域的扩大也使得更多人加入到基于单片机系统的开发行列中,推动着单片机技术的创新进步。
然而传统的单片机系统开发除了需要购置诸如仿真器、编程器、示波器等价格不菲的电子设备外,开发过程也较繁琐。来自英国Labcenter Electronics公司的Proteus软件很好地诠释了利用现代EDA工具方便快捷开发单片机系统的优势。它包括PROTEUS VSM(Virtual System Modelling)、PROTEUS PCB DESIGN两大组成部分,在PC机上就能实现原理图电路设计、电路分析与仿真、单片机代码级调试与仿真、系统测试与功能验证以及形成PCB文件的完整嵌入式系统设计与研发过程。
单片机系统作为一种典型的嵌入式系统,其系统设计包括硬件电路设计和软件编程设计两个方面, 其调试过程一般分为软件调试、硬件测试、系统调试3个过程。如果采用单片机系统的虚拟仿真软件——Proteus,则不用制作具体的电路板也能够完成以上工作。
数字钟是采用数字电路实现对时,分,秒,数字显示的计时装置,由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得数字钟的精度,远远超过老式钟表,钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表的报时功能。数字钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、码头、剧院、办公室等场所,给人们的生活、学习、工作带来极大的方便[4]。不仅如此,在现代化的进程中,也离不开电子钟的相关功能和原理,比如机械手的控制、家务的自动化、定时自动报警、按时自动打铃、时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备、甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。而且是控制的核心部分。因此,研究数字钟及扩大其应用,有着非常现实的意义。
电子钟在工业控制和日常生活中是很重要的,它不仅可以用于计时、提醒又可用于对机器的控制,在自动化的过程中必然有电子钟的参与,因此电子钟的应用会越来越广泛。而且向着精确、低功耗、多功能发展。基于单片机设计的数字钟精确度较高, 因为在程序的执行过程中, 任何指令都不影响定时器的正常计数,即便程序很长也不会影响中断的时间。从而,使数字钟的精度仅仅取决于单片机的产生机器周期电路和定时器硬件电路的精确度。另外,程序较为简洁,具有可靠性和较好的可读性。如果我们想将它应用于实时控制之中,只要对上述程序和硬件电路稍加修改,便可以得到实时控制的实用系统,从而应用到实际工作与生产中去。
数字电子钟的设计方法有多种,例如,可用中小规模集成电路组成电子钟, 也可以利用专用的电子钟芯片配以显示电路及其所需要的外围电路组成电子钟还可以利用单片机来实现电子钟等等。这些方法都各有特点, 其中,利用单片机实现的电子钟具有编程灵活, 便于功能扩充, 精确度高等特点[5]。
基于以上分析,在此次设计中,我选择的是利用单片机制作电子钟。电子钟的设计本身包括程序的设计和硬件电路的设计[6]。我的思路是,先进行电路的整体设计,再根据电路进行编程,在编程的过程中,对电路进行微调,以更好地配合程序。在设计完成后,进行程序调试,调试软件选择MedWin,调试成功后,再根据电路图画出仿真图,将软件装入单片机芯片,利用Proteus软件进行仿真,仿真中的错误通过改正程序中的逻辑错误和电路中的设计不当进行排除,这个过
程是很艰难的但也是很重要的。若仿真可以实现,则硬件电路的实现就可以有条不紊地进行。
2 整体设计思路
这部分主要介绍工作安排和整体设计的思想。工作过程规划如下:
图2.1 整体设计思路
针对要实现的功能,拟采用AT89C51单片机进行设计,AT89C51 单片机是一款低功耗,高性能CMOS8位单片机,片内含4KB在线可编程(ISP)的可反复擦写1000次的Flash只读程序存储器,器件采用高密度、非易失性存储技术制造,
兼容标准MCS- 51指令系统及80C51引脚结构[7]。这样,既能做到经济合理又能实现预期的功能。
在程序方面,采用分块设计的方法,这样既减小了编程难度、使程序易于理解,又能便于添加各项功能。程序可分为闹钟的声音程序、显示程序、闹钟显示程序、调时显示、定时程序。运用这种方法,关键在于各模块的兼容和配合,若各模块不匹配会出现意想不到的错误。
本电子钟设计主要是依照图2.1中的流程做出来的,时间分配比较均匀。首先,在编程之前必须了解硬件结构尤其是各引脚的用法,以及内部寄存器、存储单元的用法,否则,编程无从下手,电路也无法设计。这是前期准备工作。第二部分是硬件部分:依据想要的功能分块设计设计,比如输入需要开关电路,输出需要显示驱动电路和数码管电路等。第三部分是软件部分:先学习理解汇编语言的编程方法再根据设计的硬件电路进行分块的编程调试,最终完成程序设计。第四部分是软件画图部分:设计好电路后进行画图,包括电路图和仿真图的绘制。第五部分是软件仿真部分:软硬件设计好后将软件载入芯片中进行仿真,仿真无法完成时检查软件程序和硬件电路并进行修改直到仿真成功。第六部分是硬件实现部分:连接电路并导入程序检查电路,若与设计的完全一样一般能实现想要的功能。最后进行功能扩展,本设计加进了日期显示与调整功能。
3 主要元件的使用方法
下面就本次设计中用到的主要元件的所有功能进行简单的介绍,包括AT89C51单片机、74LS07芯片、以及数码管的特性和用法。
3.1 AT89C51单片机[8]:
该单片机功能强大,不仅能满足设计的需要,也可以在设计要求的基础上进行一些扩展。
单片机的结构如下:
图3.1.1 单片机引脚图
在使用时VCC接电源电压,GND接地。P0,P1,P2,P3可作为输入或输出端口,RST是复位输入,接复位电路。XTAL1和XTAL2接复位电路。这些可以在硬件设计部分体现出来。
3.2 7407驱动器[9]:
7407是集电极开路六正相高压驱动器,1入2出,3进4出,5进6出,9进8出,11进10出,13进12出,7接地,14接高电平。
7407引脚图:
图3.2.1 7407引脚图
7407逻辑图:
图3.2.2 7407逻辑图
3.3数码管:
图3.3.1 数码管
使用共阴极数码管时将6个数码管按相同功能连接起来,3与8相连,当选通端所接管脚为低电平时该数码管选通。
单片机的P2口作为选通端,连接各数码管的3、8引脚轮流显示,连接时要加7407和上拉电阻。
单片机的P1口作为功能段,通高电平的引脚会使相应段亮起,同样的也要与7407和电阻连接使用。
4 电路设计
4.1整体设计
此次设计主要是应用单片机来设计电子时钟,硬件部分主要分以下电路模块:显示电路用六个数码管分别显示小时(年份)、分钟(月份)和秒(日),通过动态扫描进行显示,从而避免了译码器的使用,使电路更加简单。单片机采用AT89C51系列,这种单片机应用简单,适合电子钟设计。
电路的总体设计框架如下:
图4.1.1 电路模块图
4.2 分块设计
这部分介绍各模块电路的设计方法和成果,主要分为:输入部分、输出部分、复位和晶振电路。 4.2.1 输入部分
在电子钟的输入部分,设置相应的置数功能,通过外部设备的输入,如按键,实现时间的修改[10-11]。除此之外,调整闹铃、定时、日期时也需要按键进行输入。在选用输入端口时,将P3引脚与按键相连进行输入[12]。
设计的输入部分如下:
图4.2.1 输入部分
各按键功能在后面的部分将会介绍到 4.2.2 输出部分(显示电路)
该部分电路图如下所示:
图4.2.2 显示部分
在实际电路中采用单个数码管相连进行显示,先把数码管的1、2、4、5、6、7、9、10对应相连,然后把各晶体管的3和8引脚各自相连,P1.6~P1.0分别接a~g,P2作为选通端P2.0~P2.5分别从左到右接各数码管的3、8端。采用动态显示, 即一位一位地轮流点亮各位显示器[18],因此P2.0~P2.5轮流置0。持续时间为1ms,这点在程序部分还会讲到。
4.2.3 晶振与复位电路:
图4.2.3 晶振与复位电路
5 程序设计
5.1程序思路
图5.1.1 程序设计思路
结合电路,程序的总体思路是[17]:
1、点复位键后,进行时间显示,从0时0分0秒开始。
2、按下按键1时,进行调时,此时按下4调整时,按下5调整分,若2秒钟未按键,则不再等待,恢复走时,持续按键时大约0.3秒步进1,下同。
3、按下2键时进行闹铃调整,用4、5键分别调时和分,此时只有前四位进行显示,即闹铃功能精确到分,2秒钟无按键则返回时间显示,时间到达闹铃所定时间时P0.7输出高电平,蜂鸣器响,按下按键2或3时蜂鸣器停止。
4、按3键时进行定时的设定,同样,分别通过4、5调整分和秒,若两秒未按键则不进行定时,设定之后再次按下3键则进行倒计时,倒计时时间未到时若按下1键则进行时间显示;若倒计时时间到则P0.7为高电平,蜂鸣器响。定时的最大值为59分59秒。
在程序设计时,尽量改进算法,算法的改进可以使相对误差减小[12],或者可以使占用空间减小[14]。另外,分块的设计思想要贯穿始终,整个程序较为繁杂,某些程序段会反复用到,因此采取的方法是写出多个程序段,通过跳转指令进行调用。
5.2程序设计步骤
在程序设计过程中,我遇到了很多困难,这部分也是让我学到很多东西的地方。
首先,我学习了定时器的相关知识,计数器的使用是很重要的组成部分[15],在这个设计中选择计数器T0。T0的工作方式有:
方式0:不推荐
方式1:16位计数器,常用
方式2:自动重装初值的8位定时/计数器 方式3:T0相当于两个独立的8位定时/计数器
此程序采用方式1,方式1的定时时间t为t=(216-M)*12/fosc。其中M为定时器初值,fosc为12MHz,若M为0则t=65536*12/2*106=65.536ms。因此可取50ms为计时单位[16],初值M应为50*10-3*106=216-M。M=15536=[1**********]000=3CB0。即定时器初值为TH0=03CH,TL0=0B0H。定时器中断20次为一秒,这部分在中
断程序中用到。
其次,我参看了文献中的设计思路,做到胸有成竹后再进行具体的程序书写工作。认真学习了教科书中关于汇编语言编程的问题,熟悉了汇编语言的编程方法和语法习惯。
第三步就是进行具体的程序编写工作。
5.3程序的主要模块
5.3.1延迟程序
在动态扫描时,必然用到延迟程序,这里使用延迟1ms的程序,此程序需要反复调用。此段程序是很简单的,但就是在这段简单的程序上,也会出现问题,若用
D_1MS: MOV R7,#500 DJNZ R7,$ RET
则会出现警告,因为R7是8位寄存器,所能存储的最大值应为255,所以应改为:
D_1MS: MOV R7,#2 D_5: MOV R2,#250 DJNZ R2,$ DJNZ R7,D_5 RET
5.3.2 中断服务子程序:
中断服务程序中,总体思路是:由于初值是3CB0H,所以装满定时器需要50ms的时间,从而20次中断为一秒,一秒之后,判断是否到60秒,若不到则秒加一,然后返回,若到,则秒赋值为0,分加一,依次类推。包括日期显示的功
能也是如此。另外,由于要实现倒计时功能,因此在中断程序中还要加入减一的寄存器,需要时将其进行显示。基于以上考虑,以R3为倒计时中的秒,R4为倒计时的分,当秒加1时R3减一,减到0之后,秒赋值为59,分减一,直到分为0。再显示走时部分。
流程框图如下:
图5.3.1 中断程序思路
5.3.3 主程序
主程序主要对按键进行扫描,以及判断定时和闹铃时间是否已到,若到则调用声音程序,该段程序如下:
MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整 JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时 JNB P3.2,NLTZ1;按下2键进行闹铃设置 JNB P3.3,DSTZ;按下3键进行定时设置 ACALL DISP; MOV A, HOUR; SUBB A, 38H; JZ FEN; AJMP DSPD2; FEN:
MOV A, MINUTE; SUBB A, 37H; JZ SHENGYIN1; DSPD2: MOV A, R4; JZ S_PD; AJMP MAIN; S_PD: MOV A, R3; JZ SHENGYIN1; AJMP MAIN; 5.3.4显示程序
6个晶体管轮流进行显示,分别显示1ms,这依赖的是人们视觉的惰性,该段程序如下:
DISP:;走时的显示程序,包括调时时的显示 MOV DPTR,#LEDTAB MOV A,SECOND MOV B,#10
DIV AB;A存十位B存个位 MOVC A,@A+DPTR MOV P1,A CLR SEC_S
ACALL D_1MS;显示秒十位 SETB SEC_S MOV A,B
MOVC A,@A+DPTR MOV P1,A CLR SEC_G
ACALL D_1MS;显示秒个位 SETB SEC_G „„
以此类推,进行时和分的显示 RET
另外,调闹铃和定时时间、进行日期显示时,有各自的显示程序,但不能成为独立子程序,分别柔和在闹铃、定时、和日期程序中。 5.3.5 闹铃程序和定时程序
这两段程序分别包含了各自的显示、调整程序。程序思路是对照,走时部分的程序,进行编写,包括显示程序,与显示时间的程序是相似的,闹铃和定时的调整程序与走时调整程序相似。
5.4程序调试
程序写完以后必须进行调试,以验证程序是否正确。在程序调试时,出现了很多问题,比如跳转距离过长、打错字母、逻辑有错等,发现问题后,利用两天
时间进行了改正,但即使编译通过,最后也不一定能够实现功能。以为程序的调试只能检查出语法错误,而不能检查出逻辑的错误。要真正把程序写对,要通过仿真发现并且改正错误。
6 功能仿真
这部分工作可能遇到的困难是很多的,程序庞大很可能出现各种问题。在仿真工作中,首先要对仿真软件有足够的了解并能够正确熟练地运用
6.1 软件介绍
在这部分工作中用到了medwin3和Proteus两个软件,其中Medwin3用来编译程序并生成hex文件,装入Proteus仿真图的芯片中,通过仿真结果一步步进行调整最后达到预期的功能。 6.1.1PROTEUS
PROTEUS软件是目前世界上最先进、最完整的嵌入式系统设计与仿真平台,可以实现数字电路、模拟电路及微控制器系统与外设的混合电路系统的电路仿真、软件仿真、系统协同仿真和PCB设计等功能,是目前唯一能够对各种处理器进行实时仿真、调试与测试的EDA工具。微控制器系统相关的仿真需建立编译和调试环境,可选择MedWin V3 软件。该软件支持众多不同公司的芯片,集编辑、编译和程序仿真等于一体,同时还支汇编和C语言的程序设计。Proteus的界面友好易学,在调试程序、软件仿真方面有很强大的功能。 其革命性的功能是:将电路仿真和微处理器仿真进行协同,直接在基于原理图的虚拟原型上进行处理器编程调试,并进行功能验证,通过动态器件如电机、LED、LCD、开关等,实时看到运行后的输入、输出的效果。Proteus为我们建立了完备的电子设计开发环境。 6.1.2MedWin
MedWin可以用来编写汇编语言程序并进行编译、产生代码并装入仿真器以便于仿真,在输出文件夹中会产生hex文件,将该hex文件导入仿真图的单片机芯片中即可进行仿真。
使用时点击“项目管理—新建项目”就可以建立编程的平台,然后选择项目管理中的新建文件就可以建立asm文件,在这个文件中可以进行程序的编写,程序编写完毕后可点击“项目管理—编译\汇编”看其是否有错,有错时,在下面的窗口会提示出错的行以及错误原因。改正无误后可产生代码并装入,将hex文件导入单片机中即可进行仿真
6.2仿真过程:
通常在仿真过程中会遇到很大的麻烦。在程序汇编通过之后程序不一定是正确的,比如我刚开始进行仿真时数码管并不进行显示,结果发现应该是置零的置一了,应该置一的置零了。改正之后发现虽然走时程序正常了,但是调时中出现了大量的问题,更不要说闹铃和定时程序了。在整个毕业设计的过程中程序的修改贯穿始终,在修改的过程中一定要条理清晰,认真细心。
6.2.1仿真图的绘制
在使用Proteus进行仿真时,仿真图不用画出数码管驱动程序,其他部分与设计的硬件图相仿。绘制结果如下:
图6.2.1 仿真图
6.2.2功能的实现
在绘制仿真图之后,要向单片机装入程序,从而使单片机开始工作并带动整个电路工作,装入过程为:点击单片机,选择所编译程序的输出hex文件,确定即可。此时单片机会按照程序所设定的功能进行工作,在仿真过程中会遇到各种问题,在第九章会具体讲到。这里列出仿真结果:
(1)走时仿真:
图6.2.2 走时状态下的仿真结果
(2)闹钟设定的仿真:
图6.2.3 闹铃仿真结果
可见所定闹钟时间为10点15分。
(3)定时钟倒计时的仿真:
图6.2.3 倒计时仿真
可见,倒计时进行到3分3秒。
7 实际电路的实现
在仿真无误后,开始进行实际电路的搭接。搭接时先不用芯片实物,而用仿真器替代。按照电路图,先把数码管按照对应的管脚连接起来,然后接驱动电路等,接好之后把程序装入仿真器,通电运行,再对电路进行调试。
在根据电路图搭接好各个器件后,一个很重要的问题就是检查各器件是否完全工作。下面介绍检验方法:
导线看似不用太费力气去检验,但一个成功的实验需要前期充分的准备,比如在我的实验过程中,由于导线繁多,而且使用旧导线进行实际电路的连接,所以就出现了导线不通的情况,因此验证过程中不要放过小问题。
数码管的检测:拆除89C51芯片,先分别给芯片P2对应的导线加低电平,再分别给P1对应的导线加高电平,使每个数码管的每一笔段都能亮。若出错,先检查电路的连接再换一下器件试试,对于此电路问题出在7407的连接方法的问题比
较大。这部分需要重点验证。
随后,按下复位键看9引脚是否为低电平,是则没有错误。
通过以上工作,硬件仿真无误后,可以用单片机芯片代替仿真器进行最后的实现工作,用easyPRO80B编程器将程序下载到芯片中,具体步骤为:先进行擦除,然后查空,查空无误后打开所需的hex文件,然后进行编程、校验。这时程序载入了芯片中,就可以实现相应的功能了。
实验结果如下:
图7.1 走时显示实物图
这里要说的是,软件仿真成功和硬件电路实现之间是有很大差别的,在做软件仿真时,没有驱动的问题,没有芯片和器件质量的问题,也没有电线导电的问题,没有工作条件的问题,但在实际电路中这些因素都要考虑。常常会出现这种情况:软件仿真实现了,但实际电路没有任何功能。在电子钟硬件实现过程中,
就出现了很多问题,有引脚接错的问题,也有插线松动或电线不通的问题,这些问题都是需要耐心和细心认真解决的。
8 日历功能的实现
在加入其它功能时,我想到了很多可能达到的功能,比如加入备用电源、夜间亮灯功能、多个闹铃的功能、显示日期功能等。然后我进行了理论上的验证,加入备用电源可避免因停电而造成的电路全部失灵[20,21],但受到实验条件的影响未选择对这个功能进行实现。夜间亮灯功能对程序要求不高,但在电路中要加入传感器,把光的照度测出来后,低于某一值时,灯亮,从而使得夜间时也能看到时间显示,虽然程序简单,但由于要加入传感器,容易受到干扰,各项工作投入时间较长,考虑到时间有限,也没有采纳这个方案。闹铃的功能和日期的功能的实现都是比较容易的,做了权衡之后我选择了后者,因为日期功能主要涉及算法和程序的跳转、调用等,更能加深对单片机的认识和理解。
在设计的开始阶段,我主要考虑了日期的逻辑算法[19]。首先,要考虑年份是不是闰年,闰年的判断方法是:将年份除以100,若能整除,则将年份除以400,若还能整除,则为闰年,若不能,则为平年;若不能被100整除,则判断是否能被4整除,若能,则为闰年,若不能则为平年。只有2月与平、闰年相关,因此在闰年和平年的子程序中,要判断是不是2月,若是则在相应的年中进行日期的增加,若不是则转入平时的月份。其中1、3、5、7、8、10、12月是每月31天,4、6、9、11月为每月30天。
在电路方面有两种方法:(1)可以增加6个数码管用来显示日期,但这样显然电路更复杂;(2)用按键的输入决定6个数码管显示日期还是时间,这种情况下,只需加一个按键即可,不用增加数码管。最终的按键控制为:按下1键时,显示日期,并且用4、5、6键分别调整年、月、日;按下2键时,进行走时和时间调整;3键位闹铃键;4键为定时键。
这样实现功能的好处是:(1)电路简单,若同时显示日期和时间,则需要的引脚很多,需要加入译码器对引脚进行扩展。采用按键决定显示时间或日期的方法避免了这个问题;(2)节约空间,节约成本。
程序思路如下:
图8.1 扩展部分思路
由于在前面的工作中积累了较多的经验,对汇编语言已经相当熟悉,因此在实现日历功能时,程序设计显得相当容易。
按键如图8.2所示,按键功能如下:
按下按键1时,显示日期并且允许对日期进行调整;
按下按键2时,显示时间并且允许对时间进行调整;
按下按键3时,显示闹钟所设定的时间并允许通过5、6键对闹钟进行设定; 按下按键4时,显示定时功能所设定的时间并允许对其进行设定,再次按下时,开始倒计时过程,并进行倒计时过程的显示,在显示日期时,该键可对年份进行调整;
按键5、6可对时间显示时的时、分或日期显示时的月、日进行调整。
按键形式:
图8.2 按键图示
实验成果如下:
图8.2 日期显示实物图
图中显示的日期为10年5月27日。
9 电子钟设计中遇到的问题及其解决方法
在电子钟设计中程序比较长,遇到了各种各样的问题,比如跳转距离过长出现语法错误。因此修改程序的时间很长,有语法错误,也有仿真时功能无法实现的问题,在此不能一一说明,只能对个别问题加以阐述。
由于在走时调整、闹铃调整及定时设定时,按下键时每0.2秒步进1,这就需要每0.2秒对按键输入进行一次扫描,因此开始时,我用的是延迟0.2秒再返回按键扫描程序的方法,但是可以想到,进行单纯的延迟时,不会有显示,在仿真时功能没有实现。后来我采用的是反复调用若干次显示程序以实现延迟,较好地解决了这个问题。虽然现在回过头来发现这个问题很简单,但当时是百思不得其解。我从中学到:任何简单的事情都会有出错的可能,有些时候人的思路中的一些错误是自己难以发现的,在工作和生活中要多对自己的想法提出质疑。
不光是这种明显的问题很多,有些细微的问题也一样出现了,但解决起来并不容易。
在最后的硬件实现阶段发现蜂鸣器不响,此时连接方法是蜂鸣器直接连接在了P0.7引脚。考虑到单片机的输出电流比较小,虽然P0.7引脚的电平已经达到2V以上,也无法驱动蜂鸣器。于是我设想加上驱动电路。
作此修改之后,蜂鸣器发出响声,但是又遇到了新的问题:蜂鸣器无法停止响声!看上去这个问题很简单,只要有停止闹铃的按键输入时,在程序中加一句将P0.7置零的语句就可以了。但事实并不是这么简单。通过苦思冥想,发现在主程序中,对“定时时间是否已到”是不断进行扫描的,而倒计时是在中断服务子程序中进行的,当倒计时为0分0秒时,主程序判断出来后会不停地调用声音程序:
MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
ACALL DISP;
MOV A,HOUR;
SUBB A,38H;
JZ FEN;
AJMP DSPD2;
FEN:
MOV A,MINUTE;
SUBB A,37H;
JZ SHENGYIN1;
DSPD2:
MOV A,R4;
JZ S_PD;
AJMP MAIN;
S_PD:
MOV A,R3;
JZ SHENGYIN1;
AJMP MAIN;
蜂鸣器响声不停是不可避免的,因为R3和R4是在中断程序中变化的,随着时间的推移必然都为0,在此情况下即使按下了声音停止键,由于程序跳回主程序,又会不断地调用声音程序。基于这个想法要达到的效果是:按下声音停止键之后,不再进行定时时间是否为0的判断。要实现这个想法就要引入新的参数,这里,试用3CH作为判断的因子。当点击定时开始后,将3CH赋值为1,在主程序中判断3CH如果不为0,就进行倒计时是否到0的判断。蜂鸣器响后,点击3键时,将3CH赋值为0,这样在主程序中就不进行这个判断,因此蜂鸣器就不会响。
当然这个解决问题的过程不是一下子解决的在这个过程中,我进行了相当多的尝试和摸索,最终找到了这个解决途径。
这个问题解决后,发现闹铃也有相同的问题,声音会持续一分钟,在此期间即使按下停止键,声音也不会停。发现这个问题后,可以看出,这个问题解决起来比上个问题要简单得多,因为闹钟程序没有涉及到中断服务子程序。因此考虑按下停止键时,修改判断所用的参数比如38H,即在clr P0.7的同时加一句DEC 38H,当再进行判断时,蜂鸣器就不会再响了。
结论
本文介绍的是利用AT89C51单片机设计的有调时、定时、闹铃功能的电子钟。并详细说明了软件和硬件设计方法及仿真、硬件实现。在设计过程中可以看出,汇编语言有着其独特的魅力,它简单易学,语法错误容易纠正;用单片机实现电子钟的设计是比较方便和易于实现的。
通过电子钟的设计和制作,加深了对单片机的理解,能够更熟练地应用单片机实现预期的功能,对今后的工作有很大的帮助。电子钟各项功能的实现,为自动控制的实现打下了理论基础,获得了实现方法。
当然,该电子钟还有很多不足之处,比如闹钟不能关闭,且只能定一个闹钟。在今后的工作中还要对此加以研究,尽量实现更多的功能。
在今后的其他工作中,也可以把这次设计中的收获运用进去,这是我此次毕业设计得到的最大财富。
参考文献
1 H.G.Cragon.The Elements of Single-Chip Microcomputer Architecture. Computer,1980 (13)27~41
2 潘永雄.新编单片机原理与应用. 第2版.西安:西安电子科技大学出版社2006
3 何立民.我国单片机应用技术发展趋势及展望.自动化与仪表,1992(1):1~5
4 向继文,廖立新.基于AT89S51 的电子钟系统设计.机电产品开发与创新,2007(2):62~63
5 张静.基于单片机数字钟的设计.办公自动化杂志,2006(89):4~5 6 樊金荣,谢智文.数字倒计时秒表的设计与实现.中南民族大学计算机科学学院院报,2005(1): 62~63
7 魏立峰,王宝兴.单片机原理与应用技术[M].北京:北京大学出版社,2006. 8 马立国. AD7888与AT89C51单片机接口应用技术.集成电路通讯,2007(25):33~34
9 http://www.elecfans.com/article/88/196/2008/[1**********]7.html 10 Andy Morell. Countdown Timer.Electronics,2003(29):321
11 Mark E.Buccini.Digital countdown timer never needs battery replacement. END,2005 (11):79~80
12 周兴华.一款电路极简的单片机电子钟设计详解.电子制作,2003(10):31 13 郭长立.DDJ-Ⅱ型多功能单片机计时器的改进设计.仪表技术,2004(4):29~30
14 何宏森.多功能智能电子钟的设计.兵工自动化,2005(4):82~84 15 张景元陈平.一种基于单片机的多功能数字钟. 微计算机信息( 嵌入式与SOC)2005 (21):136
16 刘盛雄,周 奇,韦云隆.基于单片机的数字式电子钟的设计与制作.重
庆工学院学报,2006(8):91
17 卢超.基于单片机的数字电子钟的设计与制作.大庆师范学院学报,2006(5):49
18 刘建英.基于单片机的时钟设计.内蒙古石油化工,2005(1):13 19 何宏森.多功能智能电子钟的设计.兵工自动化,2005(4):83
20 蔡希彪,曹洪奎,芳琳.单片机电子时钟系统的设计与仿真.中国科技信息,2007(4):61~63
21 Scott Edwards. Crystal-Controlled Oscillator Is Heartbeat of 60-hour Timer. The Nuts and Volts of BASIC Stamps,1996(1):95~103
致谢
时光荏苒,大学时光转眼逝去,在大学的4年中我不但学到了知识,还认识了很多值得珍惜的老师和同学。在即将离校的日子,我更加珍惜这所剩无几的日子,认真地完成了毕业设计,在这个过程中,张存善老师给了我极大的帮助,不仅是知识上的,更有很多心理上的支持,他引导我在各种杂事比较多的情况下能踏踏实实做点属于自己的工作,让我学会了自主学习。
毕业设计是大学生活中最后阶段的工作,是真正考验我们能力的一项教学内容,在这个过程中我认真思考,不断尝试,收获了很多在平时的课堂上收获不到的东西。毕业设计即将结束,我会吸取毕业设计中的经验和教训,在今后的工作中少走弯路。
夏天即将来临,我们也即将离校,回首过去的日子,大学的确教给了我们很多东西。此刻,我十分感谢母校、感谢老师们对我的教诲。虽然有很多不舍,但我依然会昂首走向新的生活,不辜负老师的培养。
附录A 整体电路图
图附A
附录B 完整程序
HOU_S BIT P2.0;第一个数码管
HOU_G BIT P2.1;第二个数码管
MIN_S BIT P2.2;第三个数码管
MIN_G BIT P2.3;第四个数码管
SEC_S BIT P2.4;第五个数码管
SEC_G BIT P2.5;第六个数码管
DAY EQU 39H;日期
MONTH EQU 3AH;月份
YEAR EQU 3BH;年份
SECOND EQU 30H;秒
MINUTE EQU 31H;分
HOUR EQU 32H;时
TIM_1 EQU 33H; TIM_2 EQU 34H;
ORG 0000H
LJMP CHUSHI ORG 000BH LJMP TIMER0 ORG 30H
CHUSHI:;初始化 MOV SECOND,#0; MOV MINUTE,#0; MOV HOUR,#0;时间的初值为000000
MOV DAY,#1; MOV MONTH,#1; MOV YEAR,#1;日期的初值为000000
SETB HOU_S; SETB HOU_G; SETB MIN_S; SETB MIN_G; SETB SEC_S; SETB SEC_G;初始状态为1,都不显示
MOV R0,#0; MOV R1,#12;闹铃初始化
MOV R3,#0; MOV R4,#1;存储定时时间,点击定时开始后,从所存时间开始倒
计时
MOV R5,#0; MOV R6,#0;设定定时时间所用寄存器
MOV 38H,#12; MOV 37H,#0;存储所定闹铃,以便判断是否闹铃时间到
CLR P0.7; MOV TIM_1,#10;执行完后经历0.5秒
MOV TIM_2,#2;执行完后经历1秒
ANL TMOD,#0F0H ORL TMOD,#01H;定时器0为模式1
MOV TH0,#03CH MOV TL0,#0B0H;装入初值
SETB ET0; SETB TR0; SETB EA;允许中断 MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按
下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
ACALL DISP;调用显示程序
FMQPD:;判断定时是否到零、闹铃时间是否已到
MOV A,HOUR; SUBB A,38H; JZ FEN;判断时是否到闹铃所定时间,若到,则对分进行判断,若不到,则对定时进行判断
AJMP DSPDKQ FEN:
MOV A,MINUTE; SUBB A,37H; JZ SHENGYIN1;时和分都到闹铃时间则蜂鸣器响
DSPDKQ:;判断是否应该进行定时时间的判断
MOV A,3CH;3CH
是引入的判断因子,当其为0时不对定时时间是否到0进行判断,从而不开启蜂鸣器
JNZ DSPD2;当3CH不是0时,跳转到定时判断程序
AJMP MAIN DSPD2: MOV A,R4; JZ S_PD; AJMP MAIN; S_PD: MOV A,R3; JZ SHENGYIN1; AJMP MAIN; DSTZ: AJMP DSTZ1;
DATETZ: AJMP DATETZ1;
SHENGYIN1: MOV 3CH,#1 SETB P0.7 AJMP MAIN ZSTZ1: MOV 35H,#60;
MOV 36H,#10; ZSTZ2: ACALL DISP; DJNZ 35H,ZSTZ2; JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
JNB P3.4,H_T; JNB P3.5,M_T; DJNZ 36H,ZSTZ2; AJMP MAIN; H_T: ACALL DISP; INC HOUR; MOV A,HOUR; CJNE A,#24,ZSTZ1;
MOV HOUR,#0; AJMP ZSTZ1; M_T: ACALL DISP; INC MINUTE; MOV A,MINUTE;
CJNE A,#60,ZSTZ1;
MOV MINUTE,#0; AJMP ZSTZ1; NLTZ1: CLR P0.7; DEC 38H MOV 35H,#100; MOV 36H,#10; NLTZ2: ACALL ONE; ACALL TWO; DJNZ 35H,NLTZ2; JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
JNB P3.4,NLXS2; JNB P3.5,NLXS1; DJNZ 36H,NLTZ2; AJMP MAIN; NLXS1: MOV
DPTR,#LEDTAB;
MOV 35H,#100; MOV 36H,#10; INC R0; MOV 37H,R0; CJNE R0,#60,NLTZ2;
MOV R0,#0; MOV 37H,R0; AJMP NLTZ2; ONE: MOV DPTR,#LEDTAB;
MOV A,R0; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G; ACALL D_1MS; SETB MIN_G; RET;
NLXS2: MOV DPTR,#LEDTAB;
MOV 35H,#60; MOV 36H,#10; INC R1; MOV 38H,R1; CJNE R1,#24,NLTZ2;
MOV R1,#0; MOV 38H,R1; AJMP NLTZ2; TWO: MOV DPTR,#LEDTAB;
MOV A,R1; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR HOU_S; ACALL D_1MS; SETB HOU_S; MOV DPTR,#LEDTAB;
MOV A,B; MOVC A,@A+DPTR;
MOV P1,A;
CLR HOU_G; ACALL D_1MS; SETB HOU_G; RET; DSTZ1: MOV 3CH,#0 CLR P0.7; MOV 35H,#100; MOV 36H,#10; JNB P3.3,DSTZ1; DSTZ2: ACALL DS_S; ACALL DS_M; DJNZ 35H,DSTZ2; JNB
P3.0,DATETZ3;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ;按下2键进行闹铃设置
JNB P3.4,DSXS1; JNB P3.5,DSXS2; JNB P3.3,DSKS1; DJNZ 36H,DSTZ2; AJMP MAIN; DATETZ3:
AJMP DATETZ ZSTZ: AJMP ZSTZ1 NLTZ: AJMP NLTZ1 DSXS1: MOV 35H,#100; MOV 36H,#10; INC R6; CJNE R6,#60,DSTZ2;
MOV R6,#0; AJMP DSTZ2; DS_M:; MOV DPTR,#LEDTAB;
MOV A,R6; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G;
ACALL D_1MS; SETB MIN_G; RET; DSXS2: MOV 35H,#100; MOV 36H,#10; INC R5; CJNE R5,#60,DSTZ2;
MOV R5,#0; AJMP DSTZ2; DS_S: MOV DPTR,#LEDTAB;
MOV A,R5; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_S; ACALL D_1MS; SETB SEC_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_G; ACALL D_1MS; SETB SEC_G;
DSKS1: MOV 3CH,#1 MOV A,R5; MOV R3,A; MOV A,R6; MOV R4,A; DSKS2: MOV DPTR,#LEDTAB;
MOV A,R3; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_S; ACALL D_1MS; SETB SEC_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_G; ACALL D_1MS; SETB SEC_G; MOV A,R4; MOV B,#10; DIV AB; MOVC
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G; ACALL D_1MS; SETB MIN_G; JNB P3.0,MAIN2; JNB P3.1,MAIN2; DSPD:; MOV A,R4; JZ PANDUAN_S; AJMP DSKS2; PANDUAN_S:; MOV A,R3; JZ SHENGYIN; AJMP DSKS2; MAIN2: LJMP MAIN;
SHENGYIN: MOV 3CH,#1 SETB P0.7 AJMP MAIN
RETI_11:;由于程序较长,此处加一个返回程序,避免跳转距离过长
POP PSW; POP ACC; RETI; ;中断服务程序 TIMER0: PUSH ACC; PUSH PSW; MOV A,#0B0H; ADD A,TL0; MOV TL0,A; MOV TH0,#03CH; DJNZ TIM_1,RETI_11;
MOV TIM_1,#10; DJNZ TIM_2,RETI_11;
MOV TIM_2,#2; INC SECOND; MOV A,SECOND; CJNE R3,#0,RETI_2;
MOV R3,#60; DEC R4; RETI_2: DEC R3;
A,#60,RETI_11;
MOV SECOND,#0; INC MINUTE; MOV A,MINUTE; RETI_3: CJNE A,#60,RETI_11;
MOV MINUTE,#0; MOV SECOND,#0; INC HOUR; MOV A,HOUR; CJNE A,#24,RETI_11;
MOV HOUR,#0; MOV MINUTE,#0; MOV SECOND,#0; T_YEARPD: MOV A,YEAR; MOV B,#100; DIV AB; MOV A,B; JZ T_YEARPD2;看年份是否能被100整除,若能,再进行额外判断
MOV A,YEAR;不能被100整除,则判断是否能被4整除
MOV B,#4; DIV AB;
JZ T_RUNYEAR;若年份能被4整除则跳转到闰年部分
T_PINGYEAR:;年份不能被4整除则为平年
MOV A,MONTH; CJNE
A,#2,T_PINGMONTH;若不是2月,则跳转到平时的月份进行判断
INC DAY; MOV A,DAY; CJNE A,#29,RETI_11;
MOV DAY,#1; INC MONTH; MOV A,MONTH; CJNE A,#13,RETI_11;
MOV MONTH,#1; INC YEAR; AJMP RETI_1;返回 T_YEARPD2:;能被100整除的情况下,的额外判断
MOV A,YEAR; MOV B,#100; DIV AB;
DIV AB
JNZ T_PINGYEAR;若不能被400整除则为平年
T_RUNYEAR:;闰年的情况
MOV A,MONTH; CJNE
A,#2,T_PINGMONTH;看是不是2月
INC DAY; MOV A,DAY; CJNE A,#30,RETI_1;
MOV DAY,#1; INC MONTH; MOV A,MONTH; CJNE A,#13,RETI_1;
MOV MONTH,#1; INC YEAR; AJMP RETI_1; T_PINGMONTH: MOV
A,MONTH
ADD A,#2 SUBB A,#3;判断是
不是一月
JZ T_DAY31;若是一月调用一个月31天的程序段
MOV A,MONTH; SUBB A,#3; JZ T_DAY31; MOV A,MONTH; SUBB A,#4; JZ T_DAY30;调用一个月30天的程序段
MOV A,MONTH SUBB A,#5 JZ T_DAY31 MOV A,MONTH SUBB A,#6 JZ T_DAY30 MOV A,MONTH SUBB A,#7 JZ T_DAY31 MOV A,MONTH SUBB A,#8 JZ T_DAY31 MOV A,MONTH SUBB A,#9 JZ T_DAY30 MOV A,MONTH SUBB A,#10 JZ T_DAY31 MOV A,MONTH
SUBB A,#11 JZ T_DAY30 MOV A,MONTH SUBB A,#12 JZ T_DAY31 RETI_1: POP PSW POP ACC RETI;中断返回 T_DAY31:;当一个月为31天时的日期计算方法
INC DAY MOV A,DAY CJNE A,#32,RETI_1
MOV DAY,#1 INC MONTH MOV A,MONTH CJNE A,#13,RETI_1
MOV MONTH,#1 INC YEAR AJMP RETI_1 T_DAY30:;当一个月为30天时的日期计算方法
INC DAY MOV A,DAY CJNE
42
A,#31,RETI_1
MOV DAY,#1 INC MONTH MOV A,MONTH CJNE A,#13,RETI_1
MOV MONTH,#1 INC YEAR AJMP RETI_1
DISP:;走时的显示程序,包括调时时的显示
MOV DPTR,#LEDTAB
MOV A,SECOND MOV B,#10 DIV AB;A存十位B存个位
MOVC A,@A+DPTR
MOV P1,A CLR SEC_S ACALL D_1MS;显示秒十位
SETB SEC_S MOV A,B MOVC A,@A+DPTR
MOV P1,A
CLR SEC_G ACALL D_1MS;显示秒个位
SETB SEC_G MOV A,MINUTE MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR MIN_S ACALL D_1MS SETB MIN_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR MIN_G ACALL D_1MS SETB MIN_G MOV A,HOUR MOV B,#10 DIV AB MOV DPTR,#LEDTAB
MOVC A,@A+DPTR
MOV P1,A CLR HOU_S ACALL D_1MS
SETB HOU_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR HOU_G ACALL D_1MS SETB HOU_G RET
DATEDISP:;日期的显示程序,包括日期调整时的显示
MOV DPTR,#LEDTAB
MOV A,DAY MOV B,#10 DIV AB;A存十位B存个位
MOVC A,@A+DPTR
MOV P1,A CLR SEC_S ACALL D_1MS SETB SEC_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR SEC_G
43
ACALL D_1MS SETB SEC_G MOV A,MONTH MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR MIN_S ACALL D_1MS SETB MIN_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR MIN_G ACALL D_1MS SETB MIN_G MOV A,YEAR MOV B,#100 DIV AB MOV A,B MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR HOU_S ACALL D_1MS SETB HOU_S
MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR HOU_G ACALL D_1MS SETB HOU_G RET
DATETZ1:;日期调整程序
MOV 35H,#100 DATETZ2: ACALL DATEDISP DJNZ 35H,DATETZ2
JNB P3.3,YEAR_T JNB P3.4,MONTH_T
JNB P3.5,DAY_T JNB P3.1,MAIN3 AJMP DATETZ1 MAIN3: AJMP MAIN
YEAR_T:;年的调整很容易;直接加1
ACALL DATEDISP INC YEAR
AJMP DATETZ1 MONTH_T:;月的调整也很容易,加到13时月变为1
ACALL DATEDISP INC MONTH MOV A,MONTH CJNE A,#13,DATETZ1
MOV MONTH,#1 AJMP DATETZ1 DAY_T:;日期的调整需要判断是不是闰年,还要判断当月具体是哪个月
YEARPD: MOV A,YEAR MOV B,#100 DIV AB MOV A,B JZ YEARPD2;看年份是否能被100整除,若能,再进行额外判断
MOV A,YEAR;不能被100整除,则判断是否能被4整除
MOV B,#4 DIV AB MOV A,B
44
JZ RUNYEAR;若年份能被4整除则跳转到闰年部分
PINGYEAR:;年份不能被4整除则为平年
MOV A,MONTH CJNE
A,#2,PINGMONTH;若不是2月,则跳转到平时的月份进行判断
INC DAY MOV A,DAY CLR C SUBB A,#29 JC DATETZ1 MOV DAY,#1 AJMP DATETZ1;返回扫描
YEARPD2:;能被100整除的情况下,的额外判断
MOV A,YEAR MOV B,#100 DIV AB MOV B,#4 DIV AB
JNZ PINGYEAR;若不能被400整除则为平年
RUNYEAR:;闰年的情况
MOV A,MONTH CJNE
A,#2,PINGMONTH;看是不是2月
INC DAY MOV A,DAY CLR C SUBB A,#30 JC DATETZ1 MOV DAY,#1 AJMP DATETZ1 PINGMONTH:MOV A,MONTH
ADD A,#2 SUBB A,#3;判断是不是一月
JZ DAY31;若是一月调用一个月31天的程序段
MOV A,MONTH SUBB A,#3 JZ DAY31 MOV A,MONTH SUBB A,#4 JZ DAY30;调用一个月30天的程序段
MOV A,MONTH SUBB A,#5
JZ DAY31 MOV A,MONTH SUBB A,#6 JZ DAY30 MOV A,MONTH SUBB A,#7 JZ DAY31 MOV A,MONTH SUBB A,#8 JZ DAY31 MOV A,MONTH SUBB A,#9 JZ DAY30 MOV A,MONTH SUBB A,#10 JZ DAY31 MOV A,MONTH SUBB A,#11 JZ DAY30 MOV A,MONTH SUBB A,#12 JZ DAY31 DAY30: INC DAY MOV A,DAY CLR C SUBB A,#31 JC DATETZ11 MOV DAY,#1 AJMP DATETZ1
45
DAY31: INC DAY MOV A,DAY CLR C SUBB A,#32 JC DATETZ11 MOV DAY,#1 AJMP DATETZ1 DATETZ11: AJMP DATETZ1 D_1MS: MOV R7,#2 D_5: MOV R2,#250 DJNZ R2,$ DJNZ R7,D_5 RET
LEDTAB: DB
7EH,30H,6DH,79H,33H,5BH,5FH,70H,7FH,7BH
END
郑州科技学院
专科毕业设计(论文)
题 目 ____________________
____________________
学生姓名
专业班级
学 号
所 在 系
指导教师
完成时间 年 月
日
目 录
1 引言............................................................. 1
2 整体设计思路..................................................... 3
3 主要元件的使用方法............................................... 4
3.1 AT89C51单片机: ................................................ 4
3.2 7407驱动器: ................................................... 5
3.3数码管: ........................................................ 6
4 电路设计......................................................... 7
4.1整体设计 ........................................................ 7
4.2 分块设计........................................................ 7
4.2.1 输入部分..................................................... 7
4.2.2 输出部分(显示电路)......................................... 8
4.2.3 晶振与复位电路:............................................. 9
5 程序设计......................................................... 9
5.1程序思路 ........................................................ 9
5.2程序设计步骤 ................................................... 10
5.3程序的主要模块 ................................................. 11
5.3.1延迟程序 ..................................................... 11
5.3.2 中断服务子程序:............................................. 11
5.3.3 主程序....................................................... 13
5.3.4显示程序 ..................................................... 13
5.3.5 闹铃程序和定时程序........................................... 14
5.4程序调试 ....................................................... 14
6 功能仿真........................................................ 15
6.1 软件介绍....................................................... 15
6.1.1PROTEUS....................................................... 15
6.1.2MedWin........................................................ 15
6.2仿真过程: ..................................................... 16
6.2.1仿真图的绘制 ................................................. 16
6.2.2功能的实现 ................................................... 17
7 实际电路的实现.................................................. 18
8 日历功能的实现.................................................. 20
9 电子钟设计中遇到的问题及其解决方法.............................. 23
结论............................................................... 25
参考文献........................................................... 26
致谢............................................................... 28
附录A 整体电路图 .................................................. 29
附录B 完整程序 .................................................... 30
1 引言
单片机因将其主要组成部分集成在一个芯片上而得名,就是把中央处理器、随机存储器、只读存储器、中断系统、定时器/计数器以及I/O接口电路等部件集成在一个芯片上[1]。
单片机自20世纪70年代问世以来,以其极高的性能价格比,受到人们的重视和关注,应用很广、发展很快。单片机具有体积小、功能多、价格低廉、使用方便、系统设计灵活等优点[2]。因此,它应用广泛前景美好,它的实用性大大地提高了我对毕业设计的兴趣。
在我国,单片机的开发应用已有15年左右,已经形成一支庞大的技术开发队伍,为我国单片机应用积累了丰富的经验。随着电子技术、计算机芯片技术和微电子技术的飞速发展促进了单片机技术一日千里的变化[3]。
随着半导体技术的飞速发展,以及移动通信、网络技术、多媒体技术在嵌入式系统设计中的应用,单片机从4位、8位、16位到32位,其发展历程一直受到广大电子爱好者的极大关注。单片机功能越来越强大,价格却不断下降的优势无疑成为嵌入式系统方案设计的首选,同时单片机应用领域的扩大也使得更多人加入到基于单片机系统的开发行列中,推动着单片机技术的创新进步。
然而传统的单片机系统开发除了需要购置诸如仿真器、编程器、示波器等价格不菲的电子设备外,开发过程也较繁琐。来自英国Labcenter Electronics公司的Proteus软件很好地诠释了利用现代EDA工具方便快捷开发单片机系统的优势。它包括PROTEUS VSM(Virtual System Modelling)、PROTEUS PCB DESIGN两大组成部分,在PC机上就能实现原理图电路设计、电路分析与仿真、单片机代码级调试与仿真、系统测试与功能验证以及形成PCB文件的完整嵌入式系统设计与研发过程。
单片机系统作为一种典型的嵌入式系统,其系统设计包括硬件电路设计和软件编程设计两个方面, 其调试过程一般分为软件调试、硬件测试、系统调试3个过程。如果采用单片机系统的虚拟仿真软件——Proteus,则不用制作具体的电路板也能够完成以上工作。
数字钟是采用数字电路实现对时,分,秒,数字显示的计时装置,由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得数字钟的精度,远远超过老式钟表,钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表的报时功能。数字钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、码头、剧院、办公室等场所,给人们的生活、学习、工作带来极大的方便[4]。不仅如此,在现代化的进程中,也离不开电子钟的相关功能和原理,比如机械手的控制、家务的自动化、定时自动报警、按时自动打铃、时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备、甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。而且是控制的核心部分。因此,研究数字钟及扩大其应用,有着非常现实的意义。
电子钟在工业控制和日常生活中是很重要的,它不仅可以用于计时、提醒又可用于对机器的控制,在自动化的过程中必然有电子钟的参与,因此电子钟的应用会越来越广泛。而且向着精确、低功耗、多功能发展。基于单片机设计的数字钟精确度较高, 因为在程序的执行过程中, 任何指令都不影响定时器的正常计数,即便程序很长也不会影响中断的时间。从而,使数字钟的精度仅仅取决于单片机的产生机器周期电路和定时器硬件电路的精确度。另外,程序较为简洁,具有可靠性和较好的可读性。如果我们想将它应用于实时控制之中,只要对上述程序和硬件电路稍加修改,便可以得到实时控制的实用系统,从而应用到实际工作与生产中去。
数字电子钟的设计方法有多种,例如,可用中小规模集成电路组成电子钟, 也可以利用专用的电子钟芯片配以显示电路及其所需要的外围电路组成电子钟还可以利用单片机来实现电子钟等等。这些方法都各有特点, 其中,利用单片机实现的电子钟具有编程灵活, 便于功能扩充, 精确度高等特点[5]。
基于以上分析,在此次设计中,我选择的是利用单片机制作电子钟。电子钟的设计本身包括程序的设计和硬件电路的设计[6]。我的思路是,先进行电路的整体设计,再根据电路进行编程,在编程的过程中,对电路进行微调,以更好地配合程序。在设计完成后,进行程序调试,调试软件选择MedWin,调试成功后,再根据电路图画出仿真图,将软件装入单片机芯片,利用Proteus软件进行仿真,仿真中的错误通过改正程序中的逻辑错误和电路中的设计不当进行排除,这个过
程是很艰难的但也是很重要的。若仿真可以实现,则硬件电路的实现就可以有条不紊地进行。
2 整体设计思路
这部分主要介绍工作安排和整体设计的思想。工作过程规划如下:
图2.1 整体设计思路
针对要实现的功能,拟采用AT89C51单片机进行设计,AT89C51 单片机是一款低功耗,高性能CMOS8位单片机,片内含4KB在线可编程(ISP)的可反复擦写1000次的Flash只读程序存储器,器件采用高密度、非易失性存储技术制造,
兼容标准MCS- 51指令系统及80C51引脚结构[7]。这样,既能做到经济合理又能实现预期的功能。
在程序方面,采用分块设计的方法,这样既减小了编程难度、使程序易于理解,又能便于添加各项功能。程序可分为闹钟的声音程序、显示程序、闹钟显示程序、调时显示、定时程序。运用这种方法,关键在于各模块的兼容和配合,若各模块不匹配会出现意想不到的错误。
本电子钟设计主要是依照图2.1中的流程做出来的,时间分配比较均匀。首先,在编程之前必须了解硬件结构尤其是各引脚的用法,以及内部寄存器、存储单元的用法,否则,编程无从下手,电路也无法设计。这是前期准备工作。第二部分是硬件部分:依据想要的功能分块设计设计,比如输入需要开关电路,输出需要显示驱动电路和数码管电路等。第三部分是软件部分:先学习理解汇编语言的编程方法再根据设计的硬件电路进行分块的编程调试,最终完成程序设计。第四部分是软件画图部分:设计好电路后进行画图,包括电路图和仿真图的绘制。第五部分是软件仿真部分:软硬件设计好后将软件载入芯片中进行仿真,仿真无法完成时检查软件程序和硬件电路并进行修改直到仿真成功。第六部分是硬件实现部分:连接电路并导入程序检查电路,若与设计的完全一样一般能实现想要的功能。最后进行功能扩展,本设计加进了日期显示与调整功能。
3 主要元件的使用方法
下面就本次设计中用到的主要元件的所有功能进行简单的介绍,包括AT89C51单片机、74LS07芯片、以及数码管的特性和用法。
3.1 AT89C51单片机[8]:
该单片机功能强大,不仅能满足设计的需要,也可以在设计要求的基础上进行一些扩展。
单片机的结构如下:
图3.1.1 单片机引脚图
在使用时VCC接电源电压,GND接地。P0,P1,P2,P3可作为输入或输出端口,RST是复位输入,接复位电路。XTAL1和XTAL2接复位电路。这些可以在硬件设计部分体现出来。
3.2 7407驱动器[9]:
7407是集电极开路六正相高压驱动器,1入2出,3进4出,5进6出,9进8出,11进10出,13进12出,7接地,14接高电平。
7407引脚图:
图3.2.1 7407引脚图
7407逻辑图:
图3.2.2 7407逻辑图
3.3数码管:
图3.3.1 数码管
使用共阴极数码管时将6个数码管按相同功能连接起来,3与8相连,当选通端所接管脚为低电平时该数码管选通。
单片机的P2口作为选通端,连接各数码管的3、8引脚轮流显示,连接时要加7407和上拉电阻。
单片机的P1口作为功能段,通高电平的引脚会使相应段亮起,同样的也要与7407和电阻连接使用。
4 电路设计
4.1整体设计
此次设计主要是应用单片机来设计电子时钟,硬件部分主要分以下电路模块:显示电路用六个数码管分别显示小时(年份)、分钟(月份)和秒(日),通过动态扫描进行显示,从而避免了译码器的使用,使电路更加简单。单片机采用AT89C51系列,这种单片机应用简单,适合电子钟设计。
电路的总体设计框架如下:
图4.1.1 电路模块图
4.2 分块设计
这部分介绍各模块电路的设计方法和成果,主要分为:输入部分、输出部分、复位和晶振电路。 4.2.1 输入部分
在电子钟的输入部分,设置相应的置数功能,通过外部设备的输入,如按键,实现时间的修改[10-11]。除此之外,调整闹铃、定时、日期时也需要按键进行输入。在选用输入端口时,将P3引脚与按键相连进行输入[12]。
设计的输入部分如下:
图4.2.1 输入部分
各按键功能在后面的部分将会介绍到 4.2.2 输出部分(显示电路)
该部分电路图如下所示:
图4.2.2 显示部分
在实际电路中采用单个数码管相连进行显示,先把数码管的1、2、4、5、6、7、9、10对应相连,然后把各晶体管的3和8引脚各自相连,P1.6~P1.0分别接a~g,P2作为选通端P2.0~P2.5分别从左到右接各数码管的3、8端。采用动态显示, 即一位一位地轮流点亮各位显示器[18],因此P2.0~P2.5轮流置0。持续时间为1ms,这点在程序部分还会讲到。
4.2.3 晶振与复位电路:
图4.2.3 晶振与复位电路
5 程序设计
5.1程序思路
图5.1.1 程序设计思路
结合电路,程序的总体思路是[17]:
1、点复位键后,进行时间显示,从0时0分0秒开始。
2、按下按键1时,进行调时,此时按下4调整时,按下5调整分,若2秒钟未按键,则不再等待,恢复走时,持续按键时大约0.3秒步进1,下同。
3、按下2键时进行闹铃调整,用4、5键分别调时和分,此时只有前四位进行显示,即闹铃功能精确到分,2秒钟无按键则返回时间显示,时间到达闹铃所定时间时P0.7输出高电平,蜂鸣器响,按下按键2或3时蜂鸣器停止。
4、按3键时进行定时的设定,同样,分别通过4、5调整分和秒,若两秒未按键则不进行定时,设定之后再次按下3键则进行倒计时,倒计时时间未到时若按下1键则进行时间显示;若倒计时时间到则P0.7为高电平,蜂鸣器响。定时的最大值为59分59秒。
在程序设计时,尽量改进算法,算法的改进可以使相对误差减小[12],或者可以使占用空间减小[14]。另外,分块的设计思想要贯穿始终,整个程序较为繁杂,某些程序段会反复用到,因此采取的方法是写出多个程序段,通过跳转指令进行调用。
5.2程序设计步骤
在程序设计过程中,我遇到了很多困难,这部分也是让我学到很多东西的地方。
首先,我学习了定时器的相关知识,计数器的使用是很重要的组成部分[15],在这个设计中选择计数器T0。T0的工作方式有:
方式0:不推荐
方式1:16位计数器,常用
方式2:自动重装初值的8位定时/计数器 方式3:T0相当于两个独立的8位定时/计数器
此程序采用方式1,方式1的定时时间t为t=(216-M)*12/fosc。其中M为定时器初值,fosc为12MHz,若M为0则t=65536*12/2*106=65.536ms。因此可取50ms为计时单位[16],初值M应为50*10-3*106=216-M。M=15536=[1**********]000=3CB0。即定时器初值为TH0=03CH,TL0=0B0H。定时器中断20次为一秒,这部分在中
断程序中用到。
其次,我参看了文献中的设计思路,做到胸有成竹后再进行具体的程序书写工作。认真学习了教科书中关于汇编语言编程的问题,熟悉了汇编语言的编程方法和语法习惯。
第三步就是进行具体的程序编写工作。
5.3程序的主要模块
5.3.1延迟程序
在动态扫描时,必然用到延迟程序,这里使用延迟1ms的程序,此程序需要反复调用。此段程序是很简单的,但就是在这段简单的程序上,也会出现问题,若用
D_1MS: MOV R7,#500 DJNZ R7,$ RET
则会出现警告,因为R7是8位寄存器,所能存储的最大值应为255,所以应改为:
D_1MS: MOV R7,#2 D_5: MOV R2,#250 DJNZ R2,$ DJNZ R7,D_5 RET
5.3.2 中断服务子程序:
中断服务程序中,总体思路是:由于初值是3CB0H,所以装满定时器需要50ms的时间,从而20次中断为一秒,一秒之后,判断是否到60秒,若不到则秒加一,然后返回,若到,则秒赋值为0,分加一,依次类推。包括日期显示的功
能也是如此。另外,由于要实现倒计时功能,因此在中断程序中还要加入减一的寄存器,需要时将其进行显示。基于以上考虑,以R3为倒计时中的秒,R4为倒计时的分,当秒加1时R3减一,减到0之后,秒赋值为59,分减一,直到分为0。再显示走时部分。
流程框图如下:
图5.3.1 中断程序思路
5.3.3 主程序
主程序主要对按键进行扫描,以及判断定时和闹铃时间是否已到,若到则调用声音程序,该段程序如下:
MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整 JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时 JNB P3.2,NLTZ1;按下2键进行闹铃设置 JNB P3.3,DSTZ;按下3键进行定时设置 ACALL DISP; MOV A, HOUR; SUBB A, 38H; JZ FEN; AJMP DSPD2; FEN:
MOV A, MINUTE; SUBB A, 37H; JZ SHENGYIN1; DSPD2: MOV A, R4; JZ S_PD; AJMP MAIN; S_PD: MOV A, R3; JZ SHENGYIN1; AJMP MAIN; 5.3.4显示程序
6个晶体管轮流进行显示,分别显示1ms,这依赖的是人们视觉的惰性,该段程序如下:
DISP:;走时的显示程序,包括调时时的显示 MOV DPTR,#LEDTAB MOV A,SECOND MOV B,#10
DIV AB;A存十位B存个位 MOVC A,@A+DPTR MOV P1,A CLR SEC_S
ACALL D_1MS;显示秒十位 SETB SEC_S MOV A,B
MOVC A,@A+DPTR MOV P1,A CLR SEC_G
ACALL D_1MS;显示秒个位 SETB SEC_G „„
以此类推,进行时和分的显示 RET
另外,调闹铃和定时时间、进行日期显示时,有各自的显示程序,但不能成为独立子程序,分别柔和在闹铃、定时、和日期程序中。 5.3.5 闹铃程序和定时程序
这两段程序分别包含了各自的显示、调整程序。程序思路是对照,走时部分的程序,进行编写,包括显示程序,与显示时间的程序是相似的,闹铃和定时的调整程序与走时调整程序相似。
5.4程序调试
程序写完以后必须进行调试,以验证程序是否正确。在程序调试时,出现了很多问题,比如跳转距离过长、打错字母、逻辑有错等,发现问题后,利用两天
时间进行了改正,但即使编译通过,最后也不一定能够实现功能。以为程序的调试只能检查出语法错误,而不能检查出逻辑的错误。要真正把程序写对,要通过仿真发现并且改正错误。
6 功能仿真
这部分工作可能遇到的困难是很多的,程序庞大很可能出现各种问题。在仿真工作中,首先要对仿真软件有足够的了解并能够正确熟练地运用
6.1 软件介绍
在这部分工作中用到了medwin3和Proteus两个软件,其中Medwin3用来编译程序并生成hex文件,装入Proteus仿真图的芯片中,通过仿真结果一步步进行调整最后达到预期的功能。 6.1.1PROTEUS
PROTEUS软件是目前世界上最先进、最完整的嵌入式系统设计与仿真平台,可以实现数字电路、模拟电路及微控制器系统与外设的混合电路系统的电路仿真、软件仿真、系统协同仿真和PCB设计等功能,是目前唯一能够对各种处理器进行实时仿真、调试与测试的EDA工具。微控制器系统相关的仿真需建立编译和调试环境,可选择MedWin V3 软件。该软件支持众多不同公司的芯片,集编辑、编译和程序仿真等于一体,同时还支汇编和C语言的程序设计。Proteus的界面友好易学,在调试程序、软件仿真方面有很强大的功能。 其革命性的功能是:将电路仿真和微处理器仿真进行协同,直接在基于原理图的虚拟原型上进行处理器编程调试,并进行功能验证,通过动态器件如电机、LED、LCD、开关等,实时看到运行后的输入、输出的效果。Proteus为我们建立了完备的电子设计开发环境。 6.1.2MedWin
MedWin可以用来编写汇编语言程序并进行编译、产生代码并装入仿真器以便于仿真,在输出文件夹中会产生hex文件,将该hex文件导入仿真图的单片机芯片中即可进行仿真。
使用时点击“项目管理—新建项目”就可以建立编程的平台,然后选择项目管理中的新建文件就可以建立asm文件,在这个文件中可以进行程序的编写,程序编写完毕后可点击“项目管理—编译\汇编”看其是否有错,有错时,在下面的窗口会提示出错的行以及错误原因。改正无误后可产生代码并装入,将hex文件导入单片机中即可进行仿真
6.2仿真过程:
通常在仿真过程中会遇到很大的麻烦。在程序汇编通过之后程序不一定是正确的,比如我刚开始进行仿真时数码管并不进行显示,结果发现应该是置零的置一了,应该置一的置零了。改正之后发现虽然走时程序正常了,但是调时中出现了大量的问题,更不要说闹铃和定时程序了。在整个毕业设计的过程中程序的修改贯穿始终,在修改的过程中一定要条理清晰,认真细心。
6.2.1仿真图的绘制
在使用Proteus进行仿真时,仿真图不用画出数码管驱动程序,其他部分与设计的硬件图相仿。绘制结果如下:
图6.2.1 仿真图
6.2.2功能的实现
在绘制仿真图之后,要向单片机装入程序,从而使单片机开始工作并带动整个电路工作,装入过程为:点击单片机,选择所编译程序的输出hex文件,确定即可。此时单片机会按照程序所设定的功能进行工作,在仿真过程中会遇到各种问题,在第九章会具体讲到。这里列出仿真结果:
(1)走时仿真:
图6.2.2 走时状态下的仿真结果
(2)闹钟设定的仿真:
图6.2.3 闹铃仿真结果
可见所定闹钟时间为10点15分。
(3)定时钟倒计时的仿真:
图6.2.3 倒计时仿真
可见,倒计时进行到3分3秒。
7 实际电路的实现
在仿真无误后,开始进行实际电路的搭接。搭接时先不用芯片实物,而用仿真器替代。按照电路图,先把数码管按照对应的管脚连接起来,然后接驱动电路等,接好之后把程序装入仿真器,通电运行,再对电路进行调试。
在根据电路图搭接好各个器件后,一个很重要的问题就是检查各器件是否完全工作。下面介绍检验方法:
导线看似不用太费力气去检验,但一个成功的实验需要前期充分的准备,比如在我的实验过程中,由于导线繁多,而且使用旧导线进行实际电路的连接,所以就出现了导线不通的情况,因此验证过程中不要放过小问题。
数码管的检测:拆除89C51芯片,先分别给芯片P2对应的导线加低电平,再分别给P1对应的导线加高电平,使每个数码管的每一笔段都能亮。若出错,先检查电路的连接再换一下器件试试,对于此电路问题出在7407的连接方法的问题比
较大。这部分需要重点验证。
随后,按下复位键看9引脚是否为低电平,是则没有错误。
通过以上工作,硬件仿真无误后,可以用单片机芯片代替仿真器进行最后的实现工作,用easyPRO80B编程器将程序下载到芯片中,具体步骤为:先进行擦除,然后查空,查空无误后打开所需的hex文件,然后进行编程、校验。这时程序载入了芯片中,就可以实现相应的功能了。
实验结果如下:
图7.1 走时显示实物图
这里要说的是,软件仿真成功和硬件电路实现之间是有很大差别的,在做软件仿真时,没有驱动的问题,没有芯片和器件质量的问题,也没有电线导电的问题,没有工作条件的问题,但在实际电路中这些因素都要考虑。常常会出现这种情况:软件仿真实现了,但实际电路没有任何功能。在电子钟硬件实现过程中,
就出现了很多问题,有引脚接错的问题,也有插线松动或电线不通的问题,这些问题都是需要耐心和细心认真解决的。
8 日历功能的实现
在加入其它功能时,我想到了很多可能达到的功能,比如加入备用电源、夜间亮灯功能、多个闹铃的功能、显示日期功能等。然后我进行了理论上的验证,加入备用电源可避免因停电而造成的电路全部失灵[20,21],但受到实验条件的影响未选择对这个功能进行实现。夜间亮灯功能对程序要求不高,但在电路中要加入传感器,把光的照度测出来后,低于某一值时,灯亮,从而使得夜间时也能看到时间显示,虽然程序简单,但由于要加入传感器,容易受到干扰,各项工作投入时间较长,考虑到时间有限,也没有采纳这个方案。闹铃的功能和日期的功能的实现都是比较容易的,做了权衡之后我选择了后者,因为日期功能主要涉及算法和程序的跳转、调用等,更能加深对单片机的认识和理解。
在设计的开始阶段,我主要考虑了日期的逻辑算法[19]。首先,要考虑年份是不是闰年,闰年的判断方法是:将年份除以100,若能整除,则将年份除以400,若还能整除,则为闰年,若不能,则为平年;若不能被100整除,则判断是否能被4整除,若能,则为闰年,若不能则为平年。只有2月与平、闰年相关,因此在闰年和平年的子程序中,要判断是不是2月,若是则在相应的年中进行日期的增加,若不是则转入平时的月份。其中1、3、5、7、8、10、12月是每月31天,4、6、9、11月为每月30天。
在电路方面有两种方法:(1)可以增加6个数码管用来显示日期,但这样显然电路更复杂;(2)用按键的输入决定6个数码管显示日期还是时间,这种情况下,只需加一个按键即可,不用增加数码管。最终的按键控制为:按下1键时,显示日期,并且用4、5、6键分别调整年、月、日;按下2键时,进行走时和时间调整;3键位闹铃键;4键为定时键。
这样实现功能的好处是:(1)电路简单,若同时显示日期和时间,则需要的引脚很多,需要加入译码器对引脚进行扩展。采用按键决定显示时间或日期的方法避免了这个问题;(2)节约空间,节约成本。
程序思路如下:
图8.1 扩展部分思路
由于在前面的工作中积累了较多的经验,对汇编语言已经相当熟悉,因此在实现日历功能时,程序设计显得相当容易。
按键如图8.2所示,按键功能如下:
按下按键1时,显示日期并且允许对日期进行调整;
按下按键2时,显示时间并且允许对时间进行调整;
按下按键3时,显示闹钟所设定的时间并允许通过5、6键对闹钟进行设定; 按下按键4时,显示定时功能所设定的时间并允许对其进行设定,再次按下时,开始倒计时过程,并进行倒计时过程的显示,在显示日期时,该键可对年份进行调整;
按键5、6可对时间显示时的时、分或日期显示时的月、日进行调整。
按键形式:
图8.2 按键图示
实验成果如下:
图8.2 日期显示实物图
图中显示的日期为10年5月27日。
9 电子钟设计中遇到的问题及其解决方法
在电子钟设计中程序比较长,遇到了各种各样的问题,比如跳转距离过长出现语法错误。因此修改程序的时间很长,有语法错误,也有仿真时功能无法实现的问题,在此不能一一说明,只能对个别问题加以阐述。
由于在走时调整、闹铃调整及定时设定时,按下键时每0.2秒步进1,这就需要每0.2秒对按键输入进行一次扫描,因此开始时,我用的是延迟0.2秒再返回按键扫描程序的方法,但是可以想到,进行单纯的延迟时,不会有显示,在仿真时功能没有实现。后来我采用的是反复调用若干次显示程序以实现延迟,较好地解决了这个问题。虽然现在回过头来发现这个问题很简单,但当时是百思不得其解。我从中学到:任何简单的事情都会有出错的可能,有些时候人的思路中的一些错误是自己难以发现的,在工作和生活中要多对自己的想法提出质疑。
不光是这种明显的问题很多,有些细微的问题也一样出现了,但解决起来并不容易。
在最后的硬件实现阶段发现蜂鸣器不响,此时连接方法是蜂鸣器直接连接在了P0.7引脚。考虑到单片机的输出电流比较小,虽然P0.7引脚的电平已经达到2V以上,也无法驱动蜂鸣器。于是我设想加上驱动电路。
作此修改之后,蜂鸣器发出响声,但是又遇到了新的问题:蜂鸣器无法停止响声!看上去这个问题很简单,只要有停止闹铃的按键输入时,在程序中加一句将P0.7置零的语句就可以了。但事实并不是这么简单。通过苦思冥想,发现在主程序中,对“定时时间是否已到”是不断进行扫描的,而倒计时是在中断服务子程序中进行的,当倒计时为0分0秒时,主程序判断出来后会不停地调用声音程序:
MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
ACALL DISP;
MOV A,HOUR;
SUBB A,38H;
JZ FEN;
AJMP DSPD2;
FEN:
MOV A,MINUTE;
SUBB A,37H;
JZ SHENGYIN1;
DSPD2:
MOV A,R4;
JZ S_PD;
AJMP MAIN;
S_PD:
MOV A,R3;
JZ SHENGYIN1;
AJMP MAIN;
蜂鸣器响声不停是不可避免的,因为R3和R4是在中断程序中变化的,随着时间的推移必然都为0,在此情况下即使按下了声音停止键,由于程序跳回主程序,又会不断地调用声音程序。基于这个想法要达到的效果是:按下声音停止键之后,不再进行定时时间是否为0的判断。要实现这个想法就要引入新的参数,这里,试用3CH作为判断的因子。当点击定时开始后,将3CH赋值为1,在主程序中判断3CH如果不为0,就进行倒计时是否到0的判断。蜂鸣器响后,点击3键时,将3CH赋值为0,这样在主程序中就不进行这个判断,因此蜂鸣器就不会响。
当然这个解决问题的过程不是一下子解决的在这个过程中,我进行了相当多的尝试和摸索,最终找到了这个解决途径。
这个问题解决后,发现闹铃也有相同的问题,声音会持续一分钟,在此期间即使按下停止键,声音也不会停。发现这个问题后,可以看出,这个问题解决起来比上个问题要简单得多,因为闹钟程序没有涉及到中断服务子程序。因此考虑按下停止键时,修改判断所用的参数比如38H,即在clr P0.7的同时加一句DEC 38H,当再进行判断时,蜂鸣器就不会再响了。
结论
本文介绍的是利用AT89C51单片机设计的有调时、定时、闹铃功能的电子钟。并详细说明了软件和硬件设计方法及仿真、硬件实现。在设计过程中可以看出,汇编语言有着其独特的魅力,它简单易学,语法错误容易纠正;用单片机实现电子钟的设计是比较方便和易于实现的。
通过电子钟的设计和制作,加深了对单片机的理解,能够更熟练地应用单片机实现预期的功能,对今后的工作有很大的帮助。电子钟各项功能的实现,为自动控制的实现打下了理论基础,获得了实现方法。
当然,该电子钟还有很多不足之处,比如闹钟不能关闭,且只能定一个闹钟。在今后的工作中还要对此加以研究,尽量实现更多的功能。
在今后的其他工作中,也可以把这次设计中的收获运用进去,这是我此次毕业设计得到的最大财富。
参考文献
1 H.G.Cragon.The Elements of Single-Chip Microcomputer Architecture. Computer,1980 (13)27~41
2 潘永雄.新编单片机原理与应用. 第2版.西安:西安电子科技大学出版社2006
3 何立民.我国单片机应用技术发展趋势及展望.自动化与仪表,1992(1):1~5
4 向继文,廖立新.基于AT89S51 的电子钟系统设计.机电产品开发与创新,2007(2):62~63
5 张静.基于单片机数字钟的设计.办公自动化杂志,2006(89):4~5 6 樊金荣,谢智文.数字倒计时秒表的设计与实现.中南民族大学计算机科学学院院报,2005(1): 62~63
7 魏立峰,王宝兴.单片机原理与应用技术[M].北京:北京大学出版社,2006. 8 马立国. AD7888与AT89C51单片机接口应用技术.集成电路通讯,2007(25):33~34
9 http://www.elecfans.com/article/88/196/2008/[1**********]7.html 10 Andy Morell. Countdown Timer.Electronics,2003(29):321
11 Mark E.Buccini.Digital countdown timer never needs battery replacement. END,2005 (11):79~80
12 周兴华.一款电路极简的单片机电子钟设计详解.电子制作,2003(10):31 13 郭长立.DDJ-Ⅱ型多功能单片机计时器的改进设计.仪表技术,2004(4):29~30
14 何宏森.多功能智能电子钟的设计.兵工自动化,2005(4):82~84 15 张景元陈平.一种基于单片机的多功能数字钟. 微计算机信息( 嵌入式与SOC)2005 (21):136
16 刘盛雄,周 奇,韦云隆.基于单片机的数字式电子钟的设计与制作.重
庆工学院学报,2006(8):91
17 卢超.基于单片机的数字电子钟的设计与制作.大庆师范学院学报,2006(5):49
18 刘建英.基于单片机的时钟设计.内蒙古石油化工,2005(1):13 19 何宏森.多功能智能电子钟的设计.兵工自动化,2005(4):83
20 蔡希彪,曹洪奎,芳琳.单片机电子时钟系统的设计与仿真.中国科技信息,2007(4):61~63
21 Scott Edwards. Crystal-Controlled Oscillator Is Heartbeat of 60-hour Timer. The Nuts and Volts of BASIC Stamps,1996(1):95~103
致谢
时光荏苒,大学时光转眼逝去,在大学的4年中我不但学到了知识,还认识了很多值得珍惜的老师和同学。在即将离校的日子,我更加珍惜这所剩无几的日子,认真地完成了毕业设计,在这个过程中,张存善老师给了我极大的帮助,不仅是知识上的,更有很多心理上的支持,他引导我在各种杂事比较多的情况下能踏踏实实做点属于自己的工作,让我学会了自主学习。
毕业设计是大学生活中最后阶段的工作,是真正考验我们能力的一项教学内容,在这个过程中我认真思考,不断尝试,收获了很多在平时的课堂上收获不到的东西。毕业设计即将结束,我会吸取毕业设计中的经验和教训,在今后的工作中少走弯路。
夏天即将来临,我们也即将离校,回首过去的日子,大学的确教给了我们很多东西。此刻,我十分感谢母校、感谢老师们对我的教诲。虽然有很多不舍,但我依然会昂首走向新的生活,不辜负老师的培养。
附录A 整体电路图
图附A
附录B 完整程序
HOU_S BIT P2.0;第一个数码管
HOU_G BIT P2.1;第二个数码管
MIN_S BIT P2.2;第三个数码管
MIN_G BIT P2.3;第四个数码管
SEC_S BIT P2.4;第五个数码管
SEC_G BIT P2.5;第六个数码管
DAY EQU 39H;日期
MONTH EQU 3AH;月份
YEAR EQU 3BH;年份
SECOND EQU 30H;秒
MINUTE EQU 31H;分
HOUR EQU 32H;时
TIM_1 EQU 33H; TIM_2 EQU 34H;
ORG 0000H
LJMP CHUSHI ORG 000BH LJMP TIMER0 ORG 30H
CHUSHI:;初始化 MOV SECOND,#0; MOV MINUTE,#0; MOV HOUR,#0;时间的初值为000000
MOV DAY,#1; MOV MONTH,#1; MOV YEAR,#1;日期的初值为000000
SETB HOU_S; SETB HOU_G; SETB MIN_S; SETB MIN_G; SETB SEC_S; SETB SEC_G;初始状态为1,都不显示
MOV R0,#0; MOV R1,#12;闹铃初始化
MOV R3,#0; MOV R4,#1;存储定时时间,点击定时开始后,从所存时间开始倒
计时
MOV R5,#0; MOV R6,#0;设定定时时间所用寄存器
MOV 38H,#12; MOV 37H,#0;存储所定闹铃,以便判断是否闹铃时间到
CLR P0.7; MOV TIM_1,#10;执行完后经历0.5秒
MOV TIM_2,#2;执行完后经历1秒
ANL TMOD,#0F0H ORL TMOD,#01H;定时器0为模式1
MOV TH0,#03CH MOV TL0,#0B0H;装入初值
SETB ET0; SETB TR0; SETB EA;允许中断 MAIN:
JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按
下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
ACALL DISP;调用显示程序
FMQPD:;判断定时是否到零、闹铃时间是否已到
MOV A,HOUR; SUBB A,38H; JZ FEN;判断时是否到闹铃所定时间,若到,则对分进行判断,若不到,则对定时进行判断
AJMP DSPDKQ FEN:
MOV A,MINUTE; SUBB A,37H; JZ SHENGYIN1;时和分都到闹铃时间则蜂鸣器响
DSPDKQ:;判断是否应该进行定时时间的判断
MOV A,3CH;3CH
是引入的判断因子,当其为0时不对定时时间是否到0进行判断,从而不开启蜂鸣器
JNZ DSPD2;当3CH不是0时,跳转到定时判断程序
AJMP MAIN DSPD2: MOV A,R4; JZ S_PD; AJMP MAIN; S_PD: MOV A,R3; JZ SHENGYIN1; AJMP MAIN; DSTZ: AJMP DSTZ1;
DATETZ: AJMP DATETZ1;
SHENGYIN1: MOV 3CH,#1 SETB P0.7 AJMP MAIN ZSTZ1: MOV 35H,#60;
MOV 36H,#10; ZSTZ2: ACALL DISP; DJNZ 35H,ZSTZ2; JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
JNB P3.4,H_T; JNB P3.5,M_T; DJNZ 36H,ZSTZ2; AJMP MAIN; H_T: ACALL DISP; INC HOUR; MOV A,HOUR; CJNE A,#24,ZSTZ1;
MOV HOUR,#0; AJMP ZSTZ1; M_T: ACALL DISP; INC MINUTE; MOV A,MINUTE;
CJNE A,#60,ZSTZ1;
MOV MINUTE,#0; AJMP ZSTZ1; NLTZ1: CLR P0.7; DEC 38H MOV 35H,#100; MOV 36H,#10; NLTZ2: ACALL ONE; ACALL TWO; DJNZ 35H,NLTZ2; JNB P3.0,DATETZ;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ1;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ1;按下2键进行闹铃设置
JNB P3.3,DSTZ;按下3键进行定时设置
JNB P3.4,NLXS2; JNB P3.5,NLXS1; DJNZ 36H,NLTZ2; AJMP MAIN; NLXS1: MOV
DPTR,#LEDTAB;
MOV 35H,#100; MOV 36H,#10; INC R0; MOV 37H,R0; CJNE R0,#60,NLTZ2;
MOV R0,#0; MOV 37H,R0; AJMP NLTZ2; ONE: MOV DPTR,#LEDTAB;
MOV A,R0; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G; ACALL D_1MS; SETB MIN_G; RET;
NLXS2: MOV DPTR,#LEDTAB;
MOV 35H,#60; MOV 36H,#10; INC R1; MOV 38H,R1; CJNE R1,#24,NLTZ2;
MOV R1,#0; MOV 38H,R1; AJMP NLTZ2; TWO: MOV DPTR,#LEDTAB;
MOV A,R1; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR HOU_S; ACALL D_1MS; SETB HOU_S; MOV DPTR,#LEDTAB;
MOV A,B; MOVC A,@A+DPTR;
MOV P1,A;
CLR HOU_G; ACALL D_1MS; SETB HOU_G; RET; DSTZ1: MOV 3CH,#0 CLR P0.7; MOV 35H,#100; MOV 36H,#10; JNB P3.3,DSTZ1; DSTZ2: ACALL DS_S; ACALL DS_M; DJNZ 35H,DSTZ2; JNB
P3.0,DATETZ3;按下0键时,显示日期并可对日期进行调整
JNB P3.1,ZSTZ;按下1键时,显示时间,并可调时
JNB P3.2,NLTZ;按下2键进行闹铃设置
JNB P3.4,DSXS1; JNB P3.5,DSXS2; JNB P3.3,DSKS1; DJNZ 36H,DSTZ2; AJMP MAIN; DATETZ3:
AJMP DATETZ ZSTZ: AJMP ZSTZ1 NLTZ: AJMP NLTZ1 DSXS1: MOV 35H,#100; MOV 36H,#10; INC R6; CJNE R6,#60,DSTZ2;
MOV R6,#0; AJMP DSTZ2; DS_M:; MOV DPTR,#LEDTAB;
MOV A,R6; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G;
ACALL D_1MS; SETB MIN_G; RET; DSXS2: MOV 35H,#100; MOV 36H,#10; INC R5; CJNE R5,#60,DSTZ2;
MOV R5,#0; AJMP DSTZ2; DS_S: MOV DPTR,#LEDTAB;
MOV A,R5; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_S; ACALL D_1MS; SETB SEC_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_G; ACALL D_1MS; SETB SEC_G;
DSKS1: MOV 3CH,#1 MOV A,R5; MOV R3,A; MOV A,R6; MOV R4,A; DSKS2: MOV DPTR,#LEDTAB;
MOV A,R3; MOV B,#10; DIV AB; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_S; ACALL D_1MS; SETB SEC_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR SEC_G; ACALL D_1MS; SETB SEC_G; MOV A,R4; MOV B,#10; DIV AB; MOVC
MOV P1,A; CLR MIN_S; ACALL D_1MS; SETB MIN_S; MOV A,B; MOVC A,@A+DPTR;
MOV P1,A; CLR MIN_G; ACALL D_1MS; SETB MIN_G; JNB P3.0,MAIN2; JNB P3.1,MAIN2; DSPD:; MOV A,R4; JZ PANDUAN_S; AJMP DSKS2; PANDUAN_S:; MOV A,R3; JZ SHENGYIN; AJMP DSKS2; MAIN2: LJMP MAIN;
SHENGYIN: MOV 3CH,#1 SETB P0.7 AJMP MAIN
RETI_11:;由于程序较长,此处加一个返回程序,避免跳转距离过长
POP PSW; POP ACC; RETI; ;中断服务程序 TIMER0: PUSH ACC; PUSH PSW; MOV A,#0B0H; ADD A,TL0; MOV TL0,A; MOV TH0,#03CH; DJNZ TIM_1,RETI_11;
MOV TIM_1,#10; DJNZ TIM_2,RETI_11;
MOV TIM_2,#2; INC SECOND; MOV A,SECOND; CJNE R3,#0,RETI_2;
MOV R3,#60; DEC R4; RETI_2: DEC R3;
A,#60,RETI_11;
MOV SECOND,#0; INC MINUTE; MOV A,MINUTE; RETI_3: CJNE A,#60,RETI_11;
MOV MINUTE,#0; MOV SECOND,#0; INC HOUR; MOV A,HOUR; CJNE A,#24,RETI_11;
MOV HOUR,#0; MOV MINUTE,#0; MOV SECOND,#0; T_YEARPD: MOV A,YEAR; MOV B,#100; DIV AB; MOV A,B; JZ T_YEARPD2;看年份是否能被100整除,若能,再进行额外判断
MOV A,YEAR;不能被100整除,则判断是否能被4整除
MOV B,#4; DIV AB;
JZ T_RUNYEAR;若年份能被4整除则跳转到闰年部分
T_PINGYEAR:;年份不能被4整除则为平年
MOV A,MONTH; CJNE
A,#2,T_PINGMONTH;若不是2月,则跳转到平时的月份进行判断
INC DAY; MOV A,DAY; CJNE A,#29,RETI_11;
MOV DAY,#1; INC MONTH; MOV A,MONTH; CJNE A,#13,RETI_11;
MOV MONTH,#1; INC YEAR; AJMP RETI_1;返回 T_YEARPD2:;能被100整除的情况下,的额外判断
MOV A,YEAR; MOV B,#100; DIV AB;
DIV AB
JNZ T_PINGYEAR;若不能被400整除则为平年
T_RUNYEAR:;闰年的情况
MOV A,MONTH; CJNE
A,#2,T_PINGMONTH;看是不是2月
INC DAY; MOV A,DAY; CJNE A,#30,RETI_1;
MOV DAY,#1; INC MONTH; MOV A,MONTH; CJNE A,#13,RETI_1;
MOV MONTH,#1; INC YEAR; AJMP RETI_1; T_PINGMONTH: MOV
A,MONTH
ADD A,#2 SUBB A,#3;判断是
不是一月
JZ T_DAY31;若是一月调用一个月31天的程序段
MOV A,MONTH; SUBB A,#3; JZ T_DAY31; MOV A,MONTH; SUBB A,#4; JZ T_DAY30;调用一个月30天的程序段
MOV A,MONTH SUBB A,#5 JZ T_DAY31 MOV A,MONTH SUBB A,#6 JZ T_DAY30 MOV A,MONTH SUBB A,#7 JZ T_DAY31 MOV A,MONTH SUBB A,#8 JZ T_DAY31 MOV A,MONTH SUBB A,#9 JZ T_DAY30 MOV A,MONTH SUBB A,#10 JZ T_DAY31 MOV A,MONTH
SUBB A,#11 JZ T_DAY30 MOV A,MONTH SUBB A,#12 JZ T_DAY31 RETI_1: POP PSW POP ACC RETI;中断返回 T_DAY31:;当一个月为31天时的日期计算方法
INC DAY MOV A,DAY CJNE A,#32,RETI_1
MOV DAY,#1 INC MONTH MOV A,MONTH CJNE A,#13,RETI_1
MOV MONTH,#1 INC YEAR AJMP RETI_1 T_DAY30:;当一个月为30天时的日期计算方法
INC DAY MOV A,DAY CJNE
42
A,#31,RETI_1
MOV DAY,#1 INC MONTH MOV A,MONTH CJNE A,#13,RETI_1
MOV MONTH,#1 INC YEAR AJMP RETI_1
DISP:;走时的显示程序,包括调时时的显示
MOV DPTR,#LEDTAB
MOV A,SECOND MOV B,#10 DIV AB;A存十位B存个位
MOVC A,@A+DPTR
MOV P1,A CLR SEC_S ACALL D_1MS;显示秒十位
SETB SEC_S MOV A,B MOVC A,@A+DPTR
MOV P1,A
CLR SEC_G ACALL D_1MS;显示秒个位
SETB SEC_G MOV A,MINUTE MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR MIN_S ACALL D_1MS SETB MIN_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR MIN_G ACALL D_1MS SETB MIN_G MOV A,HOUR MOV B,#10 DIV AB MOV DPTR,#LEDTAB
MOVC A,@A+DPTR
MOV P1,A CLR HOU_S ACALL D_1MS
SETB HOU_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR HOU_G ACALL D_1MS SETB HOU_G RET
DATEDISP:;日期的显示程序,包括日期调整时的显示
MOV DPTR,#LEDTAB
MOV A,DAY MOV B,#10 DIV AB;A存十位B存个位
MOVC A,@A+DPTR
MOV P1,A CLR SEC_S ACALL D_1MS SETB SEC_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR SEC_G
43
ACALL D_1MS SETB SEC_G MOV A,MONTH MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR MIN_S ACALL D_1MS SETB MIN_S MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR MIN_G ACALL D_1MS SETB MIN_G MOV A,YEAR MOV B,#100 DIV AB MOV A,B MOV B,#10 DIV AB MOVC A,@A+DPTR
MOV P1,A CLR HOU_S ACALL D_1MS SETB HOU_S
MOV A,B MOVC A,@A+DPTR
MOV P1,A CLR HOU_G ACALL D_1MS SETB HOU_G RET
DATETZ1:;日期调整程序
MOV 35H,#100 DATETZ2: ACALL DATEDISP DJNZ 35H,DATETZ2
JNB P3.3,YEAR_T JNB P3.4,MONTH_T
JNB P3.5,DAY_T JNB P3.1,MAIN3 AJMP DATETZ1 MAIN3: AJMP MAIN
YEAR_T:;年的调整很容易;直接加1
ACALL DATEDISP INC YEAR
AJMP DATETZ1 MONTH_T:;月的调整也很容易,加到13时月变为1
ACALL DATEDISP INC MONTH MOV A,MONTH CJNE A,#13,DATETZ1
MOV MONTH,#1 AJMP DATETZ1 DAY_T:;日期的调整需要判断是不是闰年,还要判断当月具体是哪个月
YEARPD: MOV A,YEAR MOV B,#100 DIV AB MOV A,B JZ YEARPD2;看年份是否能被100整除,若能,再进行额外判断
MOV A,YEAR;不能被100整除,则判断是否能被4整除
MOV B,#4 DIV AB MOV A,B
44
JZ RUNYEAR;若年份能被4整除则跳转到闰年部分
PINGYEAR:;年份不能被4整除则为平年
MOV A,MONTH CJNE
A,#2,PINGMONTH;若不是2月,则跳转到平时的月份进行判断
INC DAY MOV A,DAY CLR C SUBB A,#29 JC DATETZ1 MOV DAY,#1 AJMP DATETZ1;返回扫描
YEARPD2:;能被100整除的情况下,的额外判断
MOV A,YEAR MOV B,#100 DIV AB MOV B,#4 DIV AB
JNZ PINGYEAR;若不能被400整除则为平年
RUNYEAR:;闰年的情况
MOV A,MONTH CJNE
A,#2,PINGMONTH;看是不是2月
INC DAY MOV A,DAY CLR C SUBB A,#30 JC DATETZ1 MOV DAY,#1 AJMP DATETZ1 PINGMONTH:MOV A,MONTH
ADD A,#2 SUBB A,#3;判断是不是一月
JZ DAY31;若是一月调用一个月31天的程序段
MOV A,MONTH SUBB A,#3 JZ DAY31 MOV A,MONTH SUBB A,#4 JZ DAY30;调用一个月30天的程序段
MOV A,MONTH SUBB A,#5
JZ DAY31 MOV A,MONTH SUBB A,#6 JZ DAY30 MOV A,MONTH SUBB A,#7 JZ DAY31 MOV A,MONTH SUBB A,#8 JZ DAY31 MOV A,MONTH SUBB A,#9 JZ DAY30 MOV A,MONTH SUBB A,#10 JZ DAY31 MOV A,MONTH SUBB A,#11 JZ DAY30 MOV A,MONTH SUBB A,#12 JZ DAY31 DAY30: INC DAY MOV A,DAY CLR C SUBB A,#31 JC DATETZ11 MOV DAY,#1 AJMP DATETZ1
45
DAY31: INC DAY MOV A,DAY CLR C SUBB A,#32 JC DATETZ11 MOV DAY,#1 AJMP DATETZ1 DATETZ11: AJMP DATETZ1 D_1MS: MOV R7,#2 D_5: MOV R2,#250 DJNZ R2,$ DJNZ R7,D_5 RET
LEDTAB: DB
7EH,30H,6DH,79H,33H,5BH,5FH,70H,7FH,7BH
END