万年历课程设计报告

更新时间:2023-12-23 18:47:01 阅读量: 教育文库 文档下载

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

南 阳 理 工 学 院 计 算 机 与 信 息 工 程 学 院 软硬件专业综合课程设计总结报告

题目:基于单片机的万年历设计

姓 名: 陈振伟 学 号: 1206644030 专 业: 12通信工程(升) 指导教师: 鲁庆宾 起止日期: 13.11.18—14.01.10

南 阳 理 工 学 院 计 算 机 与 信 息 工 程 学 院 软硬件专业综合课程设计任务书

实践题目 学生姓名 指导教师 实践日期 陈振伟 鲁庆宾 班级 职称 基于单片机的万年历的设计 12通信工程 副教授 学号 实践地点 1206644030 南阳理工学院 2013年11月18日起至2014年1月10日 选题的目的: 二十一世纪的今天,最具代表性的计时产品就是电子万年历,它是近代世界钟表业界的第三次革命。第一次是摆和摆轮游丝的发明,相对稳定的机械振荡频率源使钟表的走时差从分级缩小到秒级。第二次革命是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,使钟表的走时月差从分级缩小到秒级。第三次革命就是单片机数码计时技术的应用(电子万年历),使计时产品的走时日差从分级缩小到1/600万秒,从原有传统指针计时的方式发展为人们日常更为熟悉的夜光数字显示方式。 技术要求: 1、通过查阅有关资料用AT89C51单片机设计一个万年历; 2、系统的主要功能有: (1) 能够通过按键进行日期、时、分、秒的调整; (2) 可以实现实时温度更新显示; (3) 能够显示日期、时间、温度及星期; 进度安排: 2013年11月18日——2013年11月30日 查阅资料、项目总体分析 2013年12月01日——2013年12月13日 系统功能总体设计 2013年12月14日——2013年12月26日 软件程序及硬件电路设计 2013年12月27日——2014年01月03日 软硬件系统调试、测试 2014年01月04日——2014年01月08日 撰写实训报告 2014年01月09日——2014年01月10日 验收 主要参考资料: [1] 王新颖单片机原理及应用北京大学出版社 2008 [2] 陈忠平 单片机基础与最小系统实践.北京航空航天大学出版社 [3] 窦振中 单片机外围器件实用手册存储器分册.北京航空航天大学出版社 教师签名: 年 月 日

I

摘 要

随着社会、科技的发展,人类得知时间,从观太阳、摆钟到现在电子钟,不断研究、创新。为了在观测时间的同时,能够了解其它与人类关系相关的信息,比如温度、星期、日期等,电子万年历诞生了,它集时间、日期、星期和温度功能与一身,具有读取方便、显示直观、功能多样、电路简洁等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景,该电子万年历主要采用AT89C51单片机作为主控核心,由DS1302时钟芯片提供时钟、DS18B20温度传感芯片提供温度数据、LCD液晶显示屏显示。AT89C51单片机是由Atmel公司推出的,功耗小,电压可选用4~6V电压供电;DS1302时钟芯片是美国DALLAS公司推出的具有涓细电流充电功能的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小;DS18B20温度芯片是一种测量精度高的数字温度传感器,具有只需要一个数据电缆传输数据,电路连接简单的特点;数字显示是采用的LCD液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒和温度等信息。此外,该电子万年历还具有时间校准等功能。

关键词:时钟芯片DS1302;LCD液晶显示;单片机AT89C51;时钟电路;数字显示;DS18B20温度传感芯片;

II

目 录

摘 要 .............................................................................................................................................. II 目 录 ............................................................................................................................................ III 第1章 绪论 ..................................................................................................................................... 1 第2章 功能要求 .............................................................................................................................. 2 第3章 方案论证与设计 .................................................................................................................... 2 3.1 控制部分的方案选择 ............................................................... 2 3.2 测温部分的方案选择 ............................................................... 3 3.3 显示部分的方案选择 ................................................................. 3 第4章 系统硬件电路设计 ................................................................................................................ 3 4.1 主控器 AT89C51 ................................................................... 4 4.2 时钟电路 DS1302 ................................................................. 4 4.2.1. DS1302的性能特性 ........................................................... 4 4.2.2 DS1302数据操作原理 .......................................................... 5 4.3 测温电路的设计 ................................................................... 7 4.3.1 温度传感器工作原理 ........................................................... 7 4.5 键盘接口的设计 ................................................................. 12 第5章 系统程序的设计 .................................................................................................................. 12 5.1 阳历程序设计 .................................................................... 12 5.2 时间调整程序设计 ................................................................ 13 5.3 温度程序设计 .................................................................... 15 5.3.1 主程序 ...................................................................... 15 5.3.2 读出温度子程序 .............................................................. 15 5.3.3 温度转换命令子程序 .......................................................... 16 5.3.4 计算温度子程序 .............................................................. 16 5.3.5显示数据刷新子程序 .......................................................... 16 第6章 调试及性能分析 .................................................................................................................. 17 6.1 调试步骤 ........................................................................ 17 6.2 性能分析 ........................................................................ 17 结论 ................................................................................................................................................ 18 参考文献 ......................................................................................................................................... 19 附录 ................................................................................................................................................ 20 软硬件专业综合课程设计考核表...................................................................................................... 40

III

第1章 绪论

随着电子技术的高速发展,对电子方面人才的要求越来越高,不仅要求其具备相关的专业理论知识,还要求其具有较强的设计、制作等实践动手能力.此次学校举行的电子设计无疑是对从事电子相关专业的人的一次很好的锻炼和考验,是培养信息人才的一次良好的机会,为其提供了一个理论知识与实践相结合的平台。 通过本次课程设计,引导学生结合所学的电路理论和程序设计的知识,思考设计方案,以小组合作方式,分工完成各个部分,从而掌握相关的硬件结合软件显示电路的设计和调试技术,一方面提高了学生的实践动手和协作能力,另一方面培养了学生综合运用所学理论知识进行工程设计的能力本设计为软件,硬件相结合的一组设计。在软件设计过程中,应对硬件部分有相关了解,这样有助于对设计题目的更深了解,有助于软件设计。基本的要了解一些主要器件的基本功能和作用。

除了采用集成化的时钟芯片外,还有采用MCU的方案,利用AT89系列单片微机制成万年历电路,采用软件和硬件结合的方法,控制LCD液晶屏输出,分别用来显示年、月、日、使、分、秒、星期、温度,其最大特点是:硬件电路简单,方案方便易于实现,软件设计独特,可靠。AT89C51是由ATMEL公司推出的一种小型单片机。95年出现在中国市场。其主要特点为采用Flash存储器技术,降低了制造成本,其软件、硬件与MCS-51完全兼容,可以很快被中国广大用户接受。

本文介绍了基于AT89C51单片机设计的电子万年历。

首先我们在绪论中简单介绍了单片机的发展与其在中低端领域中的优势以及课题的开发意义;接着介绍了AT89C51单片机的硬件结构和本课程设计所要外扩的LCD显示的方法,并在此基础上实现了万年历基本电路的设计;然后使用C语言进行万年历程序的设计,程序采用模块化结构,使得逻辑关系简单明了。

1

第2章 功能要求

1. 万年历能用数码管显示阳历年、月、日、星期、[小]时、分、秒并设置指定时间的闹铃。

2. 数字式温度计要求测温范围-50~100°C, LCD数码管直读显示。

第3章 方案论证与设计

3.1 控制部分的方案选择

1. 用可编程逻辑器件设计。可采用ALTERA公司的FLEX10K系列PLD器件。设计起来结构清晰,各个模块,从硬件上设计起来相对简单,控制与显示的模块间的连接也会比较方便。但是考虑到本设计的特点,EDA在功能扩展上比较受局限,而且EDA占用的资源也相对多一些。从成本上来讲,用可编程逻辑器件来设计也没有什么优势。

2. 用凌阳16位单片机设计。凌阳16位单片机有丰富的中断源和时基,方便本实验的设计。它的准确度相当高,并且C语言和汇编兼容的编程环境也很方便来实现一些递归调用。I/O口功能也比较强大,方便使用。用凌阳16位单片机做控制器最有特色的就是它的可编程音频处理,可完成语音的录制播放和识别。这些都方便对设计进行扩展,使设计更加完善。成本也相对低一些。但是,在控制与显示的结合上有些复杂,显示模组资源相对有限,而且单片机的稳定性不是很高。

3. 主控芯片使用51系列AT89C52单片机,时钟芯片用美国DALLAS公司推出的一种高性能、低功耗、带RAM的时钟DS1302。采用DS1302作为主要计时芯片,可以做到计时准确。更重要的是,DS1302可以在很小电流的后备电源(2.5~5V电源,在2.5V时耗电小于300nA)下继续计时,停电后时钟无需重新调整,并可编程选择多种充电电流来对后备电源进行慢速充电,可以保证后备电源基本不耗电,还可自设闹铃,阳历、星期与年月日自动对应。本系统采用了此方案。

2

3.2 测温部分的方案选择

1.在日常生活及工农业生产中经常要乃至温度的检测及控制,传统的测温元件有热电偶和热电阻。而热电偶和热电阻测一般都是电压,再转换成对应的温度,需要比较多的外部硬件支持,硬件电路复杂,软件调试复杂,制作成本高。 2.与前面相比,采用美国DALLAS半导体公司继DS1820之后推出的一种改进型智能温度传感器DS18B20作为检测元件,测温范围为-55~125°C,最大分辨率可达0.0625°C。DS18B20可以直接读出被测温度值,而且采用3线制与单片机相连,减少了外部的硬件电路,具有低成本和易使用的特点。

3.3 显示部分的方案选择

1. 液晶显示方式。液晶显示效果出众,可以运用菜单项来方便操作,但是在显示时,特别是使用秒表功能时扫描速度跟不上,屏幕会有明显的闪烁。而且由于61板的存储空间有限,液晶显示就不能与语音播抱程序同时实现。这些大大影响了电子万年历的性能。

2. 相比液晶显示,8段数码管虽然操作比液晶显示略显繁琐,但可视范围十分宽,而且经济实惠,也不需要复杂的驱动程序。所以最后选择LCD数码管显示方案。

综上所述,按照系统设计功能的要求,确定硬件系统由主控制器、时钟模块、测温电路、显示模块、键盘接口共5个模块组成,总体系统构成框图如图3.1所示。

图3-1 电子万年历系统构成框图

DS18B20温度探DS1302时钟模块 AT89C51 主控制器 键盘扫描电数码显示电

第4章 系统硬件电路设计

3

电子万年历电路原理图见附件一,系统由主控制器AT89C51、时钟芯片DS1302、温度传感器DS18B20传感器、显示电路及键盘扫描电路组成。

4.1 主控器 AT89C51

ATMEL公司生产的AT89C52单片机采用高性能的静态80C51设计,由先进工艺制造,并带有非易失性Flsah程序存储器。它是一种高性能、低功耗的8位CMOS微处理芯片,市场应用最多。主要性能特点有:

8KB Flash ROM,可以檫写1000次以上,数据保存10年。 256字节内部RAM。 电源控制模式

——时钟可停止和恢复; ——空闲模式; ——掉电模式。 6个中断源。 4个中断优先级。 4个8位I/O口。 全双工增强型UART。

3个16位定时/计数器,T0、T1(标准80C51)和增加的T2(捕获和比较)。

全静态工作方式:0~24MHz。

4.2 时钟电路 DS1302

4.2.1. DS1302的性能特性

实时时钟,可对秒、分、时、日、周、月以及带闰年补偿的年进行计数; 用于高速数据暂存的31×8位RAM; 最少引脚的串行I/O; 2.5~5.5V电压工作范围; 2.5V时耗电小于300nA;

用于时钟或RAM数据读/写的单字节或多字节(脉冲方式)数据传送方式; 简单的3线接口;

可选的慢速充电(至Vcc1)的能力。

DS1302时钟芯片包括实时时钟/日历和31字节的静态RAM。它经过一个简

4

单的串行接口与微处理器通信。实时时钟/日历提供秒、分、时、日、周、月和年等信息。对于小于31天的月和月末的日期自动调整,还包括闰年校正的功能。时钟的运行可以采用24h或带AM(上午)/PM(下午)的12h格式。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302有主电源/后备电源双电源引脚:Vcc1在单电源与电池供电的系统中提供低电源,并提供低功率的电池备份;Vcc2在双电源系统中提供主电源,在这种运用方式中,Vcc1连接到备份电,以便在没有主电源的情况下能保存时间信息以及数据。DS1302由Vcc1或Vcc2中较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电;当Vcc2小于Vcc时, DS13026由Vcc1供电。

4.2.2 DS1302数据操作原理

DS1302在任何数据传送时必须先初始化,把RST脚置为高电平,然后把8位地址和命令字装入移位寄存器,数据在SCLK的上升沿被输入。无论是读周期还是写周期,开始8位指定40个寄存器中哪个将被访问到。在开始8个时钟周期,把命令字节装入移位寄存器之后,另外的时钟周期在读操作时输出数据,在写操作是写入时写入数据。时钟脉冲的个数在单字节方式下为8加8,在多字节方式下为8加字节数,最大可达248字节数。

如果在传送过程中置RST脚为低电平,则会终止本次数据传送,并且I/O引脚变为高阻态。上电运行时,在Vcc大于等于2.5V之前,RST脚必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。DS1302的引脚及内部结构图如图4.1所示,表4.1为各引脚的功能。

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

为了提高对32个地址的寻址能力(地址/命令位1~5=逻辑1),可以把时钟/日历或RAM寄存器规定为多字节(burst)方式。位6规定时钟或RAM,而位0规定读或写。在时钟/日历寄存器中的地址9~31或RAM寄存器中的地址31不能寄存数据。在多字节方式中,读或写从地址0的位0开始。必须按数据传送的

5

次序写最先的8个寄存器。但是,当以多字节方式写RAM时,为了传送数据不必写所有31字节。不管是否写了全部31字节,所写的每一字节都将传送至RAM。

Vcc2 X1 X2 GND 1 2 3 4 8 7 6 5 Vcc1 SCLK I/O RST

Vcc1 Vcc2 GND I/O 电源 控制 实时时钟 输入移位寄存器 DATA BUS 32.768kHz X1 振荡器与分频器 X2

SCLK RST 命令与 控制逻辑 31×8RAM 图 4.1 DS1302引脚及内部结构

表 4.1 DS1302引脚功能

引脚号 1 2,3 4 5 6 7 8

1 RAM A4 A3 A2 A1 A0 RAM K 引脚名称 Vcc2 X1,X2 GND RST I/O SCLK Vcc1 功 能 主电源 振荡源,外界32.768kHz晶振 地线 复位/片选线 串行数据输入/输出端(双向) 串行数据输入端 后备电池 CK 图 4.2 DS1302的控制字

DS1302共有12个寄存器,其中有7个寄存器与日历、时钟相关,存

放的数据位为BCD码形式。其日历、时间寄存器及其控制字见表3.2,其中奇数为读操作,偶数为写操作。

时钟暂停:秒寄存器的位7定义位时钟暂停位。当它为1时,DS1302

停止震荡,进入低功耗的备份方式。通常在对DS1302进行写操作时(如进入时

6

钟调整程序),停止震荡。当它为0时,时钟将开始启动。

AM-PM/12-24[小]时方式:[小]时寄存器的位7定义为12或24[小]

时方式选择位。它为高电平时,选择12[小]时方式。在此方式下,位5是AM/PM位,此位是高电平时表示PM低电平表示AM。在24[小]时方式下,位5为第二个10[小]时位(20~23h)。

表 4.2 内部寄存器地址和内容

积存器名 秒积存器 分积存器 [小]时积存器 日积存器 月积存器 周积存器 年积存器

DS1302的晶震选用32.768kHz,电容推荐值为33pF,因为震荡频率

较低,也可以不接电容,对计时精度影响不大。

命令字节 写 读 80H 82H 84H 85H 88H 8AH 8CH 取值范围 积存器内容 7 0 12/24 0 0 0 6 5 4 3 2 1 0 SEC MIN CH 10S 10 min 81H 00~59 83H 00~59 85H 00~23或01~12 87H 01~28,29,30,31 89H 01~12 8BH 01~07 D3H 00~99 0 10A/HR HR P 0 10DATE DATE 0 0 0 0 10M MONTH 0 0 DAY YEAR 10YEAR 4.3 测温电路的设计

测温电路主要使用温度传感器DS18B20,由于精度要求不高所以采用2位共阳LCD数码管以动态扫描法实现温度显示。其设计原理图如附件一所示。

4.3.1 温度传感器工作原理

DS18B20温度传感器是美国DALLAS半导体公司最新推出的一种改进型智能温度传感器,与传统的热敏电阻等测温元件相比,它能直接读出被测温度,并且可根据实际要示通过简单的编程实现9~12位的数字值读数方式。DS18B20的性能特点如下:

独特的单线接口仅需要一个端口引脚进行通信;

多个DS18B20可以并联在唯一的三线上,实现多点组网功能; 无须外部器件;

7

可通过数据线供电,电压范围为3.0~3.5V; 零待机功耗;

温度以9或12数字量读出;

用户可定义的非易失性温度报警设置;

报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件; 负电压特性,电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。

DS18B20采用3脚PR—35封装或8脚SOIC封装,其内部结构框图如图4.3所示。

64位ROM的位结构如图4.4所示。开始8位是产品类型的编号,接着是每个器件的唯一的序号,共有48位,最后8位是前面56位的CRC检验码,这也是多个DS18B20可以采用一线进行通信的原因。非易失性温度报警触发器TH和TL,可通过软件写入户报警上下限。

DS18B20温度传感器的内部存储器还包括一个调整暂存RAM和一个易失性的可电擦除的EERAM。高速暂存RAM的结构为8字节存储器,结构如图4.5所示。头2个字节包含测得的温度信息,第3和第4节是TH和TL的拷贝,是易失的,每次上电复位时被刷新。第5个字节为配置寄存器,它的内容用于确定温度值的数字转换分辨率。DS18B20工作时按此寄存器中的分辨率将温度转换为相应精度的数值。该字节各位的定义如图4.6所示。低5位一直1,M是测试模式位,用于设置DS18B20在工作模式还是在测试模式。在DS18B20出厂时该位被设置为0,用户不要去改动,R1和R0决定温度转换的精度位数,即用来设置分辨率,定义方法见表4.3。

由表4.3可见,DS18B20温度转换的时间比较长,而且设定的分辨率越高,所需要的温度数据转换时间就越长。因此,在实际应用中要将分辨率和转换时间权衡考虑。

高速暂存RAM的第6、7、8字节保留未用,表现为全逻辑1。第9字节读出前面所有8字节的CRC码,可用来检验数据,从而保证通信数据的正确性。

当DS18B20接收到温度转换命令后,开始启动转换。转换完成后的温度值就以16位带符号扩展的二进制补码形式存储在高速暂存存储器的第1、2字节。

8

单片机可以通过单线接口读出该数据,读数据时低位在先,高位在后,数据格式以0.0625°C/LSB形式表示。温度值格式如图4.7所示。

64位ROM 和 存储器与控制逻辑 I/O 温度传感器 高温触发器TH 低温触发器TL 配置寄存器 8位CRC发生器 C VDD 单线接口 高速 缓存 图4.3DS18B20内部结构

8位工厂代码(10H) MSB LSB MSB LSB MSB LSB

图4.4 64位ROM结构图

温度LSB 温度MSB TH用户字节1 TL用户字节2 1字节 2字节 3字节 4字节 5字节 6字节 78位检验CRC 48位序列号 EEROTH用户字节1 9

配置寄存器 保留 保留 保留 CRC 字节 8字节 9字节 TL用户字节2 图4.5 高速暂存RAM结构图

TM R1 R0 1 1 1 1 1 图 4.6 配置寄存器

表 4.3 DS18B20分辨率的定义规定 R1 0 0 1 1 温度/C° R0 0 1 0 1 分辨率/位 9 10 11 12 二进制表示 测量最大转换时间/ms 93.75 187.5 375 750 表 4.4 DS18B20温度与测得值对应表 十六进制表示 +125 0000 0111 1101 0000 07D0H +85 0000 0101 0101 0000 0550H +25.0620000 0001 1001 0001 0191H 5 +10.120000 0000 1010 0010 00A2H 5 +0.5 0000 0000 0000 1000 0008H 0 0000 0000 0000 0000 0000H -0.5 1111 1111 1111 1000 FFF8H 10

-10.125 -25.0625 -55 1111 1111 0101 1110 1111 1110 0110 1111 1111 1100 1001 0000

FF5EH FE6FH FC90H LS字节 23 22 21 20 S S S 图 4.7 温度数字值格式

斜率累加预低温度系数振荡器 减法计数器1 减到0 高温度系数振荡增MS字节 S 2-1 2-2 2-3 2-4 S S6 S5 S4 计数比较预置 温度寄存器 停减到0 减法计数图 4.8 DS18B20测温原理图

表 4.5 74LS164特性表

操作模式 复 位 MR L H H H H 输 入 A × L L H H B × L H L H Q0 L L L L H 输 出 Q1~Q7 Q0~Q6 Q0~Q6 Q0~Q6 Q0~Q6 Q0~Q6 移 位

74LS164内部为8个D触发器,用以实现数据的串行移位,74LS164特性见表4.5。单片机以串口方式0(移位寄存器方式)输出数据,3片74LS164作为3排共阳数码管的串/并转换显示接口。74LS164为TTl单向8位移位寄存器,可实现串行输入,并行输出。其中A、B(第1、2脚)为串行数据输入端,2个引脚按逻辑“与”运算规律输入信号,共一个输入信号时可并接,共同作为输入脚。

11

CP(第8脚)为时钟输入端,可连接到串行口的TXD端。每一个时钟信号的上升沿加到CP端时,移位寄存器移一位。8个时钟脉冲过后,8位二进制数全部移入74LS164中。MR脚(第9脚)为复位端,当该脚为低电平时,移位寄存器各位复0;只有当它高电平时,时钟脉冲才起作用。Q1~Q8(第3~6和10~13引脚)并行输出端分别接数码管的h~a(因为串口从低位开始传送)各段对应的引脚上。在给出了8个脉冲后,最先进入74LS164的第一个字节数据到达了最高位。再来1个脉冲,第1个脉冲就会从最高位移出,进入下个74LS164的第1位。3片74LS164首尾相串,而时钟端则接在一起。这样,当输入8个脉冲时,从单片机RXD端输出的第1字节数据就进入了第1片74LS164中,而当第2个8个脉冲到来后,第1字节数据就进入了第2片74LS164,而随后的第2字节的数据则进入了第1片74LS164。这样,当第3个8个脉冲完成后,首次送出的数据被送到了最下面的164(第3片)中,其它数据依次出现在第二和第一片74LS164中,实现了数据在74LS164中的串行输入、并行输出。

在方式0状态下,串行口为同步移位寄存器方式,其波特率是固定的,为fosc/12。数据由RXD(P3.0)端输入或输出,同步移位脉冲由TXD(P3.1)端输出。发送、接收数据时低位在先。所以根据提供的硬件电路图,在编写程序时,查共阳数码管的段码的二进制数据应该将正常的共阳数据管0~9的二进制值按位反序排序,如原来的二进制为11000000(C0H),要改为00000011(03H),就能使数码管正常显示。

4.5 键盘接口的设计

由于按键只有5个,用普通按钮接10K上拉电阻,用查询法完成读键功能。

第5章 系统程序的设计

5.1 阳历程序设计

因为使用了时钟芯片DS1302,阳历程序只需从DS1302各寄存器中读出年、周、月、日、[小]时、分、秒等数据,再处理即可。在首次对DS1302进行操作之前,必须对它进行初始化,然后从DS1302中读出数据,再经过处理后,送给

12

显示缓冲单元。阳历程序流程图见图5.1所示。

开 始 初始化1302 1302开始振荡 从1302中读出年、周、月、日、[小]时、分、秒 读出的数据都为BCD码,将其高低位分离送显示缓冲单元 图5.1 阳历程序流程图

5.2 时间调整程序设计

调整时间用5个调整按钮,1个作为移位、控制用,2个作为加和减用,还有2个作为闹钟调整使用,分别定义为控制按钮、加按钮、减按钮、闹钟加按纽、闹钟减按纽。在调整时间过程中,要调整的位与别的位应该有区别。所以增加了闪烁功能,即调整的位一直在闪烁,直到调整下一位。闪烁原理就是,让要调整的一位每隔一定时间熄灭一次,比如说50ms。利用定时器计时,当达到50ms溢出时,就送给该位熄灭符,在下一次溢出时,再送正常显示的值,不断交替,直到调整该位结束。此时送正常显示值给该位,再进入下一位调整闪烁程序。时间调整程序流程图如图5.2所示。

13

控制键有效,进入年调整程序员 控制键有效,进入月调整程序员 等待按键程序 等待按键程序 加键有效 减键有效 加键有效 减键有效 年加1 年减1 月加1 月减1 控制键有效,进入日调整程序员 控制键有效,进入星期调整程序员 等待按键程序 等待按键程序 加键有效 减键有效 加键有效 减键有效 日加1 日减1 星期加1 星期减1 控制键有效,进入[小]时调整程序员 控制键有效,进入分调整程序员 等待按键程序 等待按键程序 加键有效 减键有效 加键有效 减键有效 [小]时加1 [小]时减1 分加1 分减1 控制键有效,跳出时间调整程序,进入主循环程序 图 5.2 时间调整程序程序流

程图

14

5.3 温度程序设计

系统程序主要包括主程序、读出温度子程序、温度转换命令子程序、计算温度子程序、显示数据刷新子程序等等。

5.3.1 主程序

主程序的主要功能是负责温度的实时显示、读出并处理DS18B20的测量温度值,温度测量每1s进行一次。其程序流程图见5.3。

5.3.2 读出温度子程序

主要功能是读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写。其程序流程图如图5.4所示。

发温度转换开始命1SY 初次上Y 读出温度值 温度计算处理 显示数据刷新 N 9字节Y CRC校验正Y 移入温度暂存器 N N N 调用显示子程序 初始化 发DS18B20复位命发跳过ROM命发读取温度命读取操作,CRC结束 图5.3 DS18B20温度计主程序流程图 图5.4 读出温度子程序流程图

15

5.3.3 温度转换命令子程序

温度转换子程序主要是发温度转换开始命令,当采用12位分辨率时转换时间约为750ms,在本程序设计中采用1s显示程序延时法等待转换的完成。温度转换命令子程序流程图如图5.5所示。

5.3.4 计算温度子程序

计算温度子程序将RAM中读取值进行BCD码的转换运算,并进行温度值正负的判定。

5.3.5显示数据刷新子程序

显示数据刷新子程序主要是对显示缓冲器中的显示数据进行刷新操作,当最高显示位为0时将符号显示位移入下一位。程序流程图如图5.6所示。

开始 温度零下? N Y 温度值取补码 置“—”标志 置“+”标志 计算小数位BCD值 计算整数位BCD值 结束

图5.5 温度转换命令子程序流程图

16

温度数据移入显示寄N 十位数Y 百位数Y 十位数显示符号 百位数显示数据 N 结束 图5.6 显示数据刷新子程序流程图

第6章 调试及性能分析

6.1 调试步骤

系统的调试分为硬件调试和软件调试。其中硬件调试主要是检测硬件电路是否有短路、断路、虚焊现象。时钟和测温部分的硬件电路很简单,DS1302通过3根线、DS18B20只通过1根线与单片机相连接,很容易检测,主要是检测引脚晶振和电源是否接好。另外可以通过软件来调试硬件,如编写一个简单的显示程序来测试显示电路连接是否正确。接下来可进行软件调试,可以编写只含DS1302的计时和读写程序、显示程序,测试DS1302是否正常工作。最后调试日历、时间、闹钟、报警和温度程序。

6.2 性能分析

计时器最关键的是计时的精度。电子万年历中DS1302上最好使用专用的晶振。经测试制作的电子万年历,误差较大,设计可以通过换用标准晶振或用软件进行修正。

17

结论

通过这次的课程设计,使深深感到自身能力的不足,也使我将学到的知识应用到了实践中,在这段时间里,我学到了很多知识也有很多感受,我开始了独立的学习和试验,遇到了很多的困难,我通过查阅大量相关的书籍、报纸、期刊、和资料,让自己头脑中模糊的概念逐渐清晰,使自己非常稚嫩的作品一步步完善起来,每一次改进都是我学习的收获,每一次试验的成功都会让我兴奋好长一段时间。从中我也充分认识到了学习的重要性。

虽然我的设计还有很多不足之处,但我可以很自豪的说,这里面的每一段文字和每一个图形,都有自己的劳动当看着自己的设计,真是莫大的幸福和欣慰。我相信其中的酸甜苦辣最终都会化为甜美的甘泉。

由于本人的水平有限,设计当中,难免会有不少的缺点和不足之处,恳请指导老师批评并改正。

18

参考文献

[1] 王新颖单片机原理及应用北京大学出版社 2008

[2] 陈忠平 单片机基础与最小系统实践.北京航空航天大学出版社

[3] 窦振中 单片机外围器件实用手册存储器分册.北京航空航天大学出版社 [4] 沈庆阳, [5] 陈明荧. 8051[6] 何立民. 郭庭吉 8051单片机实践与应用.清华大学出版社

单片机课程设计实训教程[M]. 北京: 清华大学出版社 单片机高级教程[M]. 北京: 北京航空航天大学出版社, 2003.

19

附录

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

#include #include

#define uchar unsigned char #define uint unsigned int

uchar code digit[]={\定义字符数组显示数字 uchar code Error[]=\说明没有检测到DS18B20 uchar code table[]=%uchar code table1[]=%uchar code table2[]=\

uchar code table3[]=%uchar code table4[]=\

uchar code table5[]=\

uchar code table6[]=%uchar code table7[]=\/*uchar code table8[]=%uchar code table9[]=%uchar code table10[]=%uchar code table11[]=\

uchar code table12[]=%uchar code table13[]=\

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

以下是对液晶模块的操作程序

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

sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚 sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚 sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚 sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚 sbit DQ=P2^6; sbit T_RST=P1^5;

sbit T_CLK=P1^3; sbit T_IO=P1^4; sbit beep=P2^4;

sbit key1=P3^0; //调闹钟的小时即x sbit key2=P3^1; //调闹钟的分钟即y sbit key3=P3^2; //显示切换 sbit key4=P3^3; sbit ACC0=ACC^0;

20

sbit ACC7=ACC^7;

uchar time; //设置全局变量,专门用于严格延时 static uchar x=0x08,y=30; uchar t_sec,sec1,sec2; uchar t_min,min1,min2; uchar t_hour,hour1,hour2; uchar t_mon,mon1,mon2; uchar t_day,day1,day2; uchar t_year,year1,year2; uchar week,week1; uchar com,inf;

void tixing(unsigned char mm,unsigned dd); void show();

void delay1(uchar t) {

uchar a,b;

for(a=t;a>0;a--) for(b=110;b>0;b--); }

/***************************************************** 函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒 ***************************************************/ void delay1ms() {

uchar i,j;

for(i=0;i<10;i++) for(j=0;j<33;j++) ; }

/***************************************************** 函数功能:延时若干毫秒 入口参数:n

***************************************************/ void delaynms(uchar n) {

uchar i;

for(i=0;i

/***************************************************** 函数功能:判断液晶模块的忙碌状态

返回值:result。result=1,忙碌;result=0,不忙

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

21

bit BusyTest(void) {

bit result;

RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态 RW=1;

E=1; //E=1,才允许读写 _nop_(); //空操作 _nop_(); _nop_();

_nop_(); //空操作四个机器周期,给硬件反应时间 result=BF; //将忙碌标志电平赋给result E=0; //将E恢复低电平 return result; }

/***************************************************** 函数功能:将模式设置指令或显示地址写入液晶模块 入口参数:dictate

***************************************************/ void WriteInstruction (uchar dictate) {

while(BusyTest()==1); //如果忙就等待

RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令 RW=0;

E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, // 就是让E从0到1发生正跳变,所以应先置\ _nop_();

_nop_(); //空操作两个机器周期,给硬件反应时间 P0=dictate; //将数据送入P0口,即写入指令或地址 _nop_(); _nop_(); _nop_();

_nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_();

_nop_(); //空操作四个机器周期,给硬件反应时间

E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 }

/***************************************************** 函数功能:指定字符显示的实际地址 入口参数:x

***************************************************/ void WriteAddress(unsigned char x)

22

{

WriteInstruction(x|0x80); //显示位置的确定方法规定为\地址码x\ }

/***************************************************** 函数功能:将数据(字符的标准ASCII码)写入液晶模块 入口参数:y(为字符常量)

***************************************************/ void WriteData(uchar y) {

while(BusyTest()==1);

RS=1; //RS为高电平,RW为低电平时,可以写入数据 RW=0;

E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, // 就是让E从0到1发生正跳变,所以应先置\ P0=y; //将数据送入P0口,即将数据写入液晶模块 _nop_(); _nop_(); _nop_();

_nop_(); //空操作四个机器周期,给硬件反应时间 E=1; //E置高电平 _nop_(); _nop_(); _nop_();

_nop_(); //空操作四个机器周期,给硬件反应时间

E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 }

/***************************************************** 函数功能:对LCD的显示模式进行初始化设置

***************************************************/ void LcdInitiate(void) {

delaynms(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间

WriteInstruction(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口

delaynms(5); //延时5ms ,给硬件一点反应时间 WriteInstruction(0x38);

delaynms(5); //延时5ms ,给硬件一点反应时间 WriteInstruction(0x38); //连续三次,确保初始化成功

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x0c); //显示模式设置:显示开,无光标,光标不闪烁 delaynms(5); //延时5ms ,给硬件一点反应时间 WriteInstruction(0x06); //显示模式设置:光标右移,字符不移 delaynms(5); //延时5ms ,给硬件一点反应时间

23

WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除 delaynms(5); //延时5ms ,给硬件一点反应时间 }

void write_com(uchar com)//向1602写指令 {

RS=0; RW=0; P0=com;

delaynms(10); E=1;

delaynms(10); E=0; }

/***************************************************** 函数功能:将DS18B20传感器初始化,读取应答信号 出口参数:flag

***************************************************/ bit Init_DS18B20(void) {

bit flag; //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在

DQ = 1; //先将数据线拉高

for(time=0;time<2;time++) //略微延时约6微秒 ;

DQ = 0; //再将数据线从高拉低,要求保持480~960us for(time=0;time<200;time++) //略微延时约600微秒

; //以向DS18B20发出一持续480~960us的低电平复位脉冲 DQ = 1; //释放数据线(将数据线拉高) for(time=0;time<10;time++)

; //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲) flag=DQ; //让单片机检测是否输出了存在脉冲(DQ=0表示存在) for(time=0;time<200;time++) //延时足够长时间,等待存在脉冲输出完毕 ;

return (flag); //返回检测成功标志 }

/***************************************************** 函数功能:从DS18B20读取一个字节数据 出口参数:dat

***************************************************/ uchar ReadOneChar(void) {

uchar i=0;

uchar dat; //储存读出的一个字节数据 for (i=0;i<8;i++)

24

{

DQ =1; // 先将数据线拉高 _nop_(); //等待一个机器周期

DQ = 0; //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序 dat>>=1;

_nop_(); //等待一个机器周期

DQ = 1; //将数据线\人为\拉高,为单片机检测DS18B20的输出电平作准备 for(time=0;time<2;time++)

; //延时约6us,使主机在15us内采样 if(DQ==1)

dat|=0x80; //如果读到的数据是1,则将1存入dat else

dat|=0x00;//如果读到的数据是0,则将0存入dat //将单片机检测到的电平信号DQ存入r[i] for(time=0;time<8;time++)

; //延时3us,两个读时序之间必须有大于1us的恢复期 }

return(dat); //返回读出的十进制数据 }

/***************************************************** 函数功能:向DS18B20写入一个字节数据 入口参数:dat

***************************************************/ void WriteOneChar(uchar dat) {

uchar i=0;

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

DQ =1; // 先将数据线拉高 _nop_(); //等待一个机器周期

DQ=0; //将数据线从高拉低时即启动写时序 DQ=dat&0x01; //利用与运算取出要写的某位二进制数据, //并将其送到数据线上等待DS18B20采样 for(time=0;time<10;time++)

;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样 DQ=1; //释放数据线 for(time=0;time<1;time++)

;//延时3us,两个写时序间至少需要1us的恢复期 dat>>=1; //将dat中的各二进制位数据右移1位 }

for(time=0;time<4;time++)

; //稍作延时,给硬件一点反应时间 }

25

/***************************************************** 函数功能:显示没有检测到DS18B20

***************************************************/ void display_error(void) {

uchar i;

WriteAddress(0x00); //写显示地址,将在第1行第1列开始显示 i = 0; //从第一个字符开始显示

while(Error[i] != '\\0') //只要没有写到结束标志,就继续写 {

WriteData(Error[i]); //将字符常量写入LCD i++; //指向下一个字符

delaynms(100); //延时100ms较长时间,以看清关于显示的说明 }

while(1) //进入死循环,等待查明原因 ; }

/***************************************************** 函数功能:显示温度的小数点

***************************************************/ void display_dot(void) {

WriteAddress(0x80+0x40+0x03); //写显示地址,将在第2行第10列开始显示

WriteData('.'); //将小数点的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间 }

/***************************************************** 函数功能:显示温度的单位(Cent)

***************************************************/ void display_cent(void) {

WriteAddress(0x80+0x40+0x05); //写显示地址,将在第2行第13列开始显示

WriteData(0xdf);

WriteAddress(0x80+0x40+0x06); WriteData('C'); }

/***************************************************** 函数功能:显示温度的整数部分 入口参数:x

***************************************************/ void display_temp1(unsigned char x) {

26

uchar j,k,l; //j,k,l分别储存温度的百位、十位和个位 j=x/100; //取百位 k=(x0)/10; //取十位

l=x; //取个位

WriteAddress(0x80+0x40); //写显示地址,将在第2行第7列开始显示 WriteData(digit[j]); //将百位数字的字符常量写入LCD WriteData(digit[k]); //将十位数字的字符常量写入LCD WriteData(digit[l]); //将个位数字的字符常量写入LCD delaynms(50); //延时1ms给硬件一点反应时间 }

/***************************************************** 函数功能:显示温度的小数数部分 入口参数:x

***************************************************/ void display_temp2(uchar x) {

WriteAddress(0x80+0x40+0x04); //写显示地址,将在第2行第11列开始显示 WriteData(digit[x]); //将小数部分的第一位数字字符常量写入LCD delaynms(50); //延时1ms给硬件一点反应时间 }

/***************************************************** 函数功能:做好读温度的准备

***************************************************/ void ReadyReadTemp(void) {

Init_DS18B20(); //将DS18B20初始化

WriteOneChar(0xCC); // 跳过读序号列号的操作 WriteOneChar(0x44); // 启动温度转换 for(time=0;time<100;time++)

; //温度转换需要一点时间 Init_DS18B20(); //将DS18B20初始化 WriteOneChar(0xCC); //跳过读序号列号的操作

WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位 }

/******************************************* 向1302写一个字节

*******************************************/ void input_BYTE(uchar dat) {

uchar i; ACC=dat;

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

27

T_IO=ACC0; T_CLK=1; T_CLK=0;

ACC=(ACC>>1); } }

/******************************************* 1302读出一个字节

*******************************************/ uchar output_BYTE() {

uchar i;

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

ACC=(ACC>>1); ACC7=T_IO; T_CLK=1; T_CLK=0; }

return (ACC); }

/******************************************* 写数据

*******************************************/ void write_1302(uchar add,uchar dat) {

T_RST=0; T_CLK=0; T_RST=1;

input_BYTE(add); input_BYTE(dat); T_CLK=1; T_RST=0; }

/******************************************* 读数据

*******************************************/ uchar read_1302(uchar add) {

uchar inf; T_RST=0; T_CLK=0; T_RST=1;

input_BYTE(add);

28

inf=output_BYTE(); T_CLK=1; T_RST=0;

return (inf); }

void init_1302() {

write_1302(0x8e,0x00);//关闭写保护; // write_1302(0x90,0xaa);//设置充电方式; write_1302(0x80,0x00);//秒寄存器初始化; write_1302(0x82,0x01);//分....... write_1302(0x84,0x10);//时....... write_1302(0x86,0x01);//日........ write_1302(0x88,0x10);//月....... write_1302(0x8a,0x02);//星期...

write_1302(0x8c,0x13);//年...... write_1302(0x8e,0x80);//打开写保护; }

/********************************** 闹钟显示子程序

**********************************/ void show_naozhong(uchar x,uchar y) {

uchar i,x1,x2,y1,y2; x1=x/10; //十位 x2=x;//个位

WriteAddress(0x80+0x0b); //显示闹钟的小时部分 WriteData(table1[x1]); WriteAddress(0x80+0x0c); WriteData(table1[x2]);

y1=y/10; //十位 y2=y;//个位

WriteAddress(0x80+0x0e); //显示闹钟的分钟部分 WriteData(table1[y1]); WriteAddress(0x80+0x0f); WriteData(table1[y2]);

WriteAddress(0x80+0x0d); //显示小时与分钟之间的那个冒号 WriteData(':');

WriteAddress(0x80); //显示字符串:Alarm Clock for(i=0;i<11;i++) {

29

WriteData(table[i]); }

WriteAddress(0x80+0x40); //显示字符串:Today is fine! for(i=0;i<14;i++) {

WriteData(table3[i]); } }

void main(void) {

uchar i;

uchar TL; //储存暂存器的温度低位 uchar TH; //储存暂存器的温度高位 uchar TN; //储存温度的整数部分 uchar TD; //储存温度的小数部分 LcdInitiate(); //将液晶初始化 init_1302();

delaynms(5); //延时5ms给硬件一点反应时间 // if(Init_DS18B20()==1) // display_error(); EA=1;//开总中断

EX1=1;//开外部中断1 IT1=0;//下降沿触发

WriteAddress(0x80+0x10); for(i=0;i<6;i++) {

WriteData(table4[i]); }

WriteAddress(0x80+0x50); for(i=0;i<16;i++) {

WriteData(table5[i]); }

for(i=0;i<16;i++) {

write_com(0x18); delaynms(250); }

delaynms(250); delaynms(250); delaynms(250); write_com(0x01); while(1)

30

// // // //

{

t_sec=read_1302(0x81);//读秒 ; sec1=t_sec&0x0f; sec2=(t_sec>>4);

t_min=read_1302(0x83);//读分 ; min1=t_min&0x0f; min2=(t_min>>4);

t_hour=read_1302(0x85);//读小时 ; hour1=t_hour&0x0f; hour2=(t_hour>>4);

WriteAddress(0x80+0x40+0x08); //显示小时 WriteData(table1[hour2]); WriteAddress(0x80+0x40+0x09); WriteData(table1[hour1]); t_day=read_1302(0x87);//读日; day1=t_day&0x0f; day2=(t_day>>4);

t_mon=read_1302(0x89);//读月 ; mon1=t_mon&0x0f; mon2=(t_mon>>4);

week=read_1302(0x8b);//读星期 ; week1=week&0x0f;

t_year=read_1302(0x8d);//读年 ; year1=t_year&0x0f; year2=(t_year>>4);

WriteAddress(0x80+0x06); WriteData('2');

WriteAddress(0x80+0x07); WriteData('0');

WriteAddress(0x80); //显示星期(0x80~0x80+0x05) for(i=0;i<4;i++) {

WriteData(table2[i]); }

31

WriteAddress(0x80+0x04); WriteData(table1[week1]);

WriteAddress(0x80+0x08);//显示年 WriteData(table1[year2]); WriteAddress(0x80+0x09); WriteData(table1[year1]);

WriteAddress(0x80+0x0a); //显示‘/’ WriteData('/');

WriteAddress(0x80+0x0b);//显示月 WriteData(table1[mon2]); WriteAddress(0x80+0x0c); WriteData(table1[mon1]);

WriteAddress(0x80+0x0d); //显示‘/’ WriteData('/');

WriteAddress(0x80+0x0e);//显示日 WriteData(table1[day2]); WriteAddress(0x80+0x0f); WriteData(table1[day1]); /*第一行在此显示完毕*/

display_dot(); //显示温度的小数点 display_cent(); //显示温度的单位

WriteAddress(0x80+0x40+0x08); //显示小时 WriteData(table1[hour2]); WriteAddress(0x80+0x40+0x09); WriteData(table1[hour1]);

WriteAddress(0x80+0x40+0x0a); //显示':' WriteData(':');

WriteAddress(0x80+0x40+0x0b); //显示分钟 WriteData(table1[min2]); WriteAddress(0x80+0x40+0x0c); WriteData(table1[min1]);

WriteAddress(0x80+0x40+0x0d); //显示':' WriteData(':');

WriteAddress(0x80+0x40+0x0e); //显示秒 WriteData(table1[sec2]);

32

WriteAddress(0x80+0x40+0x0f); WriteData(table1[sec1]); /*第二行在此显示完毕*/

ReadyReadTemp(); //读温度准备

TL=ReadOneChar(); //先读的是温度值低位 TH=ReadOneChar(); //接着读的是温度值高位

TN=TH*16+TL/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16 //这样得出的是温度的整数部分,小数部分被丢弃了 TD=(TL)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整, //这样得到的是温度小数部分的第一位数字(保留1位小数)

display_temp1(TN); //显示温度的整数部分 display_temp2(TD); //显示温度的小数部分 //以下部分是闹钟键盘检测程序

if((x==hour2*10+hour1)&&(y==min2*10+min1))//若时间到了,则开启闹钟 {

beep=0; }

else //否则,关闭闹钟 {

beep=1; }

delaynms(10);

tixing(t_mon,t_day); } }

void exter1()interrupt 2 {

uint k;

write_com(0x01); for(k=0;k<2000;k++) {

while(key1==0) //键盘扫描.当key1按下时, { //闹钟的小时部分加一 delaynms(10);

if(key1==0) //消抖 {

delaynms(10);

while(key1==0); //松手检测 x++;

if(x==24) //小时部分加到24后自动清零 x=0; } }

33

while(key2==0) //键盘检测。当key2按下时, {

delaynms(10); //闹钟的分钟部分加一 if(key2==0) //消抖 {

delaynms(10);

while(key2==0);//松手检测 y++;

if(y==60) //若分钟部分加到60,则自动清零 y=0; }

}

show_naozhong(x,y); //调用闹钟显示程序 }

write_com(0x01); }

void tixing(unsigned char mm,unsigned dd) {

uchar i;

if(mm==0x01&&dd==0x01) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table6[i]); }

show();

if(mm!=0x01||dd!=0x01) break; } }

if(mm==0x02&&dd==0x14) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table7[i]); }

show();

if(mm!=0x02||dd!=0x14)

34

/* break; } }

if(mm==0x04&&dd==0x05) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table8[i]); }

show();

if(mm!=0x04||dd!=0x05) break; } }

if(mm==0x05&&dd==0x01) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table9[i]); }

show();

if(mm!=0x05||dd!=0x01) break; } }

if(mm==0x06&&dd==0x15) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table10[i]); }

show();

if(mm!=0x06||dd!=0x15) break; }

35

}

}

if(mm==0x08&&dd==0x01) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table11[i]); }

show();

if(mm!=0x08||dd!=0x01) break; } }

if(mm==0x09&&dd==0x10) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table12[i]); }

show();

if(mm!=0x09||dd!=0x10) break; } }

if(mm==0x10&&dd==0x01) {

while(1) {

WriteAddress(0x80); for(i=0;i<16;i++) {

WriteData(table13[i]); }

show();

if(mm!=0x10||dd!=0x01) break; } } */

36

void show() {

// uchar i;

uchar TL; //储存暂存器的温度低位 uchar TH; //储存暂存器的温度高位 uchar TN; //储存温度的整数部分 uchar TD; //储存温度的小数部分

t_day=read_1302(0x87);//读日; day1=t_day&0x0f; day2=(t_day>>4);

t_mon=read_1302(0x89);//读月 ; mon1=t_mon&0x0f; mon2=(t_mon>>4);

week=read_1302(0x8b);//读星期 ; week1=week&0x0f;

t_year=read_1302(0x8d);//读年 ; year1=t_year&0x0f; year2=(t_year>>4);

t_sec=read_1302(0x81);//读秒 ; sec1=t_sec&0x0f; sec2=(t_sec>>4);

t_min=read_1302(0x83);//读分 ; min1=t_min&0x0f; min2=(t_min>>4);

t_hour=read_1302(0x85);//读小时 ; hour1=t_hour&0x0f; hour2=(t_hour>>4);

// WriteAddress(0x80+0x40+0x08); //显示小时 // WriteData(table1[hour2]); // WriteAddress(0x80+0x40+0x09); // WriteData(table1[hour1]);

t_day=read_1302(0x87);//读日; day1=t_day&0x0f; day2=(t_day>>4);

37

t_mon=read_1302(0x89);//读月 ; mon1=t_mon&0x0f; mon2=(t_mon>>4);

week=read_1302(0x8b);//读星期 ; week1=week&0x0f;

t_year=read_1302(0x8d);//读年 ; year1=t_year&0x0f; year2=(t_year>>4);

display_dot(); //显示温度的小数点 display_cent(); //显示温度的单位

WriteAddress(0x80+0x40+0x08); //显示小时 WriteData(table1[hour2]); WriteAddress(0x80+0x40+0x09); WriteData(table1[hour1]);

WriteAddress(0x80+0x40+0x0a); //显示':' WriteData(':');

WriteAddress(0x80+0x40+0x0b); //显示分钟 WriteData(table1[min2]); WriteAddress(0x80+0x40+0x0c); WriteData(table1[min1]);

WriteAddress(0x80+0x40+0x0d); //显示':' WriteData(':');

WriteAddress(0x80+0x40+0x0e); //显示秒 WriteData(table1[sec2]); WriteAddress(0x80+0x40+0x0f); WriteData(table1[sec1]); /*第二行在此显示完毕*/

ReadyReadTemp(); //读温度准备

TL=ReadOneChar(); //先读的是温度值低位 TH=ReadOneChar(); //接着读的是温度值高位

TN=TH*16+TL/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16 //这样得出的是温度的整数部分,小数部分被丢弃了 TD=(TL)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整,

38

//这样得到的是温度小数部分的第一位数字(保留1位小数)

display_temp1(TN); //显示温度的整数部分 display_temp2(TD); //显示温度的小数部分 //以下部分是闹钟键盘检测程序

if((x==hour2*10+hour1)&&(y==min2*10+min1))//若时间到了,则开启闹钟 {

beep=0; }

else //否则,关闭闹钟 {

beep=1; }

delaynms(10); }

39

软硬件专业综合课程设计考核表

姓名 课题名称 陈振伟 性别 男 学号 1206644030 班级 类型 12通信工程(升) 实验研究 基于单片机的万年历的设计 考核内容 设计方案 总结报告 所占比例 15% 15% 30% 10% 20% 10% 得分 程序、计算、作品等的完成质量 创新与发挥情况 答辩情况 出勤率 指 导 教 师 评 语 指导教师: 年 月 日 总评 成绩 成绩与等 级对应表 优 90-100 良 80-89 评定 等级 中 70-79 及格 60-69 不及格 59分以下

40

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

Top