AT89S52单片机的多功能电子万年历

更新时间:2023-03-08 09:58:46 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

摘 要:本文介绍了基于AT89S52单片机的多功能电子万年历的硬件结构和软硬件设计方法。本设计由数据显示模块、温度采集模块、时间处理模块和调整设置模块四个模块组成。系统以AT89S52单片机为控制器,以串行时钟日历芯片DS1302记录日历和时间,它可以对年、月、日、时、分、秒进行计时,还具有闰年补偿等多种功能。温度采集选用DS18B20芯片,万年历采用直观的数字显示,数据显示采用1602液晶显示模块,可以在LCD1602上同时显示年、月、日、周日、时、分、秒,还具有时间校准等功能。此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,具有广阔的市场前景。

关键字:单片机AT89S52 时钟芯片DS1302 温度传感器DS18B20 1602液晶显示器

I

前言

随着科技的快速发展,时间的流逝,从观太阳、摆钟到现在电子钟,人类不断研究,不断创新纪录。目前,单片机技术的应用产品已经走进了千家万户。电子万年历的出现给人们的生活带来了诸多方便。随着微电子技术的高速发展,单片机在国民经济的个人领域得到了广泛的运用。单片机以体积小、功能全、性价比高等诸多优点,在工业控制、家用电器、通信设备、信息处理、尖端武器等各种测控领域的应用中独占鳌头,单片机开发技术已成为电子信息、电气、通信、自动化、机电一体化等专业技术人员必须掌握的技术。

单片机单芯片的微小体积和低的成本,可广泛地嵌入到如玩具、家用电器、机器人、仪器仪表、汽车电子系统、工业控制单元、办公自动化设备、金融电子系统、舰船、个人信息终端及通讯产品中,成为现代电子系统中最重要的智能化工具,于是基于单片机的醒目而时尚的电子版万年历顺应而生。基于单片机的电子万年历结合了时钟和日历的功能,将其二者融为一体,在显示时间的同时还能显示日期和年、月,它主要是通过单片机来读取时钟芯片的时间、日期,然后送给显示设备显示出来。而电子万年历作为电子类小设计不仅是市场上的宠儿,也是是单片机实验中一个很常用的题目。因为它的有很好的开放性和可发挥性,因此对作者的要求比较高,不仅考察了对单片机的掌握能力更加强调了对单片机扩展的应用。而且在操作的设计上要力求简洁,功能上尽量齐全,显示界面也要出色。数字显示的日历钟已经越来越流行,特别是适合在家庭居室、办公室、大厅、会议室、车站和广场等使用,壁挂式LED数码管显示的日历钟逐渐受到人们的欢迎。LED数字显示的日历钟显示清晰直观、走时准确、可以进行夜视,并且还可以扩展出多种功能。

II

成都理工大学工程技术学院毕业设计

1 绪论

1.1 课题研究的背景 随着科技的快速发展,时间的流逝,从观太阳、摆钟到现在电子钟,人类不断研究,不断创新纪录。它可以对年、月、日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。

此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。 1.2课题的研究目的与意义

二十一世纪是数字化技术高速发展的时代,而单片机在数字化高速发展的时代扮演着极为重要的角色。电子万年历的开发与研究在信息化时代的今天亦是当务之急,因为它应用在学校、机关、企业、部队等单位礼堂、训练场地、教学室、公共场地等场合,可以说遍及人们生活的每一个角落。所以说电子万年历的开发是国家之所需,社会之所需,人民之所需。

由于社会对信息交换不断提高的要求及高新技术的逐步发展,促使电子万年历发展并且投入市场得到广泛应用。 1.3课题解决的主要内容

本课题所研究的电子万年历是单片机控制技术的一个具体应用,主要研究内容包括以下几个方面:

(1)选用电子万年历芯片时,应重点考虑功能实在、使用方便、单片存储、低功耗、抗断电的器件。

(2)根据选用的电子万年历芯片设计外围电路和单片机的接口电路。

(3)在硬件设计时,结构要尽量简单实用、易于实现,使系统电路尽量简单。 (4)根据设计的硬件电路,编写控制AT89S52芯片的单片机程序。

(5)通过编程、编译、调试,把程序下载到仿真单片机上运行,并实现本设计的功

能。

(6)在硬件电路和软件程序设计时,主要考虑提高人机界面的友好性,方便用户操

作等因素。

1

成都理工大学工程技术学院毕业设计

2 系统的方案设计与论证

单片机电子万年历的制作有多种方法,可供选择的器件和运用的技术也有很多种。所以,系统的总体设计方案应在满足系统功能的前提下,充分考虑系统使用的环境,所选的结构要简单使用、易于实现,器件的选用着眼于合适的参数、稳定的性能、较低的功耗以及低廉的成本。

系统的功能往往决定了系统采用的结构,经过成本,性能,功耗等多方面的考虑决定用三个8位74LS164串行接口外接LED显示器,RESPACK-8对单片机AT89S52进行供电,时间芯片DS1302连接单片机AT89S52。从而实现电子万年历的功能。

按照系统设计的要求,初步确定系统由电源模块、时钟模块、显示模块、键盘接口模块、温度测量模块和闹钟模块共六个模块组成,电路系统构成框图如图1所示。

电源模块时钟模块

温度模块显示模块AT89S52

独立按键闹钟模块

图1 硬件电路框图

2.1单片机芯片设计与论证

方案一:

采用AT89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能用于3V的超低电压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术, 当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。

方案二:

采用AT89S52芯片作为硬件核心,采用Flash ROM,能以3V的超低电压工作,而且与MCS-51系列单片机完全兼容,该芯片内部存储器为8KB ROM 存储空间。同样具有AT89S52的功能,且具有在线编程可擦除技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,不需要对芯片多次拔插,所以不会

15

成都理工大学工程技术学院毕业设计

对芯片造成损坏。

由于AT89S52内部具有8KBROM存储芯片并且支持ISP在线编程,因此采用AT89S52作为主控芯片。 2.2按键控制模块设计与论证

方案一:采用矩阵键盘,由于按键多可实现数值的直接键入,但在系统中需要CPU不间断的对其端口扫描。

方案二:采用独立按键,查询简单,程序处理简单,可节省CPU资源。

因系统中所需按键不多,为了释放更多的CPU占有时间,操作方便,故采用方案二。

2.3时钟模块设计与论证

方案一:直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。采用此种方案虽然减少芯片的使用,节约成本,但是,实现的时间误差较大。

方案二:采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、周、月、年以及闰年补偿的年进行计数,而且精度高,位的RAM作为数据暂存区,工作电压2.5V~5.5V范围内,2.5V时耗电小于300nA.

由于DS1302时钟芯片计数时间精度高,而且具有闰年补偿功能等优点,故采用方案二。

2.4温度采集模块设计与论证

方案一:采用温度传感器(如热敏电阻或AD590),再经AD转换得到数字信号,精度较准,但价格昂贵,电路较复杂。

方案二:采用数字式温度传感器DS18B20,它能直接读出被测温度,并且可根据实际要求通过简单的编程实现9-12位的数字值读数方式,但准确度不高,误差最大达2度。

因为用DS18B20温度芯片,采用单总线访问,降低成本、降低制作难度且可节省单片机资源,故采用方案二。 2.5显示模块模块设计与论证

方案一:采用静态显示方法,静态显示模块的硬件制作较复杂及功耗大,要用到多个移位寄存器,但不占用端口,只需两根串口线输出。

方案二:采用动态显示方法,动态显示模块的硬件制作简单,段扫描和位扫描各占用一个端口,总需占用单片机14个端口,采用间断扫描法功耗小、硬件成本低及整个硬件系统体积相对减小。

方案三:采用LCD的方法,具有硬件制作简单可直接与单片机接口,显示内容多,功耗小,成本低等优点,LCM1602可显示32个字符,采用LCD的缺点是亮度不够。

比较以上三种方案:方案一硬件复杂体积大、功耗大;方案二硬件简单、功耗小;方案三硬件简单,显示内容多,功耗小,成本低等。本系统设计要求达到功耗小、体积小、成本低,显示信息多等要求,权衡三种方案,选择方案三。

15

成都理工大学工程技术学院毕业设计

3 系统硬件的设计

根据上述所确定的系统方案构想,下面进行系统硬件电路的具体设计,系统的具体设计在下面会详细介绍。 3.1 AT89S51单片机

本系统采用的是美国ATMEL公司生产的AT89S52单片机,首先我们来熟悉一下AT89S52单片机的外部引脚和内部结构。 1.单片机的引脚功能

AT89S52单片机有40个引脚。 ? Vcc:电源电压+5V ? GND:接地

? P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能驱动8个TTL逻辑门电路,对端口写“1”可作为高阻抗输入端用。

在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8位)和数据总线服用,在访问期间激活内部上拉电阻。

在Flash编程时,P0口接收指令字节,而在程序校验时,输出指令字节,校验时要求外接上拉电阻。

? P1口:P1口是一个带内部上拉电阻的8位双向I/O,P1的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。

Flash 编程和程序校验期间,P1接收低8位地址。 ? P2口:P2口是一个带内部上拉电阻的8位双向I/O,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。

在访问外部程序存储器或16位地址的外部数据存储器(例如执行MOVX@DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据存储器(MOVX @Ri指令)时,P2口线上的内容(也即特殊功能寄存器(SFR)区中P2寄存器的内容),在整个访问期间不改变。

Flash 编程和程序校验期间,P2亦接收低高位地址和其他控制信号。 ? P3口:P3口是一组带内部上拉电阻的8位双向I/O,P3的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对P3口写入“1”时,它们被内部的上拉电阻拉高并可作为输入端口。作输入端时,被外部拉低的P3口将用上拉电阻输出电流。P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能,见表1所示: P3口还接收一些用于Flash闪速存储器编程和程序校验的控制信号。

表2 P3口的第二功能图

端口引脚

第二功能

15

成都理工大学工程技术学院毕业设计

P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7 RXD(串行输入口) TXD(串行输出口) INT0(外中断0) INT1(外中断1)

T0(定时/计时器0外部输入) T1(定时/计时器1外部输入) WR(外部数据存储器写选通) RD(外部数据存储器读选通)

? RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。WDT溢出将使引脚输出高电平,设置SFR AUXR的DISRT0(地址8EH)可打开或关闭该功能。DISRT0位缺省为RESET输出高电平打开状态。

? ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存器允许)输出脉冲用于锁存地址的低8位字节。即使不访问外部存储器,ALE仍以时钟振荡频率的1/6输出固定的正脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE脉冲。

对Flash存储器编程期间,该引脚还用于输入编程脉冲(PROG)。

如有必要,可通过多特殊功能寄存器(SFR)区中的8EH单元的D0位置,可禁止ALE操作。该位置后,只有一条MOVX和MOVC指令ALE才会被激活。另外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE无效。

? PSEN:程序存储允许(PSEN)输出是外部程序存储器的读选通信号,当AT89S52由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN有效,即输出两个脉冲。当访问外部数据存储器,没有两次有效的PSEN信号。

? EA/VPP:外部访问允许。欲使CPU仅访问外部程序存储器(地址为0000H—FFFFH),EA端必须保持低电平(接地)。需要注意的是:如果加密位LB1被编程,复位时内部会锁存EA端状态。

如EA端为高电平(接Vcc端),CPU则执行内部程序存储器中的指令。 Flash存储器编程时,该引脚加上+12V的变成电压Vpp. ? XTAL1:振荡器反相放大器及内部时钟发生器的输入端。 ? XTAL2:振荡器反相放大器的输出端。 AT89S52单片机内部结构

2.AT89S52单片机与MCS-51完全兼容

? 看门狗(WDT):WDT是一种需要软件控制的复位方式。WDT 由13位计数器和特殊功能寄存器中的看门狗定时器复位存储器(WDTRST)构成。WDT 在默认情况下无法工作;为了激活WDT,用户必须往WDTRST 寄存器(地址:0A6H)中依次写入01EH 和0E1H。当WDT激活后,晶振工作,WDT在每个机器周期都会增加。WDT计时周期依赖于外部时钟频率。除了复位(硬件复位或WDT溢出复位),没有办法停止WDT工作。当WDT溢出,它将驱动RSR引脚输出一个高电平。

? 可编程串口(UART)在AT89S52中,UART 的操作与AT89S52 和AT89C52 一样。AT89S52系列单片机的串行通信口可以工作于同步和异步通信方式。当工作于异步方式时,它具有全双工的操作功能,也就是说,它可以同时进行数据的发送和接收。串

15

成都理工大学工程技术学院毕业设计

行口内的接收器采用的是双缓冲结构,能够在接收到的第一个字节从接收寄存器读走之前就开始接收第二个字节(当然,如果第二个字节接收完毕,而第一个字节仍然没有被读走,那将会丢掉一个字节)。串行口的发送和接收操作都是通过特殊功能寄存器中的数据缓冲寄存器SBUF进行的,但在SBUF的内部,接收寄存器和发送寄存器在物理结构上是完全独立的。如果将数据写入SBUF,数据会被送入发送寄存器准备发送。如果执行SBUF指令,则读出的数据一定来自接收缓存器。因此,CPU对SBUF的读写,实际上是分别访问2个不同的寄存器。这2个寄存器的功能决不能混淆。

? 振荡电路:AT89S52系列单片机的内部振荡器,由一个单极反相器组成。XTAL1反相器的输入,XTAL2为反相器的输出。可以利用它内部的振荡器产生时钟,只要XTAL1和XTAL2引脚上一个晶体及电容组成的并联谐振电路,便构成一个完整的振荡信号发生器,此方式称为内部方式。另一种方式由外部时钟源提供一个时钟信号到XTAL1端输入,而XTAL2端浮空。在组成一个单片机应用系统时,多数采用这种方式,这种方式结构紧凑,成本低廉,可靠性高。在电路中,对电容C1和C2的值要求不是很严格,如果使用高质的晶振,则不管频率为多少,C1、C2通常都选择30pF。

? 定时/计数器:AT89S52单片机内含有2个16位的定时器/计数器。当用于定时器方式时,定时器的输入来自内部时钟发生电路,每过一个机器周期,定时器加1,而一个机器周期包含有12个振荡周期,所以,定时器的技术频率为晶振频率的1/12,而计数频率最高为晶振频率的1/24。为了实现定时和计数功能,定时器中含有3种基本的寄存器:控制寄存器、方式寄存器和定时器/计数器。控制寄存器是一个8位的寄存器,用于控制定时器的工作状态,方式寄存器是一个8位的寄存器,用于确定定时器的工作方式,定时器/计数器是16位的计数器,分为高字节和低字节两部分。

? RAM:高于7FH内部数据存储器的地址是8位的,也就是说其地址空间只有256字节,但内部RAM的寻址方式实际上可提供384字节。的直接地址访问同一个存储空间,高于7FH的间接地址访问另一个存储空间。这样,虽然高128字节区分与专用寄器 ,即特殊功能寄存器区的地址是重合的,但实际上它们是分开的。究竟访问哪一区,存是通过不同的寻址方式加以区分的。

? SFR:SFR是具有特殊功能的所有寄存器的集合,共含有22个不同寄存器,它们的地址分配在80H~FFH中。虽然如此,不是所有的单元都被特殊功能寄存器占用,未被占用的单元,其内容是不确定的。如对这些单元进行读操作,得到的是一些随机数,而写入则无效,所以在编程时不应该将数据写入这些未确定的地址单元中,特殊功能寄存器主要有累加器ACC、B寄存器、程序状态字寄存器PSW、堆栈指针SP、数据指针DPTR、I/O端口、串行口数据缓冲器SBUF、定时器寄存器、捕捉寄存器、控制寄存器

? 中断系统:AT89S52单片机有6个中断源,中断系统主要由中断允许寄存器IE、中断优先级寄存器IP、优先级结构和一些逻辑门组成。IE寄存器用于允许或禁止中断;IP寄存器用于确定中断源的优先级别;优先级结构用于执行中断源的优先排序;有关逻辑门用于输入中断请求信号。在整个中断响应过程中CPU所执行的操作步骤如下:

(1)完成当前指令的操作 (2)将PC内容压入堆栈

15

成都理工大学工程技术学院毕业设计

(3)保存当前的中断状态 (4)阻止同级的中断请求

(5)将中断程序入口地址送PC寄存器 (6)执行中断服务程序 (7)返回

3.2时钟芯片DS1302接口设计与性能分析

3.2.1 DS1302性能简介

DS1302是Dallas公司生产的一种实时时钟芯片。它通过串行方式与单片机进行数据传送,能够向单片机提供包括秒、分、时、日、月、年等在内的实时时间信息,并可对月末日期、闰年天数自动进行调整;它还拥有用于主电源和备份电源的双电源引脚,在主电源关闭的情况下,也能保持时钟的连续运行。另外,它还能提供31字节的用于高速数据暂存的RAM。

DS1302时钟芯片内主要包括移位寄存器、控制逻辑电路、振荡器。DS1302与单片机系统的数据传送依靠RST,I/O,SCLK三根端线即可完成。其工作过程可概括为:首先系统RST引脚驱动至高电平,然后在SCLK时钟脉冲的作用下,通过I/O引脚向DS1302输入地址/命令字节,随后再在SCLK时钟脉冲的配合下,从I/O引脚写入或读出相应的数据字节。因此,其与单片机之间的数据传送是十分容易实现的,DS1302的引脚排列及内部结构图如图2:

DS1302引脚说明:

X1,X2 32.768kHz晶振引脚 GND 地线 RST 复位端

I/O 数据输入/输出端口 SCLK 串行时钟端口 VCC1 慢速充电引脚 VCC2 电源引脚

图2 DS1302管脚 3.2.2 DS1302接口电路设计

1时钟芯片DS1302的接口电路及工作原理:

图3 DS1302与MCU接口电路

15

成都理工大学工程技术学院毕业设计

图3为DS1302的接口电路,其中Vcc1为后备电源,Vcc2为主电源。VCC1在单电源与电池供电的系统中提供低电源并提供低功率的电池备份。VCC2在双电源系统中提供主电源,在这种运用方式中VCC1连接到备份电源,以便在没有主电源的情况下能保存时间信息以及数据。

DS1302由VCC1或VCC2 两者中较大者供电。当VCC2大于VCC1+0.2V时,VCC2给DS1302供电。当VCC2小于VCC1时,DS1302由VCC1供电。

DS1302在每次进行读、写程序前都必须初始化,先把SCLK端置 “0”,接着把RST端置“1”,最后才给予SCLK脉冲;读/写时序如下图5所示。表-1为DS1302的控制字,此控制字的位7必须置1,若为0则不能对DS1302进行读写数据。对于位6,若对时间进行读/写时,CK=0,对程序进行读/写时RAM=1。位1至位5指操作单元的地址。位0是读/写操作位,进行读操作时,该位为1;进行写操作时,该位为0。控制字节总是从最低位开始输入/输出的。表-2为DS1302的日历、时间寄存器内容:“CH”是时钟暂停标志位,当该位为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位为0时,时钟开始运行。“WP”是写保护位,在任何的对时钟和RAM的写操作之前,“WP”必须为0。当“WP”为1时,写保护位防止对任一寄存器的写操作。 2、DS1302的控制字

DS1302的控制字如表2所示。控制字节的高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为1表 示进行读操作,为0表示进行写操作。控制字节总是从最低位开始输出。

表3 DS1302的控制字格式 1 RAM/CK A4 A3 A2 A1 A0 RD/WR

3、数据输入输出(I/O)

在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。如下图4所示。

图4 DS1302读/写时序图 4、DS1302的寄存器AM

———

15

成都理工大学工程技术学院毕业设计

总结

在整个设计过程中,硬件方面主要设计了AT89S52单片机的最小系统、DS1302接口电路、DS18B20接口电路、闹钟及LCD显示;软件方面借助各个渠道的资料,主要设计了阳历数据读取程序、阳历转阴历程序、温度采集程序、闹铃程序以及LCD显示程序;系统的调试主要是通过一块AT89S52开发板,再借助于Keil、STC以及少许自己搭建的外围电路实现的;再此过程中,分步调试时显示出了阳历的日期及时间,还有实时温度,集中调试时没有达到预期效果。此万年历具有读显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。

在整个设计过程中学到了许多没学到的知识,在电路焊接时虽然没什么大问题,但从中也知道了焊接在整个作品中的重要性,电路工程量大,不能心急,一个个慢慢来不能急于求成。反而达到事半功倍的效果。对电路的设计、布局要先有一个好的构思,才显得电路板美观、大方。程序编写中,由于思路不清晰,开始时遇到了很多的问题,经过静下心来思考,理清了思路,反而得心应手。在此次设计中,知道了做事要有一颗平常的心,不要想着走捷径,一步一脚印。也练就了我们的耐心,做什么事都要有耐心。在本次设计中学到了很多很多东西,这是最重要的。

总之,此次毕业设计使我们的能力得到了全方位的提高,这次设计的电子万年历也存在的不足的地方,有待于以后的改进。

26

成都理工大学工程技术学院毕业设计

参考文献:

[1] 苏平.单片机的原理与接口技术[M].北京:电子工业出版社,2006,1-113. [2] 王忠民.微型计算机原理[M].西安:西安科技大学出版社,2003,15-55. [3] 左金生.电子与模拟电子技术[M].北京:电子工业出版社,2004,105-131. [4] 新编单片机原理与应用(第二版).西安电子科技大学出版社,2007.2 [5] 张萌.单片机应用系统开发综合实例[M]. 北京:清华大学出版社,2007.7 [6] 朱思荣.51单片机实现公历与农历、星期的转换[Z].当当电子网 [7] 李广弟. 单片机原理及应用[M] 北京航空航天大学出版社,2004年 [8] 王越明.电子万年历的设计[J].黑龙江科技信息,2004年

27

成都理工大学工程技术学院毕业设计

附录一(程序)

#include

//#include\#include #include

#define uint unsigned int #define uchar unsigned char

#define wd 1 //定义是否有温度功能 =0时无温度,=1时有温度

#define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)

#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)

//液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口) sbit en=P2^7;

sbit rw=P2^6; //如果硬件上rw接地,就不用写这句和后面的rw=0了 sbit rs=P2^5;

//校时按键与C51的引脚连接定义

sbit set=P3^0; //设置键 sbit add=P3^1; //加键 sbit dec=P3^2; //减键

sbit seeNL_NZ=P3^3; //查看农历/闹钟

sbit DQ=P3^7; // sbit buzzer=P2^0; //蜂鸣器,通过三极管8550驱动,端口低电平响

sbit led=P2^4; //LCD背光开关 bit led1=1;

unsigned char temp_miao;

unsigned char bltime; //背光亮的时间

//DS1302时钟芯片与C51之间的引脚连接定义 sbit IO=P1^1; sbit SCLK=P1^0; sbit RST=P1^2;

27

成都理工大学工程技术学院毕业设计

uchar a,miao,shi,fen,ri,yue,nian,week,setn,temp; uint flag;

//flag用于读取头文件中的温度值,和显示温度值 bit c_moon;

uchar nz_shi=12,nz_fen=0,nz_miao=0,setNZn; //定义闹钟变量 uchar shangyimiao,bsn,temp_hour; //记录上一秒时间 uchar T_NL_NZ; //计数器

bit timerOn=0; //闹钟启用标志位 bit baoshi=0; //整点报时标志位

bit p_r=0; //平年/润年 =0表示平年,=1表示润年

data uchar year_moon,month_moon,day_moon,week;

sbit ACC0=ACC^0; sbit ACC7=ACC^7;

/************************************************************ ACC累加器=A ACC.0=E0H

ACC.0就是ACC的第0位。Acc可以位寻址。

累加器ACC是一个8位的存储单元,是用来放数据的。但是,这个存储单元有其特殊的地位,

是单片机中一个非常关键的单元,很多运算都要通过ACC来进行。以后在学习指令时, 常用A来表示累加器。但有一些地方例外,比如在PUSH指令中,就必须用ACC这样的名字。

一般的说法,A代表了累加器中的内容、而ACC代表的是累加器的地址。 ***************************************************************/

//********阳历转换阴历表************************************ code uchar year_code[597]={

0x04,0xAe,0x53, //1901 0 0x0A,0x57,0x48, //1902 3 0x55,0x26,0xBd, //1903 6 0x0d,0x26,0x50, //1904 9 0x0d,0x95,0x44, //1905 12 0x46,0xAA,0xB9, //1906 15 0x05,0x6A,0x4d, //1907 18 0x09,0xAd,0x42, //1908 21

27

成都理工大学工程技术学院毕业设计

0x24,0xAe,0xB6, //1909 0x04,0xAe,0x4A, //1910 0x6A,0x4d,0xBe, //1911 0x0A,0x4d,0x52, //1912 0x0d,0x25,0x46, //1913 0x5d,0x52,0xBA, //1914 0x0B,0x54,0x4e, //1915 0x0d,0x6A,0x43, //1916 0x29,0x6d,0x37, //1917 0x09,0x5B,0x4B, //1918 0x74,0x9B,0xC1, //1919 0x04,0x97,0x54, //1920 0x0A,0x4B,0x48, //1921 0x5B,0x25,0xBC, //1922 0x06,0xA5,0x50, //1923 0x06,0xd4,0x45, //1924 0x4A,0xdA,0xB8, //1925 0x02,0xB6,0x4d, //1926 0x09,0x57,0x42, //1927 0x24,0x97,0xB7, //1928 0x04,0x97,0x4A, //1929 0x66,0x4B,0x3e, //1930 0x0d,0x4A,0x51, //1931 0x0e,0xA5,0x46, //1932 0x56,0xd4,0xBA, //1933 0x05,0xAd,0x4e, //1934 0x02,0xB6,0x44, //1935 0x39,0x37,0x38, //1936 0x09,0x2e,0x4B, //1937 0x7C,0x96,0xBf, //1938 0x0C,0x95,0x53, //1939 0x0d,0x4A,0x48, //1940 0x6d,0xA5,0x3B, //1941 0x0B,0x55,0x4f, //1942 0x05,0x6A,0x45, //1943 0x4A,0xAd,0xB9, //1944 0x02,0x5d,0x4d, //1945 0x09,0x2d,0x42, //1946 0x2C,0x95,0xB6, //1947 0x0A,0x95,0x4A, //1948 0x7B,0x4A,0xBd, //1949 0x06,0xCA,0x51, //1950 0x0B,0x55,0x46, //1951 0x55,0x5A,0xBB, //1952

27

成都理工大学工程技术学院毕业设计

year=temp1*16+temp2; temp1=month/16; temp2=month;

//month=temp1*10+temp2; month=temp1*16+temp2; temp1=day/16; temp2=day;

//day=temp1*10+temp2; day=temp1*16+temp2; //定位数据表地址

if(c==0){

table_addr=(year+0x64-1)*0x3; }

else {

table_addr=(year-1)*0x3; }

//定位数据表地址完成

//取当年春节所在的公历月份

temp1=year_code[table_addr+2]&0x60; temp1=_cror_(temp1,5);

//取当年春节所在的公历月份完成 //取当年春节所在的公历日

temp2=year_code[table_addr+2]&0x1f; //取当年春节所在的公历日完成

// 计算当年春年离当年元旦的天数,春节只会在公历1月或2月 if(temp1==0x1){ temp3=temp2-1; } else{

temp3=temp2+0x1f-1; }

// 计算当年春年离当年元旦的天数完成

//计算公历日离当年元旦的天数,为了减少运算,用了两个表 //day_code1[9],day_code2[3]

//如果公历月在九月或前,天数会少于0xff,用表day_code1[9], //在九月后,天数大于0xff,用表day_code2[3]

//如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1 //如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1 if (month<10){

temp4=day_code1[month-1]+day-1; } else{

temp4=day_code2[month-10]+day-1; }

27

成都理工大学工程技术学院毕业设计

if ((month>0x2)&&(year%0x4==0)){ //如果公历月大于2月并且该年的2月为闰月,天数加1

temp4+=1; }

//计算公历日离当年元旦的天数完成 //判断公历日在春节前还是春节后

if (temp4>=temp3){ //公历日在春节后或就是春节当日使用下面代码进行运算 temp4-=temp3; month=0x1;

month_p=0x1; //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月

flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0 flag_y=0;

if(flag2==0)temp1=0x1d; //小月29天 else temp1=0x1e; //大小30天

temp2=year_code[table_addr]&0xf0;

temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月

while(temp4>=temp1){ temp4-=temp1; month_p+=1;

if(month==temp2){ flag_y=~flag_y;

if(flag_y==0)month+=1; }

else month+=1;

flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; }

day=temp4+1; }

else{ //公历日在春节前使用下面代码进行运算 temp3-=temp4;

if (year==0x0){year=0x63;c=1;} else year-=1; table_addr-=0x3; month=0xc;

temp2=year_code[table_addr]&0xf0; temp2=_cror_(temp2,4); if (temp2==0) month_p=0xc; else

27

成都理工大学工程技术学院毕业设计

month_p=0xd; //

//month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12

flag_y=0;

flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; while(temp3>temp1){ temp3-=temp1; month_p-=1;

if(flag_y==0)month-=1;

if(month==temp2)flag_y=~flag_y;

flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; }

day=temp1-temp3+1; }

c_moon=c; //HEX->BCD ,运算结束后,把数据转换为BCD数据 temp1=year/10;

temp1=_crol_(temp1,4); temp2=year;

year_moon=temp1|temp2; temp1=month/10;

temp1=_crol_(temp1,4); temp2=month;

month_moon=temp1|temp2; temp1=day/10;

temp1=_crol_(temp1,4); temp2=day;

day_moon=temp1|temp2; } /*

函数功能:输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年) 调用函数示例:Conver_week(c_sun,year_sun,month_sun,day_sun) 如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);

c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世

纪,c_sun=1为19世纪

调用函数后,原有数据不变,读week得出阴历BCD数据

27

成都理工大学工程技术学院毕业设计

*/

code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表 /*

算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期但如果是在 闰年又不到3 月份上述之和要减一天再除7 星期数为0 */

void Conver_week(uchar year,uchar month,uchar day)

{//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据 uchar p1,p2;

year+=0x64; //如果为21世纪,年份数加100 p1=year/0x4; //所过闰年数只算1900年之后的 p2=year+p1;

p2=p2%0x7; //为节省资源,先进行一次取余,避免数大于0xff,避免使用整型数据

p2=p2+day+table_week[month-1]; if (year%0x4==0&&month<3)p2-=1; week=p2%0x7; }

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

uchar code tab1[]={\//年显示的固定字符 uchar code tab2[]={\ //时间显示的固定字符 uchar code nlp[]={\//农历平年显示 uchar code nlr[]={\//农历润年显示 uchar code NZd[]={\//显示闹钟固定点 uchar code qk[]= {\//清空显示 uchar code tm[]= {\

//=====================DS18B20=============================================

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

void Delayns(int num)//延时函数 {

while(num--); }

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

27

成都理工大学工程技术学院毕业设计

*******

void Init_DS18B20(void)//初始化ds1820 {

unsigned char x=0; DQ = 1; //DQ复位 Delayns(8); //稍做延时

DQ = 0; //单片机将DQ拉低

Delayns(80); //精确延时 大于 480us DQ = 1; //拉高总线 Delayns(14);

x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 Delayns(20); }

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

unsigned char ReadOneChar(void)//读一个字节 {

unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) {

DQ = 0; // 给脉冲信号 dat>>=1;

DQ = 1; // 给脉冲信号 if(DQ) dat|=0x80; Delayns(4); }

return(dat); }

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

void WriteOneChar(unsigned char dat)//写一个字节 {

unsigned char i=0; for (i=8; i>0; i--) {

DQ = 0;

DQ = dat&0x01; Delayns(5); DQ = 1; dat>>=1; }

27

本文来源:https://www.bwwdw.com/article/gh93.html

Top