万年历数字钟及可调时钟系统
多功能数字万年历课程设计

5.3用PROTEUS进行电子万年历的仿真测试15
结论1..7..
致谢18
参考文献19
附录20
1
1.1
随着科技的快速发展,时间的流逝,从观太阳、摆钟到现在电子钟,人类不断研究,不 断创新纪录。它可以对年、月、日、时、分、秒进行计时,还具有闰年补偿等多种功能, 而且DS1302的使用寿命长,误差小。对于数字电子万年历采用直观的数字显示,可以同 时显示年、月、日、时、分、秒和温度等信息, 还具有时间校准等功能。 该电路采用AT89C51单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
(8)软件设计时必须要有完善的思路,要做到程序简单,调试方便。
2
单片机电子万年历的制作有多种方法,可供选择的器件和运用的技术也有很多种。所 以,系统的总体设计方案应在满足系统功能的前提下,充分考虑系统使用的环境,所选的 结构要简单使用、易于实现,器件的选用着眼于合适的参数、稳定的性能、较低的功耗以 及低廉的成本。
对Flash存储器编程期间,该引脚还用于输入编程脉冲(PROG)。如有必要,可通过多特殊功能寄存器(SFR)区中的8EH单元的D0位置,可禁止ALE操作。该位置后,只有一条MOVX和MOVC指令ALE才会被激活。另外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE无效。
PSEN:程序存储允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C51
2.1
系统的功能往往决定了系统采用的结构,经过成本,性能,功耗等多方面的考虑决定 用三个8位74LS164串行接口外接LED显示器,RESPACK-8对单片机AT89C51进行供电,时间芯片DS1302连接单片机AT89C51。从而实现电子万年历的功能。
万年历功能介绍及操作说明

基于51单片机的液晶万年历设计
1、本设计基于STC89C52(与AT89S5
2、AT89C52通用,可任选)单片机以及DS1302时钟芯片、DS18B20温度传感器构成的万年历系统。
2、有闹钟和阴历功能,有闰年补偿,可以准确及正确的显示时间等信息。
3、可以显示年、月、日、时、分、秒、星期、温度、农历和闹钟设定。
4、掉电走时,不用重新调时,当按键按下时背光亮,更节能。
使用方法:
一共4个按键:设置、加、减、切换
按下设置的时候秒会闪,这时可以加减调节,然后再按设置是设置分钟,依次设置,最后按一下设置就是推出并保存,主界面按切换的时候是显示阴历(ping是平年,run是闰年),再按下切换是显示闹钟界面,此时可以按设置调整闹钟。
万年历时钟实训报告

一、实训目的本次万年历时钟实训的主要目的是通过实际操作,学习万年历时钟的设计与制作,掌握万年历时钟的原理和制作方法,提高动手实践能力和创新思维。
实训过程中,我们学习了万年历时钟的硬件组成、软件编程、电路设计等知识,并对万年历时钟进行了实际制作。
二、实训内容1. 万年历时钟硬件组成万年历时钟主要由以下几部分组成:(1)单片机:作为万年历时钟的核心控制器,负责处理时间、日期、温度等数据,并控制整个时钟的运行。
(2)DS1302实时时钟模块:用于存储和提供当前时间、日期等信息。
(3)DS18B20温度传感器:用于检测环境温度。
(4)LCD12864液晶显示屏:用于显示时间、日期、温度等信息。
(5)按键:用于设置和调整时间、日期、温度等信息。
2. 万年历时钟软件编程万年历时钟的软件编程主要包括以下几部分:(1)主程序:负责初始化硬件设备,处理时间、日期、温度等数据,控制LCD显示。
(2)时钟模块:负责读取DS1302模块中的时间、日期信息,并实现时钟功能。
(3)温度模块:负责读取DS18B20传感器中的温度信息,并实现温度显示功能。
(4)按键处理模块:负责处理按键输入,实现时间、日期、温度的设置和调整。
3. 万年历时钟电路设计万年历时钟的电路设计主要包括以下几部分:(1)单片机与DS1302模块的连接:通过I2C接口连接单片机与DS1302模块,实现时间、日期信息的读取和写入。
(2)单片机与DS18B20传感器的连接:通过1-Wire接口连接单片机与DS18B20传感器,实现温度信息的读取。
(3)单片机与LCD12864显示屏的连接:通过SPI接口连接单片机与LCD12864显示屏,实现显示信息的输出。
(4)按键与单片机的连接:通过GPIO接口连接按键与单片机,实现按键输入的处理。
三、实训过程1. 硬件准备首先,准备好万年历时钟所需的硬件设备,包括单片机、DS1302模块、DS18B20传感器、LCD12864显示屏、按键等。
智能时钟万年历(详细电路图)

《嵌入式课程设计》讲义项目1 智能数字万年历一.项目指标分析项目指标要求如下:1. 显示年、月、日、时、分、秒和星期。
2. 实时显示温度。
3. 可手动调整时间。
4. 采用LCD显示。
基于以上要求,核心控制芯片选用STC89C51;时钟芯片选用DS1302;温度传感器选用DS18B20;液晶屏选用LCD1602;设置按键,以便于调整时间。
二.电路原理系统电路功能图如图1所示:图1 智能数字万年历电路功能图由图1可知,P2口控制LCD的数据端;P3.5、P3.6和P3.7控制着LCD的片选、读/写和寄存器选择信号;可调电阻RP2用于调节屏的显示对比度。
P3.4是温度传感器DS18B20的1-wire接口,即片选、时钟和数据信号均由P3.4口控制。
P0.5、P0.6和P0.7是时钟芯片DS1302的SPI接口,为使信号控制更稳定,这三个接口上都上拉了10KΩ电阻;为获得精准的时钟信号,选用频率为32.768KHz的外部晶振对DS1302提供振荡信号。
P0.0-P0.3控制着四个按键,以便于调整时间。
三.程序设计基于这个项目,程序的设计可分成各芯片驱动程序设计和控制算法程序两部分。
1.各芯片的驱动程序设计在写驱动程序时,首先通读芯片手册,以掌握主要技术指标;然后可按照以下3个步骤进行:(1)分清楚各芯片的通信属于哪种接口方式,例如:时钟芯片DS1302按照SPI 接口进行通信;温度传感器DS18B20按照1-wire接口进行通信;液晶屏LCD1602采用常规的并行数据传输方式。
(2)仔细分析芯片时序图,弄清楚片选信号是高电平有效还是低电平有效;数据是在时钟信号的上升沿还是下降沿时打入;数据前还是时钟前等。
(3)将功能程序函数化、驱动程序模块化。
2.控制算法程序设计这里的算法主要集中在如何设置按键识别程序,即便于调整时间,又不影响液晶屏的显示。
这里,提供两种思想以便参考。
(1)循环扫描方式流程图图2 循环扫描方式流程图(2图3 状态机方式流程图将图2和图3比较起来看,两种方式的最大差别在于“10ms消抖时间如何度过?”。
多功能数字钟说明书

编译成功之后,我把生成的HEX文件通过下载器下载进单片机,“跑一跑”程序看看。没想到,液晶屏就没有显示。。。
DS12C887时钟芯片是整个万年历的重要芯片模块。在焊接之前,我查阅了该芯片的相关资料,认真阅读了解各引脚的作用。同时看了该芯片引脚在实际应用中的连接情况。
DS18B20温度传感器芯片,外形和三极管一样,只有3个引脚。在焊接的时候,尤其要注意1脚接地,三脚接电源。为了能够重复使用该芯片,我先焊了三脚底座,然后可以直接把芯片插上去。
主控制器每隔一段时间(小于一秒钟)读一次时钟芯片的内部寄存器的值,将读出的时间、星期、温度等值实时显示在LCD液晶屏上。同时,主控制器不断的扫描按键电路和温度测量电路,当有按键按下时,识别出按键的值并调整相应的时间、星期值再写入时钟芯片内部。温度数据由测量电路获得的环境温度值送人显示电路。
四、方案比较
单片机底座部分可以最先焊,把电源、地等连好,如EA要接低电平,否则就用片外存储器了。下载器接口则按照教材P240所画的图来进行连接,需要注意的是用于焊接的为短脚,不能颠倒。时钟部分比较简单,因为瓷片电容和晶振没有正负极,但要注意晶振、电容得靠近单片机底座。发光二极管(需要外加一个1K的电阻限流)接在p1.0口,作为最小系统的显示部分。
方案二:DS12C887+1602LCD液晶屏
DS12C887时钟芯片功能丰富价格适中,能够自动产生世纪、年、月、日、时、分、秒以及时间模式转换等的时间信息,芯片内部增加了世纪存储器,从而利用硬件电路解决了“千年”的问题。DS12C887时钟芯片中还自带有锂电池,单片机掉电后时钟芯片内部的时间信息可以保持十年之久。1602LCD液晶屏可以输出2行,每行显示16个字符。虽然1602LCD液晶屏较昂贵,但是该液晶屏显示清晰且不会闪烁,由于液晶屏是数字式的,因此和单片机系统的接口简单,操作方便。1602LCD液晶屏的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多,功耗较低。以上两种元件的程序编写简单,适用于多方面的应用。
单片机课程设计—万年历[1]
![单片机课程设计—万年历[1]](https://img.taocdn.com/s3/m/f8634cde87c24028905fc3ce.png)
郑州轻工业学院软件学院单片机与接口技术课程设计总结报告设计题目:电子万年历学生:系别:专业:班级:学号:指导教师:2021年12月16日设计题目:电子万年历设计任务与要求:1、显示年月日时分秒及星期信息2、具有可调整日期和时间功能3、增加闰年计算功能方案比拟:方案一:系统分为主控制器模块、显示模块、按键开关模块,主控制模块采用AT89C52单片机为控制中心,显示模块采用普通的共阴LED数码管,键输入采用中断实现功能调整,计时使用AT89C52单片机自带的定时器功能,实现对时间、日期的操作,通过按键盘开关实现对时间、日期的调整。
方案二:系统分为主控模块、时钟电路模块、按键扫描模块,LCD显示模块,电源电路、复位电路、晶振电路等模块。
主控模块采用AT89C52单片机,按键模块用四个按键,用于调整时间,显示模块采用LCD1602,时钟电路模块采用DS1302时钟芯片实现对时间、日期的操作。
两个方案工作原理大致相同,只有显示模块和时钟电路不同。
LED数码管价格适中,对于数字显示效果较好,而且使用单片机的端口也较少; LCD1602液晶显示屏,显示功能强大,可以显示大量文字、图形,显示多样性,清晰可见,价格相对LED数码管来说要昂贵些,但是基于本设计显示的东西较多,假设采用LED数码管的话,所需数码管较多,而且不利于控制,因此选择LCD1602作为显示模块。
DS1302是一款高性能的实时时钟芯片,以计时准确、接口简单、使用方便、工作电压范围宽和低功耗等优点,得到广泛的应用,实时时钟有秒、分、时、星期、日、月和年,月小于31天时可以自动调整,并具有闰年补偿功能,而且在掉电时能够在外部纽扣电池的供电下继续工作。
单片机有定时器的功能,但时间误差较大,且需要编写时钟程序,因此采用DS1302作为时钟电路。
比照以上方案,结合设计技术指标与要求我们选择了方案二进行设计。
逻辑总框图:该电子万年历的总体设计框图如图(1)所示。
电子万年历

摘要本设计是电子万年历。
具备三个功能:能显示年月日时分秒及星期信息,并具有可调整日期和时间功能。
我选用的是单片机8052来实现电子万年历的功能。
该电子万年历能够成功实现时钟运行,调整,显示年月日时分秒及星期,温度等信息。
该电子万年历使用12MHZ晶振与单片机8052相连接,通过软件编程的方法实现了以24小时为一个周期同时显示小时,分钟和秒的要求。
利用单片机定时器及计数器产生定时效果通过编程形成数字钟效果,再利用数码管动态扫描显示单片机内部处理的数据。
同时通过端口读入当前外部控制状态来改变程序的不同状态,实现不同功能。
电子万年历设计与制作可采用数字电路实现,也可以采用单片机来完成。
若用数字电路完成,所设计的电路相当复杂,大概需要十几片数字集成块,其功能也主要依赖于数字电路的各功能模块的组合来实现,焊接的过程比较复杂,成本也非常高。
若用单片机来设计制作完成,由于其功能的实现主要通过软件编程来完成,么就降低了硬件电路的复杂性,而且其成本也有所降低,更适合我们大学生自主研发。
所以在该设计与制作中我选用了单片机8052,它是低功耗、高性能的CMOS型8位单片机。
片内带有4KB的Flash存储器,且允许在系统内改写或用编程器编程。
另外, 单片机8052的指令系统和引脚与8051完全兼容,片内有128B 的RAM、32条I/O口线、2个16位定时计数器、5个中断源、一个全双工串行口等。
因此,采用单片机8052原理制作的电子万年历,不仅仅在原理上能够成功实现计时等功能,也更经济,更适用,更符合我们实际生活的需要,对我们大学生来说也更加有用。
目录1 概述 (3)1.1单片机原理及应用简介 (3)1.2系统硬件设计 (4)1.3结构原理与比较 (6)2 系统总体方案及硬件设计 (8)2.1系统总体方案 (8)2.2硬件电路的总体框图设计 (10)2.3硬件电路原理图设计 (11)3 软件设计 (12)3.1主程序流程图 (12)3.2显示模块流程图 (12)4 Proteus软件仿真 (14)4.1Proteus ISIS简介 (14)4.2仿真过程 (15)4.3仿真结果 (15)5 课程设计体会 (17)参考文献 (18)附1:源程序代码 (29)附2:系统原理图 (26)1 概述1.1单片机原理及应用简介随着国内超大规模集成电路的出现,微处理器及其外围芯片有了迅速的发展。
51单片机万年历课程设计报告

一、设计任务:1、设计任务:设计并制作一个数字钟。
2、设计要求:●显示年月日时分秒及星期信息●具有可调整日期和时间功能●增加闰年计算功能●显示部分由LCD1602完成二、方案论证:1.显示部分:显示部分是本次设计的重要部分,一般有以下两种方案:方案一:采用LED显示,分静态显示和动态显示。
对于静态显示方式,所需的译码驱动装置很多,引线多而复杂,且可靠性也较低。
而对于动态显示方式,虽可以避免静态显示的问题,但设计上如果处理不当,易造成亮度低,有闪烁等问题。
方案二:采用LCD显示。
LCD液晶显示具有丰富多样性、灵活性、电路简单、易于控制而且功耗小等优点,对于信息量多的系统,是比较适合的。
鉴于上述原因,我们采用方案二。
2.数字时钟:数字时钟是本设计的核心的部分。
根据需要可采用以下两种方案实现:方案一:方案完全用软件实现数字时钟。
原理为:在单片机内部存储器设三个字节分别存放时钟的时、分、秒信息。
利用定时器与软件结合实现1秒定时中断,每产生一次中断,存储器内相应的秒值加1;若秒值达到60,则将其清零,并将相应的分字节值加1;若分值达到60,则清零分字节,并将时字节值加1;若时值达到24,则将时字节清零。
该方案具有硬件电路简单的特点,但当单片机不上电,程序将不执行。
而且由于每次执行程序时,定时器都要重新赋初值,所以该时钟精度不高。
方案二:方案采用Dallas公司的专用时钟芯片DS1302。
该芯片内部采用石英晶体振荡器,其芯片精度不大于10ms/年,且具有完备的时钟闹钟功能,因此,可直接对其以用于显示或设置,使得软件编程相对简单。
为保证时钟在电网电压不足或突然掉电等突发情况下仍能正常工作,芯片内部包含锂电池。
当电网电压不足或突然掉电时,可使系统自动转换到内部锂电池供电系统。
而且即使系统不上电,程序不执行时,锂电池也能保证芯片的正常运行,以备随时提供正确的时间。
基于时钟芯片的上述优点,本设计采用方案二完成数字时钟的功能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
万年历数字钟及可调时钟系统一、引言万年历数字钟是一种用万年历时钟芯片实现年、月、日、时、分、秒计时,并通过单片机处理后送给显示芯片显示的装置,与机械式时钟相比具有更高的准确性和直观性,且具有更长的使用寿命。
本系统还可以扩展为可调的自动开关,对家电对用电设备进行控制,笔者在随后改制成为可调时的自动断电的供电系统.二、原理图设计1.单片机及其外围电路设计复位采用X25045芯片,复位电路如图1所示。
图1 复位电路设计单片机采用贴片封装的AT89S51,晶振为11.0592MHz。
其中P1.5~P1.7为下载程序使用,电路如图2所示。
图2 单片机89S51外围电路设计2.时钟芯片电路设计时钟芯片采用PCF8563,晶振采用32.768K,电容使用15pf。
PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接口功能的具有极低功耗的多功能时钟/日历芯片。
内部时钟电路、内部振荡电路、内部低电压检测电路(1.0V)以及两线制I2C 总线通讯方式,不但使外围电路及其简洁,而且也增加了芯片的可靠性。
同时每次读写数据后,内嵌的字地址寄存器会自动产生增量。
电路如图3所示。
图3 时钟芯片电路设计3.显示芯片电路设计显示芯片采用ZLG7289,晶振为12MHz。
ZLG7289A 是广州周立功单片机发展有限公司自行设计的,具有SPI 串行接口功能的可同时驱动8 位共阴式数码管(或64 只独立LED )的智能显示驱动芯片,该芯片同时还可连接多达64 键的键盘矩阵,单片即可完成LED 显示﹑键盘接口的全部功能。
电路如图4所示。
图4 显示芯片电路设计4.双电源电路设计系统采用双电源,平时使用V1=10V的外接电源,停电时使用电池,由V2输入。
电池有6节,其电压为9V。
当电池电压低于6V时,LED亮,说明电池电量不足。
电路如图5所示。
图5 双电源电路设计三、程序设计程序开始时先对系统初始化,并设置好各种中断。
下步操作主要是对时钟芯片进行操作,首先要给时钟芯片设置初值,时钟芯片便自行计数。
此时检测是否有按键按下,按键是为了调整时钟。
有按键按下则执行按键中断程序,没有按键按下则执行下一步的操作,即取时钟芯片中的时钟值,然后送显示。
程序流程图如下。
图6 总体流程图四、源程序#include <reg51.h>#include <intrins.h>#include <math.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intuchar close_date,open_date;void RESWDI(void);void WREN(void);void WRDI(void);void WRSR(void);unsigned char RSDR(void);void WIPCHK(void);void OUTByte(unsigned char Byte); unsigned char INPUTByte(void);unsigned char ReadByte(unsigned char ADD); void WriteByte(unsigned char Byte,ADD);#define _Nop() _nop_()sbit zlg7289_cs =P1^1;sbit zlg7289_clk =P2^6;sbit zlg7289_dio =P2^7;sbit zlg7289_key =P3^2;sbit p07=P0^7;sbit p06=P0^6;sbit CS=P2^4;sbit SCK=P2^2;sbit SO=P2^5;sbit SI=P2^3;sbit p10=P1^0;sbit SDA=P1^2; /*模拟I2C数据传送位*/sbit SCL=P1^3; /*模拟I2C时钟控制位*/uchar buf[9]={0x00,0x00,0x30,0x23,0x15,0x1,0x05,0x04,0x05}; uchar bufdata,bb,date;uchar SLA=0xA2,SUBA=0x00;uchar *p;uchar keychange=0;uchar key=0; /*键盘值*/bit keyint=0; /*按键中断标志*/bit keyok=1; /*数据是否修改好*/uchar num=0; /*移位键移到哪个LED*/void delay(uchar i){while(i--);}//******************** TIMER1 interrupt process ***************************//timer0 (void) interrupt 1 using 1{TH0=0x3c;TL0=0xb0;RESWDI();}void RESWDI(void) ////复位看门狗(喂狗){zlg7289_cs=1;CS =1;CS =0;CS =1;zlg7289_cs=1;}void WREN(void) //写使能复位使用)?{zlg7289_cs=1;SCK=0;CS=0;OUTByte(0x06); //发送06H写使能命令字SCK=0;CS=1;zlg7289_cs=1;}void WRDI(void) //写使能复位(禁止写{{zlg7289_cs=1;SCK=0;CS=0;OUTByte(0x04); //发送04H写禁止命令字SCK=0; CS=1;zlg7289_cs=1;}void WRSR(void) //写状态寄存器{WREN();zlg7289_cs=1;SCK=0;CS=0;OUTByte(0x01); //发送01H写寄存器命令字OUTByte(0x00); //发送寄存器值BL0,BL1为0没写保护,WD0=0 W01=1 //WD1=0WD1=0看门狗复位时间1.4SSCK=0;CS=1;zlg7289_cs=1;WIPCHK(); //判断是否写入}unsigned char RSDR(void) //读状态寄存器{unsigned char Temp;zlg7289_cs=1;SCK=0;CS=0;OUTByte(0x05); //发送05H读状态寄存器命令字Temp =INPUTByte(); //读状态寄存器值SCK=0;CS=1;return Temp;;//这一个调试时没有执行,Temp的值总是0xFF;??????????? zlg7289_cs=1;}void WIPCHK(void) //检查WIP位,判断是否写入完成{unsigned char Temp,TempCyc;for(TempCyc=0;TempCyc<50;TempCyc++){Temp =RSDR(); //读状态寄存器if (Temp&0x01==0)TempCyc =50;}}//单字节指令或数据写入X25045//在SI线上输入的数据在SCK的上升沿被锁存。
void OUTByte(unsigned char Byte) //输出一个定节{unsigned char TempCyc;zlg7289_cs=1;for(TempCyc=0;TempCyc<8;TempCyc++){SCK =0;if(Byte&0x80)SI =1;elseSI =0;SCK =1;Byte =Byte<<1; //右移}SI=0; //使SI处于确定的状态zlg7289_cs=1;}//单字节数据从X25045读到单片机//数据由SCK的下降沿输出到SO线上。
unsigned char INPUTByte(void) //输入一个字节{unsigned char Temp=0, TempCyc;zlg7289_cs=1;for(TempCyc=0;TempCyc<8;TempCyc++){Temp =Temp<<1; //右移SCK =1;SCK=0;if (SO)Temp =Temp|0x01; //SO为1,则最低位为1elseTemp&=0xFE;}return Temp;;//这一个调试时没有执行,Temp的值总是0zlg7289_cs=1;}unsigned char ReadByte(unsigned char ADD) //读地址中的数据这里不做先导字处理,只能读00-FFH{unsigned char Temp;zlg7289_cs=1;SCK=0;CS=0;SO=1;SI=1;OUTByte(0x3); //发送读指令03H 如要支持000-FFF则要把高位地址左移3位再为03H相或OUTByte(ADD); //发送低位地址Temp =INPUTByte();SCK=0;CS=1;return Temp;//这一个调试时没有执行,Temp的zlg7289_cs=1;}void WriteByte(unsigned char Byte,ADD) //向地址写入数据这里同样不做先导字处理,只能写00-FFH{WREN();zlg7289_cs=1;SCK=0;CS=0;SO=1;SI=1;OUTByte(0x2); //发送写指令02H 如要支持000-FFF则要把高位地址左移2位再为02H相或OUTByte(ADD); //发送低位地址OUTByte(Byte); //发送数据SCK=0;CS=1;WIPCHK();zlg7289_cs=1;}/***********************************************************************************模拟I2C总线传输程序*******************************************************************************************************/bit ack; /*应答标志位*//*******************************************************************起动总线函数********************************************************************/{SDA=1; /*发送起始条件的数据信号*/_Nop();SCL=1;_Nop(); /*起始条件建立时间大于4.7us,延时*/_Nop();_Nop();_Nop();_Nop();SDA=0; /*发送起始信号*/_Nop(); /* 起始条件锁定时间大于4μs*/_Nop();_Nop();_Nop();_Nop();SCL=0; /*钳住I2C总线,准备发送或接收数据*/_Nop();_Nop();}/*******************************************************************结束总线函数********************************************************************/{SDA=0; /*发送结束条件的数据信号*/_Nop(); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4μs*/_Nop();_Nop();_Nop();_Nop();_Nop();SDA=1; /*发送I2C总线结束信号*/_Nop();_Nop();_Nop();_Nop();}/*******************************************************************字节数据传送函数********************************************************************/ void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/{if((c<<BitCnt)&0x80)SDA=1;else SDA=0;_Nop();SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();_Nop(); /*保证时钟高电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0;}_Nop();_Nop();SDA=1; /*8位发送完后释放数据线,准备接收应答位*/_Nop();_Nop();SCL=1;_Nop();_Nop();_Nop();if(SDA==1)ack=0;else ack=1; /*判断是否接收到应答信号*/SCL=0;_Nop();_Nop();}/******************************************************************* 字节数据接收函数********************************************************************/ uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; /*置数据线为输入方式*/for(BitCnt=0;BitCnt<8;BitCnt++){_Nop();SCL=0; /*置时钟线为低,准备接收数据位*/_Nop();_Nop(); /*时钟低电平周期大于4.7s*/_Nop();_Nop();_Nop();SCL=1; /*置时钟线为高使数据线上数据有效*/_Nop();_Nop();retc=retc<<1;if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();_Nop();}SCL=0;_Nop();_Nop();return(retc);}/********************************************************************应答子函数********************************************************************/ void Ack_I2c(bit a){if(a==0)SDA=0; /*在此发出应答或非应答信号*/else SDA=1;_Nop();_Nop();_Nop();SCL=1;_Nop();_Nop(); /*时钟低电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/_Nop();_Nop();}/*******************************************************************向有子地址器件发送多字节数据函数********************************************************************/ bit ISendStr(uchar sla,uchar suba,uchar *s){uchar i;Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(suba); /*发送器件子地址*/if(ack==0)return(0);for(i=0;i<9;i++){SendByte(*s); /*发送数据*/if(ack==0)return(0);s++;}Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向有子地址器件读取多字节数据函数********************************************************************/ bit IRcvStr(uchar sla,uchar suba,uchar *s){uchar i;Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(suba); /*发送器件子地址*/if(ack==0)return(0);Start_I2c();SendByte(sla+1);if(ack==0)return(0);for(i=0;i<8;i++){*s=RcvByte(); /*发送数据*/Ack_I2c(0); /*发送就答位*/s++;}*s=RcvByte();Ack_I2c(1); /*发送非应位*/ Stop_I2c();return(1);}/**********模拟I2C程序结束***************************/void display(uint dis){uchar j;zlg7289_clk=0;delay(20);zlg7289_cs=0;for(j=0;j<16;j++){if((dis&0x8000)==0x8000) zlg7289_dio=1;else zlg7289_dio=0;delay(20);zlg7289_clk=1;delay(10);zlg7289_clk=0;delay(10);dis=dis<<1;}zlg7289_cs=1;delay(20);}void dis_play(uchar aa){uchar i;for(i=0;i<8;i++){if(_crol_(aa,i)&0x80)zlg7289_dio =1;elsezlg7289_dio =0;zlg7289_clk =1;delay(10);zlg7289_clk =0;}}void displaymonth(){bufdata=buf[5]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xc8);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=buf[5]&0x30;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xc9);delay(10);dis_play(bufdata); zlg7289_cs=1;delay(70);bufdata=buf[7]&0x0f; zlg7289_cs=0;delay(10);dis_play(0xca);delay(10);dis_play(bufdata); zlg7289_cs=1;delay(70);bufdata=buf[7]&0x10; bufdata=bufdata>>4; bufdata=bufdata&0x0f; zlg7289_cs=0;delay(10);dis_play(0xcf);delay(10);dis_play(bufdata); zlg7289_cs=1;delay(70);}void displaytime(){bufdata=buf[3]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xce);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=buf[3]&0x70;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcd);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=buf[4]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcc);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=buf[4]&0x30;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcb);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);}void display_x5045(){date=ReadByte(0x40);close_date=date;bufdata=date&0x0f;zlg7289_cs=0;delay(10);dis_play(0xce);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=date&0x70; bufdata=bufdata>>4; bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcd);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);date=ReadByte(0x42); bufdata=date&0x0f;zlg7289_cs=0;open_date=ReadByte(0x42);delay(10);dis_play(0xcc);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);bufdata=date&0x30;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcb);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);}/****************按键处理程序*********************/ //key=47: 闪烁移位键(shift)//key=39: +//key=39: -//key=31: 确认键(ok)void key_int() interrupt 0{keyint=1;}void keyexe(){uchar i;uchar temp=0;uchar aa;p06=1;EX0=1;zlg7289_cs =0;delay(10);dis_play(0x15); /*写入读键盘数据指令*/delay(10);for(i=0;i<8;i++){temp=temp<<1;aa=zlg7289_dio; // 按位或if(aa==1) // 读数据位,接收的数据位放入retc中temp=temp+1;zlg7289_clk=1;delay(10); // 延时zlg7289_clk=0;}zlg7289_cs=1;key=temp;if(key==47) //闪烁移位键{key=0;keyok=0;EX0=0;if(num==8){num=1;}elsenum++;switch(num){ case 1: {display(0x88fe);}break;case 2: {display(0x88fd);}break;case 3: {display(0x88fb);}break;case 4: {display(0x88f7);}break;case 5: {display(0x88ef);}break;case 6: {display(0x88df);}break;case 7: {display(0x88bf);}break;case 8: {display(0x887f);}break;default: ;}EX0=1;}else if(key==39) //+{EX0=0;key=0;RESWDI();if(num!=0){keyok=0;keychange=1;RESWDI();}if(num==7) //在分个位上{if((buf[3]&0x0f)==0x09) buf[3]&=0xf0;else ++buf[3];EX0=1;bufdata=buf[3]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xce);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==6) //在分十位上{if((buf[3]&0xf0)==0x50) buf[3]&=0x0f;else buf[3]+=0x10;EX0=1;bufdata=buf[3]&0x70;bufdata=bufdata>>4;bufdata=bufdata&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcd);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==5) //在小时个位上{if((buf[4]&0xf0)==0x20){if((buf[4]&0x0f)>0x02) buf[4]&=0xf0;else ++buf[4];}else if((buf[4]&0x0f)==0x09) buf[4]&=0xf0;else ++buf[4];EX0=1;bufdata=buf[4]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xcc);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==4) //在小时十位上{if((buf[4]&0x0f)>0x03){if((buf[4]&0xf0)>0x00) buf[4]&=0x0f;else buf[4]+=0x10;}else if((buf[4]&0xf0)==0x20) buf[4]&=0x0f;else buf[4]+=0x10;EX0=1;bufdata=buf[4]&0x30;bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;RESWDI();delay(10);dis_play(0xcb);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==1) //在日的个位上{if((buf[5]&0xf0)==0x30){if((buf[5]&0x0f)>0x00) buf[5]&=0xf0;}else if((buf[5]&0x0f)==0x09) buf[5]&=0xf0;else ++buf[5];EX0=1;bufdata=buf[5]&0x0f;RESWDI();zlg7289_cs=0;delay(10);dis_play(0xc8);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==2) //在日的十位上{if((buf[5]&0x0f)>0x01){if((buf[5]&0xf0)>0x10) buf[5]&=0x0f;else buf[5]+=0x10;}else if((buf[5]&0xf0)==0x30) buf[5]&=0x0f;EX0=1;bufdata=buf[5]&0x30;RESWDI();bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;delay(10);dis_play(0xc9);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==4) //在月个位上{if((buf[7]&0xf0)==0x10){if((buf[7]&0x0f)>0x01) buf[7]&=0x0f;else ++buf[7];}else if((buf[7]&0x0f)==0x09) buf[7]&=0xf0;else ++buf[7];EX0=1;bufdata=buf[7]&0x0f;RESWDI();zlg7289_cs=0;delay(10);dis_play(0xca);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);RESWDI();}else if(num==8) //在月十位上{if((buf[7]&0x0f)>0x02){buf[7]&=0x0f;}else if((buf[7]&0xf0)==0x10) buf[7]&=0x0f;else buf[7]+=0x10;EX0=1;bufdata=buf[7]&0x10;bufdata=bufdata>>4;bufdata&=0x0f;RESWDI();zlg7289_cs=0;delay(10);dis_play(0xcf);delay(10);dis_play(bufdata); /*显示月十位*/zlg7289_cs=1;delay(70);RESWDI();}else ;}else if(key==15) //存放断电时间,数据存放于5045中,每按键数据减少一{display_x5045();EX0=1;key=0;if(num!=0){keyok=0;keychange=1;}if(num==7) //在分个位上{date=ReadByte(0x40);if((date&0x0f)==0x00) date|=0x09;else --date;EX0=1;bufdata=date&0x0f;zlg7289_cs=0;delay(10);dis_play(0xce);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);WriteByte(date,0x40);}else if(num==6) //在分十位上{date=ReadByte(0x40);if((date&0xf0)==0x00) date|=0x50;else date-=0x10;EX0=1;bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;delay(10);dis_play(0xcd);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);WriteByte(date,0x40);}else if(num==5) //在小时个位上{date=ReadByte(0x42);if((date&0xf0)==0x20){if(((date&0x0f)==0x00)||((date&0x0f)>0x03)) date|=0x03;else --date;}else if((date&0x0f)==0x00) date|=0x09;else --date;EX0=1;zlg7289_cs=0;delay(10);dis_play(0xcc);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);WriteByte(date,0x42);}else if(num==4) //在小时十位上{date=ReadByte(0x42);if((date&0x0f)>0x03){if((date&0xf0)==0x00) date|=0x10;else date-=0x10;}else if((date&0xf0)==0x00) date|=0x20;else date-=0x10;EX0=1;bufdata=date&0x30;bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;delay(10);dis_play(0xcb);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);WriteByte(date,0x42);}else if(num==1) //在日的个位上{if((buf[5]&0xf0)==0x30){if(((buf[5]&0x0f)==0x00)||((buf[5]&0x0f)>0x01)) buf[5]|=0x01;else --buf[5];}else if((buf[5]&0x0f)==0x00) buf[5]|=0x09;else --buf[5];bufdata=buf[5]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xc8);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);}else if(num==2) //在日的十位上{if((buf[5]&0x0f)>0x01){if((buf[5]&0xf0)==0x00) buf[5]|=0x20;else buf[5]-=0x10;}else if((buf[5]&0xf0)==0x00) buf[5]|=0x30;else buf[5]-=0x10;bufdata=buf[5]&0x30;bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;delay(10);dis_play(0xc9);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);}else if(num==3) //在月个位上{if((buf[7]&0xf0)==0x10){if(((buf[7]&0x0f)==0x00)||((buf[7]&0x0f)>0x01)) buf[7]|=0x01;else --buf[7];}else if((buf[7]&0x0f)==0x00) buf[7]|=0x09;else --buf[7];bufdata=buf[7]&0x0f;zlg7289_cs=0;delay(10);dis_play(0xca);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);}else if(num==8) //在月十位上{if((buf[7]&0x0f)>0x02) buf[7]&=0x0f;else if((buf[7]&0xf0)==0x00) buf[7]|=0x10;else buf[7]-=0x10;bufdata=buf[7]&0x10;bufdata=bufdata>>4;bufdata&=0x0f;zlg7289_cs=0;delay(10);dis_play(0xcf);delay(10);dis_play(bufdata);zlg7289_cs=1;delay(70);EX0=1;}else ;}else if(key==31) //ok{EX0=0;key=0;keyok=1;num=0;if(keychange==1){keychange=0;p=buf;SUBA=0x00;buf[0]=0x00;buf[1]=0x00;buf[2]=0x00;ISendStr(SLA,SUBA,p);for (i=0;i<250;i++)delay(250);}else ;zlg7289_cs=0;delay(10);dis_play(0x88);delay(10);dis_play(0xff); /*清LED闪烁*/zlg7289_cs=1;delay(70);}EX0=1;}/************************************************************ *******主函数************************************************ void main(){unsigned char i,j,word2;/*程序的初始化**************************/TMOD=0x09;TH0=0x3c;TL0=0xb0;TR0=1;ET0=1;IP=0x02; //中断优先级敲定IT0=1;EX0=1;IE0=1;EA=1; /*打开全部中断*/p10=1;p06=1;p07=1;WREN();WRSR();WRDI();WriteByte(0x07,0x40);//在0x20中写入0x10,( 为了验证)WriteByte(0x0a,0x42);WRDI();word2=ReadByte(0x22);。