单片机电子时钟设计报告

科技创新实践

[数字时钟设计]

[用AT89S52单片机设计电子时钟的实验报告]

目录

单片机的个性化电子钟设计报告 1

一、设计背景 1

二、作品介绍 1

三、设计目的及意义 1

四、设计要求 1

五、总体方案设计 2

5.1硬件设计 2

1.单片机最小系统 AT89S52 2

2、显示模块 2

3.按键模块 2

4.晶振模块 3

5.2 软件设计 3

1 硬件框图 3

2 程序流程图 3

六、遇到的困难和解决的办法 4

七、总结及建议 5

单片机的个性化电子钟设计报告

一、设计背景

数字钟已成为人们日常生活中必不可少的必需品,广泛用于个人家庭以及办公室等公共场所,给人们的生活、学习、工作、娱乐带来极大的方便。由于数字集成电路技术的发展和采用了先进的石英技术,使数字钟具有走时准确、性能稳定、携带方便等优点,它还用于计时、自动报时及自动控制等各个领域。尽管目前市场上已有现成的数字钟集成电路芯片出售,价格便宜、使用也方便,但鉴于单片机的定时器功能也可以完成数字钟电路的设计,因此进行数字钟的设计是必要的。在这里我们将已学过的比较零散的数字电路的知识有机的、系统的联系起来用于实际,来培养我们的综合分析和设计电路,写程序、调试电路的能力。

单片机具有体积小、功能强可靠性高、价格低廉等一系列优点,不仅已成为工业测控领域普遍采用的智能化控制工具,而且已渗入到人们工作和和生活的各个角落,有力地推动了各行业的技术改造和产品的更新换代,应用前景广阔。

二、作品介绍

该作品是个性化电子钟设计,技术上主要用单片机(AT89S52)主控,4位LED数码显示,分别显示“小时:分钟”秒在下一步中。该作品主要用于24小时计时显示,能整时报时,能定时闹铃1分钟。

使用方法:开机后时钟在00:00起开始计时。

长按P3.2进入调分状态:分单元闪烁,按P3.2加1,按P3.3减1.再长按P3.2进入时调整状态,时单元闪烁,加减调整同调分.按长按退出调整状态。

(2)按P3.3进入设定闹时状态: 12:00: ,可进行分设定,按P3.4分加1,再按P3.2为时调整,按P3.4时加1,按P3.3调闹钟结束.在闹铃时可按P3.2停闹,不按闹铃1分钟。

三、设计目的及意义

(1)巩固、加深和扩大51系列单片机应用的知识面,提高综合及灵活运用所学知识解决工业控制的能力;

(2)培养针对课题需要,选择和查阅有关手册、图表及文献资料的自学能力,提高组成系统、编程、调试的动手能力;

(3)对课题设计方案的分析、选择、比较、熟悉用51单片机做系统开发、研制的过程,软硬件设计的方法、内容及步骤。

四、设计要求

(1)上电以后自动进入计时状态,起始于00:00。

(2)设计键盘调整时间,完成时间设计,并设置闹钟。

(3)定时时间为1/100秒,采用定时器实现。

(4)采用LED数码管显示,时、分采用数字显示。

(5)采用24小时制,具有方便的时间调校功能。

五、总体方案设计

5.1硬件设计

1.单片机最小系统 AT89S52

AT89S52概述:是一款非常适合单片机初学者学习的单片机,它完全兼容传统的8051,8031的指令系统,他的运行速度要比8051快最高支持达33MHz的晶体震荡器,在此系统中使用12MHz的晶振。AT89S52具有以下标准功能: 8k字节Flash,256字节RAM,32 位I/O 口线,看门狗定时器,2 个数据指针,三个16 位定时器/计数器,一个6向量2级中断结构,全双工串行口,片内晶振及时钟电路。另外,AT89S52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止……

详述:AT89S52是一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可编程Flash 存储器。使用Atmel 公司高密度非易失性存储器技术制造,与工业80C51 产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得AT89S52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。AT89S52具有以下标准功能:8k字节Flash,256字节RAM,32 位I/O 口线,看门狗定时器,2 个数据指针,三个16位定时器/计数器。一个6向量2级中断结构,全双工串行口及时钟电路。另外,AT89S52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止.

2、显示模块

LED数码管是由发光二极管构成的,亦称半导体数码管。将条状发光二极管按照共阴极(负极)或共阳极(正极)的方法连接,组成“8”字,再把发光二极管另一电极作笔段电极,就构成了LED数码管。若按规定使某些笔段上的发光二极管发光,就能显示从0~9的…系列数字。同荧光数码管(VFD)、辉光数码管(NRT)相比,它具有:体积小、功耗低、耐震动、寿命长、亮度高、单色性好、发光响应的时间短,能与TTL、CMOS电路兼容等的数显器件。+、-分别表示公共阳极和公共阴极。a~g是7个笔段电极,DP为小数点。另有一种字高为7.6mm的超小型LED数码管,管脚从左右两排引出,小数点则是独立的。

本系统利用4位LED数码管显示时间,共阴极结构。LED数码管由7段发光二极管组成,当要显示某个数字时只要将数字所对应的引脚送入低电平。

3.按键模块

本设计中主要有三个控制按键,按键功能为:

(1)P3.2为调时间模式,长按P3.2进入调分状态:分单元闪烁,按P3.2加1,按P3.3减1.再长按P3.2进入时调整状态,时单元闪烁,加减调整同调分.按长按退出调整状态。

(2)按P3.3进入设定闹时状态: 12:00: ,可进行分设定,按P3.4分加1,再按P3.2为时调整,按P3.4时加1,按P3.3调闹钟结束.在闹铃时可按P3.2停闹,不按闹铃1分钟。

(3)按下P3.4进入秒表状态:再按P3.4秒表又启动,按P3.4暂停,再按P3.4秒表清零,按P3.4退出秒表回到时钟状态。

4.晶振模块

在AT89S51芯片内部有一个高增益反相放大器,其输入端为芯片引脚XTAL1,输出端为引脚XTAL2。而在芯片内部,XTAL1和XTAL2之间跨接晶体振荡器和微调电容,从而构成一个稳定的自激振荡器。时钟电路产生的振荡脉冲经过触发器进行二分频之后,才成为单片机的时钟脉冲信号。

5.2 软件设计

1 硬件框图

根据以上的电子时钟的设计要求可以分为以下的几个硬件电路模块:单片机模块、数码显示模块、晶振模块、电源模块与按键模块等,模块之间的关系图如下面得方框电路图所示。

单片机电子时钟设计报告

2 程序流程图

(1)总体流程图

单片机电子时钟设计报告

单片机电子时钟设计报告

(4)秒表模式

六、遇到的困难和解决的办法

本次课程设计与我们以往的相比难度有所增加,主要是此次设计对知识的要求较为综合,我们用到了单片机、数字电路、模拟电路、protel/proteuse、keil-c51等知识,所以,才开始时,我们不知道从何下手。不过后来在老师的帮助下,以及自己不断的查找资料,和同学商量,终于开始有点头目了,慢慢的便进入了状态。

不过在利用protel软件画图时,我们还是遇到了不小的麻烦。最主要的便是对软件使用方法的陌生和不知道元件名称,画不了图。由于学了protel后自己很少使用,所以渐渐地忘记了对软件的使用。而我们的原理图都是参照人家的原理图来制作的,所以对很多元件我们都不知道其名称,也就不能查找元件画图。不过后来经过问老师、问同学、查资料,这些难题都一一解决。

另一个问题就是将编写好的源程序输入电脑,编译后出现很多错误,这些错误有许多是平时的实验遇到过的,例如:输入的分号格式不正确,零和字母O弄混淆了,LOOP5出现了几次,CJNE写成了CJNZ等等,幸好这些错误在平时的实验中遇到了,所以改错误很容易,但同时也说明了,平时的错误现在还在犯,证明错误我还没有完全的改正,这点我们以后一定要注意了。争取错误犯了两次就不能在犯了。除了常见的错误外,还有几条错误时我从来没有遇到过的,如:LJMP跳转指令跳不回指定的位置,是因为跳转的长度大于LJMP跳转的长度,最后只好设置跳转两次后才能跳到指定的位置。

经过多次的修改和向别人请教,错误都排除了,编译通过了,但功能没有达到设计的要求,最主要的就是设计的原理图太多错误,不能进行仿真。最后,在老师另外给了我们一个原理图后,经过几天在机房的努力,终于实现了时钟的全部要求。

七、总结及建议

本次课程设计是用AT89S52单片机CPU及接口电路设计一个数字时钟,经过一个星期的调试,结果满足设计要求,验证无误。通过单片机硬件电路的调试,实现了预先设定的功能,设计主要用到了多种芯片,程序也比较长比较麻烦,同时也遇到了不少困难,尤其是关于校时模块的设计实现。关于显示模块,在以前的实验中做过,所以问题很容易解决。

随着集成电路和计算机技术的迅速发展,使电子仪器的整体水平发生巨大变化,传统的仪器逐步的被智能仪器所取代。智能仪器的核心部件是单片机,因其极高的性价比得到广泛的应用与发展,从而加快了智能仪器的发展。而传感器作为测控系统中对象信息的入口,越来越受到人们的关注。传感器好比人体“五官”的工程模拟物,它是一种能将特定的被测量信息(物理量、化学量、生物量等)按一定规律转换成某种可用信号输出的器件或装置本次课设中的半桥电子秤就是在以上仪器的基础上设计而成的。因此,只有充分了解有关智能仪器、单片机、传感器以及各部分之间的关系才能达到要求。

通过本次设计,我们系统的了解了实时时钟的设计流程,尤其是硬、软件的设计方法,掌握了键盘显示电路的基本功能及编程方法,掌握了键盘电路和显示电路的一般原理,也进一步掌握了89S52定时器的使用和中断处理器程序的编程方法。开拓了思路,锻炼了实践动手能力,提高了分工协作能力和分析问题,解决问题的能力,达到了本次课程设计的目的。在调试电路的过程中也积累了一些宝贵的经验,比如说,在I/O口要保证标准的高电平”1”的产生,一般要上拉电阻5.1k,在一些需要高电平的地方,不能用悬空来模拟,必须严格的按照“+5v”来连接,特别是调试过程中的分部分进行很重要。

此次单片机课程设计,从选题到定稿,从理论到实践,在整整两个星期里,学到了很多的东西。同时不仅巩固了以前所学过的知识,而且还学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。这次的课程设计还让我学会了如何去培养我们的创新精神,从而不断地战胜自己,超越自己。更重要的是,我在这一设计过程中,学会了坚持不懈,不轻言放弃。

设计过程,好比是我们人类成长的历程,常有一些不如意,但毕竟这是第一次做,难免会遇到各种各样的问题。在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。我们通过查阅大量有关资料,并在小组中互相讨论,交流经验和自学,若遇到实在搞不明白的问题就会及时请教老师,使自己学到了不少知识,也经历了不少艰辛,但收获同样巨大。

在整个设计中我懂得了许多东西,也培养了我独立工作的能力,树立了对自己工作能力的信心,相信会对今后的学习工作生活有非常重要的影响。而且大大提高了动手的能力,使我充分体会到了在创造过程中探索的艰难和成功时的喜悦。虽然这个设计做的也不太好,但是在设计过程中所学到的东西是这次课程设计的最大收获和财富。

单片机课程设计虽然结束了,但通过设计所学到的东西将长久存在。相信这次设计带给我们的严谨的学习态度和一丝不苟的科学作风将会给我们未来的工作和学习打下一个更坚实的基础。

单片机课程设计,是对单片机知识的验证,可以帮助我们理解巩固所学知识,激发我们对单片机课程的兴趣,更锻炼了我们独立思考、开拓创新的能力。

在做本次课程设计的过程中,我感触最深的当属查阅大量的设计资料了。为了让自己的设计更加完善,查阅这方面的设计资料是十分必要的,同时也是必不可少的。我们是在做单片机课程设计,但我们不是艺术家,他们可以抛开实际尽情在幻想的世界里翱翔,而我们一切都要有据可依,有理可寻,不切实际的构想永远只能是构想,永远无法升级为设计。

其次,在这次课程设计中,我们运用到了以前所学的专业课知识,如:CAD制图、汇编语言、模拟和数字电路知识等。虽然过去从未独立应用过它们,但在学习的过程中带着问题去学我发现效率很高,这是我做这次课程设计的又一收获。

最后,要做好一个课程设计,就必须做到:在设计程序之前,对所用单片机的内部结构有一个系统的了解,知道该单片机内有哪些资源;要有一个清晰的思路和一个完整的软件流程图;在设计程序时,不能妄想一次就将整个程序设计好,反复修改、不断改进是程序设计的必经之路;要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便;在设计课程过程中遇到问题是很正常德,但我们应该将每次遇到的问题记录下来,并分析清楚,以免下次再碰到同样的问题。另外,这次课程设计让我感到了团队合作的重要性。在团队中,我们互帮互助,对整个课程设计来说,这是至关重要的,缺少每一个人都会对我们的设计产生影响。还有要感谢指导老师在我们遇到困难时,给予我们的建议与鼓励。

 

第二篇:单片机智能电子钟设计报告

四川师范大学成都学院

智能电子钟(LCD显示)

—电线路实现训练

学生姓名 **

学号 **

所在系  通信系

专业名称  通信工程

班 级  20##级通信工程2班

指导教师 **

四川师范大学成都学院

二○**年六月

一、设计任务

● 采用定时器实现时钟;

● 计时:秒、分、时、天、周、月、年。

● 闰年自动判别。五路定时输出,可任意关断(最大可到16路)。

● 自定任意时刻自动开/关屏。

● 计时精度:误差≤1秒/月(具有微调设置)

● 键盘采用动态扫描方式查询。所有的查询、设置功能均由功能键A、B完成。

● 画出完整的电路原理图仿真图。

二、方案与论证

2.1 、多功能电子钟计时方案

方案一:采用实时时钟芯片

实时时钟芯片具备年、月、日、时、分、秒计时功能和多点定时功能,计时数据的更新每秒自动进行一次,不需程序干预。计算机可通过中断或查询方式读取计时数据进行显示,因此计时功能的实现无需占用CPU的时间,程序简单。此外,实时时钟芯片多数带有锂电池做后备电源,具备永不停止的计时功能;具有可编程方波输出功能,可用做实时测控系统的采样信号等;有的实时时钟芯片内部还带有非易失性RAM,可用来存放需长期保存但有时也需变更的数据。由于功能完善,精度高,软件程序设计相对简单,且计时不占用CPU时间,因此,在工业实时测控系统中多采用这一类专用芯片来实现实时时钟功能。

方案二: 软件控制

利用单片机内部的定时/计数器进行中断定时,配合软件延时实现时、分、秒的计时及秒表计时。该方案节省硬件成本,且能使设计者对单片机的指令系统能有更深入的了解,从而掌握单片机应用技术MCS-51汇编语言程序设计方法,因此,本系统设计采用此种软件控制方法来实现计时。而由于ATMEL公司的AT89S52单片机是低功耗的具有4KB在线可编程Flash存储器的单片机。它与通用80C51系列单片机的指令系和引脚兼容。片内的Flash可允许在线重新编程,也可使用通用非易失性存储器编程。它将通用CPU和在线可编程Flash集成在一个芯片上,形成了功能强大、使用灵活和具有较高性能价格比的微控制器。它的功能强大,而且也较容易购买,故本设计中所选的单片机为AT89S52单片机。

2.2 、多功能电子钟键盘显示方案

方案一: 8279扩展。

该方案方框图如图1.2.1所示,8279是一种可编程的键盘/显示接口专用芯片,它含有键盘输入和显示输出两种功能,键扫描程序和动态显示程序全由8279硬件自动完成,此种方案能以比较简单的硬件电路和较少的软件开销实现单片机与键盘、LED显示器的接口。

方案二: 8155扩展,LED动态显示。

该方案方框图如图1.2.2所示,8155是一块可编程的接口芯片,与单片机的接口非常简单,它的键盘、显示共用一个接口电路,可节省I/O口。但动态扫描方式需占用CPU较多的时间,在单片机没有太多实时测控任务的情况下可以采用。

方案三: 串口扩展,LED静态显示。

该方案方框图如图1.2.3所示,独立式键盘配置灵活,软件结构简单,按键较多时不宜采用。静态显示占用口资源少,采用串口传输实现静态显示, LED数码管与单片机之间通过6个移位寄存器相连,显示亮度有保证,但此方案的硬件开销大,电路复杂,信息刷新速度慢,比较适用于并行口资源较少的场合。

方案四: 独立式按键,LED动态显示。

该方案方框图如图1.2.4所示,独立式按键直接与单片机I/O口相连构成键盘,每个按键不会相互影响,因本系统用到的按键比较少,采用独立式键盘不会浪费I/O口线,所以本系统采用独立式键盘。动态显示的亮度虽然不如静态显示,但其硬件电路较简单,可节省硬件成本,虽然动态扫描需占用CPU较多的时间,但本系统中的单片机没有很多实时测控任务,因此,本系统采用此种方案。

三、系统硬件设计

(一)系统总框图

(二)原理图设计

3.2、多功能电子钟电路原理图

四、系统软件设计

4.1、电源电路工作原理图

图4.1所示为集成电源电路的原理图

4.2、复位电路工作原理

复位是单片机的初始化操作,其主要功能是把PC初始化为0000H,使单片机从0000H单元开始执行程序,并使其它功能单元处于一个确定的初始状态。本复位电路采用的是按键复位,它是通过复位端经电阻与VCC电源接通而实现的,它兼具上电复位功能。因本系统的晶振的频率为12MHz,所以,复位信号持续时间应当超过2μS才能完成复位操作。

4.3、键盘工作原理

图4.3所示为键盘原理图

图4.3所示为键盘原理图,本系统采用的是独立式键盘结构,每个按键的工作不会影响其它I/O口线的状态。软件是采用查询式结构,首先逐位查询每根I/O口线的输入状态,如某一根I/O口线输入为低电平,则可确认该I/O口线所对应的按键已按下,然后,再转向该键的功能处理程序。

4.4、显示器工作原理

图4.4所示为键盘原理图

系统采用动态显示方式,动态显示通常都是采用动态扫描的方法进行显示,即循环点亮每一个数码管,这样虽然在任何时刻都只有一位数码管被点亮,但由于人眼存在视觉残留效应,只要每位数码管间隔时间足够短,就可以给人以同时显示的感觉。由图4.4可知,要想让数码管那一段亮,在该数码管位控段为高电平的情况下给这段送低电平就可以了。

五、总结与展望

课题设计是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。随着科学技术发展的日新月异,单片机已经成为当今计算机应用中空前活跃的领域,在生活中可以说得是无处不在,作为二十一世纪的大学生来说掌握单片机的开发技术是十分重要的。

本次课题设计是利用AT89C51单片机设计的有实时显示、时间校准、定时闹钟和整点报时功能的电子时钟。并详细说明了软件和硬件设计方法及硬件实现。通过本次设计单片机原理及应用课题设计使我充分认识到了课题设计的重要性和必要性,本次设计使我对以学过的基础知识有了更深入的理解,学会了独立思考、独立工作以及对应用所学基本理论分析和解决实际问题的能力有了很大的提高。

在此次单片机课题设计之后,我不仅加深了对单片机理论的理解,将理论很好地应用到实践当中去,而且我们还学会了如何去创新精神和严谨的科学作风,从而不断地战胜自己,超越自己。更正要的是,我在这一设计过程中,学会了坚持不懈,不轻易言弃。当然,改电子时钟还有很多不足之处,比如闹钟只能定一个。在今后的学习过程中,我们需要继续努力,锻炼自己。

六、参考文献

1 李群芳 单片微型计算机与接口技术(第三版):电子工业出版社,2008

2 刘强 51单片机含Protel实验指导书:四川师范大学成都学院实验中心,2011

3 郭天祥 新概念51单片机C语言教程  电子工业出版社

4 周广兴,张子红 单片机原理及应用教程 北京大学出版社

5 浏览 http://proteus.5d6d.com/forum-2-1.html,下载里面的相关资料

附录一:系统总电路

电路原理仿真图:

附录二:源代码

#include<reg51.H>

#include<intrins.h>

//----------------------------------------

#define uint unsigned int

#define uchar unsigned char

//----------------------------------------

/*uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,

0x80,0x98,0x88,0x83,0xc6,0xa1,0x86,0x8e};//共阳极数码管代码 */

uchar code xingqi[8]={0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06}; //星期显示代码

uchar miao,shi,fen,date,month,day,year,year10,set,mun,set_shi,set_fen,time_flag; //全局定义

uint year_data,t;

//---------------------------------------------

sbit SCLK=P3^5; //DS1302通讯线定义

sbit DIO=P3^6;

sbit RST=P3^7;

sbit speak=P0^0;

sbit DS=P2^0; //595通讯线定义

sbit SH_CP=P2^1;

sbit ST_CP1=P2^2;

sbit ST_CP2=P2^3;

sbit ST_CP3=P2^4;

sbit ST_CP4=P2^5;

sbit ST_CP5=P2^6;

sbit ST_CP6=P2^7;

sbit ST_CP7=P3^0;

sbit ST_CP8=P3^1;

sbit OE1=P1^0;

sbit OE2=P1^1;

sbit OE3=P1^2;

sbit OE4=P1^3;

sbit OE5=P1^4;

sbit OE6=P1^5;

sbit OE7=P1^6;

sbit OE8=P1^7;

sbit K1=P3^2; //按键接口定义

sbit K2=P3^3;

sbit K3=P3^4;

sbit K4=P0^1;

sbit K5=P0^2;

//-------------------------------------

void write_595(uchar temp) //写74HC595一个字节

{

uchar temp_595,i;

temp_595=temp;

for(i=0;i<8;i++)

{

SH_CP=0;

_nop_();_nop_();_nop_();

if(temp_595&0x80)

{

DS=1;

}

else

{

DS=0;

}

_nop_();_nop_();_nop_();

SH_CP=1;

temp_595<<=1;

}

}

//----------------------------------------------

void delay(uint z) //Nms延时

{

uint x,y;

for(x=z;x>0;x--)

for(y=112;y>0;y--);

}

//---------------------------------------------

void delaynus(uint z) //ums延时

{

uint x,y;

for(x=z;x>0;x--)

for(y=10;y>0;y--);

}

//-----------------------------------------------

void write(uchar date) //写入DS1302一个字节

{

uchar temp,i;

RST=1;

SCLK=0;

temp=date;

for(i=0;i<8;i++)

{

SCLK=0;

if(temp&0x01)

DIO=1;

else

DIO=0;

SCLK=1;

temp>>=1;

}

}

//-------------------------------------

uchar read() //读出DS1302一个字节

{

uchar a,temp;

RST=1;

for(a=8;a>0;a--)

{

temp>>=1;

SCLK=1;

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

SCLK=0;

if(DIO)

{

temp=temp|0x80;

}

else

{

temp=temp|0x00;

}

}

return (temp);

}

//-----------------------------------

void write_1302(uchar add,uchar dat) //写DS1302数据

{

RST=0;

SCLK=0;

RST=1;

write(add);

write(dat);

SCLK=1;

RST=0;

}

//------------------------------------------

uchar read_1302(uchar add) //读DS1302数据

{

uchar temp;

RST=0;

SCLK=0;

RST=1;

write(add);

temp=read();

SCLK=1;

RST=0;

return(temp);

}

//--------------------------------------------

void display() //显示子程序

{

miao=read_1302(0x81); //读秒

fen=read_1302(0x83); //读分

shi=read_1302(0x85)&0x3f;//读时

date=read_1302(0x87); //读日

month=read_1302(0x89); //读月

year=read_1302(0x8d); //读年

day=read_1302(0x8B); //读星期

write_595(miao); //显示秒

ST_CP1=0;

ST_CP1=1;

ST_CP1=0;

delaynus(10);

write_595(fen); //显示分

ST_CP2=0;

ST_CP2=1;

ST_CP2=0;

delaynus(10);

write_595(shi); //显示时

ST_CP3=0;

ST_CP3=1;

ST_CP3=0;

delaynus(10);

write_595(date); //显示日

ST_CP4=0;

ST_CP4=1;

ST_CP4=0;

delaynus(10);

write_595(month); //显示月

ST_CP5=0;

ST_CP5=1;

ST_CP5=0;

delaynus(10);

write_595(year); //显示年

ST_CP6=0;

ST_CP6=1;

ST_CP6=0;

delaynus(10);

write_595(xingqi[day]); //显示星期

ST_CP7=0;

ST_CP7=1;

ST_CP7=0;

delaynus(10);

}

//------------------------------------------

void ds1302_init() //1302初始化

{

RST=0;

SCLK=0;

/* write_1302(0x80,0x00);//设置初始值SEC

write_1302(0x82,0x00);//设置初始值MIN

write_1302(0x84,0x00);//设置初始值HR

write_1302(0x86,0x00);//设置初始值DATE

write_1302(0x88,0x00);//设置初始值MONTH

write_1302(0x8A,0x00);//设置初始值DAY */

write_1302(0x8C,0x10);//设置初始值YEAR

}

//----------------------------------------------

void PORT_INIT() //端口初始化

{

P0=0XFE;

P1=0X00;

P2=0X00;

P3=0XFC;

}

void time_init() //定时器初始化

{

TMOD=0x11; //设置定时器0\1都为工作方式1

TH0=(65536-50000)/256; //装入初值

TL0=(65536-50000)%256;

TH1=(65536-10000)/256; //装入初值

TL1=(65536-10000)%256;

PT0=1; //T0定时器优先级最高

EA=1 ; //开总中断

ET0=1; //开定时器0中断

ET1=1; //开定时器1中断

TR0=1; //启动定时器0

TR1=1; //启动定时器1

}

//----------------------------------------------

void main(void) //主程序

{

PORT_INIT();

ds1302_init();

time_init();

year=read_1302(0x8d); //读年数据

year_data=0x2000|year;

write_595(year_data>>8); //显示20##年的20字样

ST_CP8=0;

ST_CP8=1;

ST_CP8=0;

set_shi=0x09; //闹钟初始值设定

set_fen=0x39;

time_flag=0; //标志位

set=0;

while(1)

{

switch(set)

{

case 0: //设置秒

{

display(); //显示子程序

if((shi==set_shi)&&(fen==set_fen)&&(time_flag==0)) //闹钟设定 只设定小时和分钟

{

speak=~speak;

if((K2==0)&&(time_flag==0)) //按键K2停止闹钟响

{

P0&=0XFE;

time_flag=1;

}

delay(10);

}

} break;

}

if(fen==set_fen+1) //当不按下闹钟停止按键,一分钟后自动停止闹钟

{

P0&=0XFE;

time_flag=0;

}

}

}

//----------------------------------------

void time0() interrupt 1 // 定时器0中断

{

TR0=0;

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;

mun++;

if(mun==15)

{

mun=0;

switch(set)

{

case 1: //设置秒闪烁

{

OE1=1;

delay(300);

OE1=0;

} break;

case 2: //设置分闪烁

{

OE2=1;

delay(300);

OE2=0;

} break;

case 3: //设置时闪烁

{

OE3=1;

delay(300);

OE3=0;

} break;

case 4: //设置日闪烁

{

OE4=1;

delay(300);

OE4=0;

} break;

case 5: //设置月闪烁

{

OE5=1;

delay(300);

OE5=0;

} break;

case 6: //设置年闪烁

{

OE6=1;

OE8=1;

delay(300);

OE6=0;

OE8=0;

} break;

case 7: //设置星期闪烁

{

OE7=1;

delay(200);

OE7=0;

} break;

case 8: //设置闹钟闪烁

{

OE2=1;

OE3=1;

delay(200);

OE2=0;

OE3=0;

} break;

}

}

TR0=1;

}

//-------------------------------------------

void time1() interrupt 3 // 定时器1中断

{

TR1=0; //先关定时器

TH1=(65536-20000)/256;

TL1=(65536-20000)%256;

//---------------------------------

if(K1==0)

{

delay(10);

if(K1==0)

{

set++;

if(set==9)

{

set=0;

write_1302(0x80,miao); //设置初始值SEC

write_1302(0x82,fen); //设置初始值MIN

write_1302(0x84,shi); //设置初始值HR

write_1302(0x86,date); //设置初始值DATE

write_1302(0x88,month); //设置初始值MONTH

write_1302(0x8A,day); //设置初始值DAY

write_1302(0x8C,year_data); //设置初始值YEAR

}

t=50000;

while((!K1)&&t)

{

t--;

}

}

}

//---------------------------------------

if(K2==0)

{

delay(10);

if(K2==0)

{

switch(set)

{

case 1:

{

miao++;

if((miao&0x0f)>0x09)

{

miao+=0x10;

miao&=0xf0;

}

if(miao==0x60)

{

miao=0x00;

}

write_595(miao);

ST_CP1=0;

ST_CP1=1;

ST_CP1=0;

} break;

case 2:

{

fen++;

if((fen&0x0f)>0x09)

{

fen+=0x10;

fen&=0xf0;

}

if(fen==0x60)

{

fen=0x00;

}

ST_CP2=0;

ST_CP2=1;

ST_CP2=0;

} break;

case 3:

{

if((read_1302(0x85)&0x80)==0x00)

{

shi++;

if((shi&0x0f)>0x09)

{

shi+=0x10;

shi&=0xf0;

}

if(shi==0x24) //24小时制

{

shi=0x00;

}

}

else

{

shi=(shi|0x80)+1;

if((shi&0x0f)>0x09)

{

shi+=0x10;

shi&=0xf0;

}

if(shi==0x12) //12小时制

{

shi=0X80;

}

}

write_595(shi); //显示时

ST_CP3=0;

ST_CP3=1;

ST_CP3=0;

} break;

case 4:

{

date++;

if((date&0x0f)>0x09)

{

date+=0x10;

date&=0xf0;

}

if((date==0x32)&&((month==0x01)||(month==0x03)||(month==0x05)||(month==0x07)||(month==0x08)||(month==0x10)||(month==0x12)))

{

date=0x01;

}

else if((date==0x31)&&((month==0x04)||(month==0x06)||(month==0x09)||(month==0x11)))

{

date=0x01;

}

else if((date==0x29)&&(month==0x02)&&((year_data|read_1302(0x8d))%100!=0)&&((year_data|read_1302(0x8d))%400!=0))

{

date=0x01;

}

else if((date==0x30)&&(month==0x02)&&((year_data|read_1302(0x8d))%100==0)&&((year_data|read_1302(0x8d))%400==0))

{

date=0x01;

}

write_595(date);

ST_CP4=0;

ST_CP4=1;

ST_CP4=0;

} break;

case 5:

{

month++;

if((month&0x0f)>0x09)

{

month+=0x10;

month&=0xf0;

}

if(month==0x13)

{

month=0x01;

}

write_595(month);

ST_CP5=0;

ST_CP5=1;

ST_CP5=0;

} break;

case 6:

{

year_data++;

if((year_data&0x000f)==0x0a)

{

year_data+=0x0010;

year_data&=0xfff0;

}

if((year_data&0x00ff)==0xa0)

{

year_data+=0x0100; //向前进1

year_data&=0xff00; //后面尾数归0

}

write_595(year_data);

ST_CP6=0;

ST_CP6=1;

ST_CP6=0;

write_595(year_data>>8);

ST_CP8=0;

ST_CP8=1;

ST_CP8=0;

} break;

case 7:

{

day++;

if((day&0x0f)==0x08)

{

day=0x01;

}

write_595(xingqi[day]);

ST_CP7=0;

ST_CP7=1;

ST_CP7=0;

} break;

}

t=50000;

while((!K2)&&t)

{

t--;

}

}

}

//--------------------------

if(K3==0)

{

delay(10);

if(K3==0)

{

switch(set)

{

case 1:

{

miao--;

if((miao&0x0f)==0x0F)

{

miao&=0xf9; //减到0后,再减一次就归0,

}

if(miao==0xF9) //当全部减到00时,再减一次就为59

{

miao=0x59;

}

write_595(miao);

ST_CP1=0;

ST_CP1=1;

ST_CP1=0;

} break;

case 2:

{

fen--;

if((fen&0x0f)==0x0F)

{

fen&=0xf9;

}

if(fen==0xF9)

{

fen=0x59;

}

write_595(fen);

ST_CP2=0;

ST_CP2=1;

ST_CP2=0;

} break;

case 3:

{

if((read_1302(0x85)&0x80)==0x00)

{

shi--;

if((shi&0x0f)==0x0F)

{

shi&=0xf9;

}

if(shi==0xF9) //24小时制

{

shi=0x23;

}

}

else

{

shi=(shi|0x80)-1;

if((shi&0x0f)==0x0F)

{

shi&=0xf9;

}

if(shi==0xF9) //12小时制

{

shi=0X12;

}

}

write_595(shi); //显示时

ST_CP3=0;

ST_CP3=1;

ST_CP3=0;

} break;

case 4:

{

date--;

if((date&0x0f)==0x0F)

{

date&=0xf9;

}

if((date==0x00)&&((month==0x01)||(month==0x03)||(month==0x05)||(month==0x07)||(month==0x08)||(month==0x10)||(month==0x12)))

{

date=0x31;

}

else if((date==0x00)&&((month==0x04)||(month==0x06)||(month==0x09)||(month==0x11)))

{

date=0x30;

}

else if((date==0x00)&&(month==0x02)&&((year_data|read_1302(0x8d))%100!=0)&&((year_data|read_1302(0x8d))%400!=0))

{

date=0x28;

}

else if((date==0x00)&&(month==0x02)&&((year_data|read_1302(0x8d))%100==0)&&((year_data|read_1302(0x8d))%400==0))

{

date=0x29;

}

write_595(date);

ST_CP4=0;

ST_CP4=1;

ST_CP4=0;

} break;

case 5:

{

month--;

if((month&0x0f)==0x0F)

{

month&=0xf9;

}

if(month==0x00)

{

month=0x12;

}

write_595(month);

ST_CP5=0;

ST_CP5=1;

ST_CP5=0;

} break;

case 6:

{

year_data--;

if((year_data&0x000f)==0x0F)

{

year_data&=0xfff9;

}

if((year_data&0x00f0)==0xF0)

{

year_data&=0xf999;

}

write_595(year_data);

ST_CP6=0;

ST_CP6=1;

ST_CP6=0;

write_595(year_data>>8);

ST_CP8=0;

ST_CP8=1;

ST_CP8=0;

} break;

case 7:

{

day--;

if((day&0x0f)==0x00)

{

day=0x07;

}

write_595(xingqi[day]);

ST_CP7=0;

ST_CP7=1;

ST_CP7=0;

} break;

}

t=50000;

while((!K3)&&t) //松手检测

{

t--;

}

}

}

//-----------------------------------

switch(set)

{

case 8:

{

if(K4==0)

{

delay(10);

if(K4==0)

{

if((read_1302(0x85)&0x80)==0x00)

{

set_shi++;

if((set_shi&0x0f)>0x09)

{

set_shi+=0x10;

set_shi&=0xf0;

}

if(set_shi==0x24) //24小时制

{

set_shi=0x00;

}

}

else

{

set_shi=(set_shi|0x80)+1;

if((set_shi&0x0f)>0x09)

{

set_shi+=0x10;

set_shi&=0xf0;

}

if(set_shi==0x12) //12小时制

{

set_shi=0X80;

}

}

write_595(set_shi); //显示闹钟的时

ST_CP3=0;

ST_CP3=1;

ST_CP3=0;

t=50000;

while((!K4)&&t)

{

t--;

}

}

}

//------------------------------------

if(K5==0)

{

delay(10);

if(K5==0)

{

set_fen++;

if((set_fen&0x0f)>0x09)

{

set_fen+=0x10;

set_fen&=0xf0;

}

if(set_fen==0x60)

{

set_fen=0x00;

}

write_595(set_fen);

ST_CP2=0;

ST_CP2=1;

ST_CP2=0;

t=50000;

while((!K5)&&t)

{

t--;

}

}

}

}

}

//-------------------------

if(((K4==0)||(K5==0))&&(set==0))

{

delay(10);

if(((K4==0)||(K5==0))&&(set==0))

{

write_595(set_shi); //显示闹钟的时

ST_CP3=0;

ST_CP3=1;

ST_CP3=0;

write_595(set_fen);

ST_CP2=0;

ST_CP2=1;

ST_CP2=0;

P1=0XF9;

while((!K4)||(!K5));

P1=0X00;

}

}

//------------------------------------------

TR1=1; //退出时开定时器

}

//--------------------------------------------------

相关推荐