南京工程学院
课程设计说明书(论文)
题 目 实时钟芯片PCF8563的应用
课 程 名 称 单片机原理及应用A
院 (系、部、中心) 通信工程学院
专 业 电子信息工程(传感网)
班 级
学 生 姓 名
学 号
设 计 地 点 信息楼 C 210
指 导 教 师
设计起止时间:20##年12月23日至 20##年12月27日
目录
一、摘要··························································· 1
二、课程设计任务书···················································2
三、基本思路·······················································4
四、系统的硬件设计框图··············································4
五、系统的软件设计框图··············································5
六、相关芯片和硬件设备简介··········································7
七、系统运行结果与分析··············································15
八、设计心得体会··················································19
九、参考文献·······················································20
十、附录(源程序)····················································21
一、 摘要
近年来随着计算机在社会领域的渗透和大规模集成电路的发展,单片机的应用正在不断地走向深入,由于它具有功能强,体积小,功耗低,价格便宜,工作可靠,使用方便等特点,因此特别适合于与控制有关的系统,越来越广泛地应用于自动控制,智能化仪器,仪表,数据采集,军工产品以及家用电器等各个领域,单片机往往是作为一个核心部件来使用,在根据具体硬件结构,以及针对具体应用对象特点的软件结合,以作完善。
随着集成电路和计算机技术的迅速发展,使电子仪器的整体水平发生巨大变化,传统的仪器逐步的被智能仪器所取代。智能仪器的核心部件是单片机,因其极高的性价比得到广泛的应用与发展,从而加快了智能仪器的发展。而传感器作为测控系统中对象信息的入口,越来越受到人们的关注。传感器好比人体“五官”的工程模拟物,它是一种能将特定的被测量信息(物理量、化学量、生物量等)按一定规律转换成某种可用信号输出的器件或装置本次课设中的半桥电子秤就是在以上仪器的基础上设计而成的。因此,只有充分了解有关智能仪器、单片机、传感器以及各部分之间的关系才能达到要求。
单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。概括的讲:一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、为学习、应用和开发提供了便利条件。同时,学习使用单片机是了解计算机原理与结构的最佳选择。单片机内部也用和电脑功能类似的模块,比如CPU,内存,并行总线,还有和硬盘作用相同的存储器件,不同的是它的这些部件性能都相对我们的家用电脑弱很多,不过价钱也是低的,一般不超过10元即可......用它来做一些控制电器一类不是很复杂的工作足矣了。我们现在用的全自动滚筒洗衣机、排烟罩、VCD等等的家电里面都可以看到它的身影!......它主要是作为控制部分的核心部件。
而51系列单片机是各单片机中最为典型和最有代表性的一种,通过本次课程设计进一步对单片机学习和应用,从而更熟悉单片机的原理和相关设计并提高了开发软、硬件的能力。本设计主要在nKDE51单片机实验教学系统上,利用PCF8563日历时钟IC设计一个数字式电子钟,在1602 LCD显示器上显示日期和时间,通过键盘实现日期和时间的设置和校准。
二、课程设计任务书
三、基本思路
电子时钟主要由显示模块,校时模块和时钟运算模块三大部分组成。其中校时模块和时钟运算模块要对年,月,日,时,分,秒的数量进行操纵,并且当秒计到59时,要自己清零即显示秒的模块都为零并向分进一,分计到59时,自己也要清零并向时进1,时计到24时,时就要清零又从秒开始计时;像上述一样,循环计时到365次时向年进一,如此便实现了电子时钟对年,月,日,时,分,秒的数值操纵。通过芯片产生的年月日及日期再通过1602液晶显示器显示出来,同时添加了整点报时功能:每当数字钟计时到整点时发出声响,并且响5秒(程序中自己设置的),另外还自行添加了上下课打铃和闹钟设定功能,可以通过外部按键改变设定值。
四、系统的硬件设计框图
五、系统的软件设计框图
1、系统图
2、软件设计流程图
(1)软件程序内容
本设计的软件程序包括主程序、延时程序、1602字符点阵液晶显示器的显示模块、实时钟PCF8563芯片的初始化及读写程序、欢迎界面显示子程序、清屏子程序、定时打铃子程序、时钟显示子程序、查询时间表切换程序、按键子程序和延时子程序等等。另外,还设计了上下课时间打铃子程序、闹钟子程序和防抖动程序。
其中在主函数中首先初始化时钟芯片和1602字符点阵液晶显示屏,然后滚动显示欢迎界面“zong lao shi Nice to meet you”,延时一段时间后清屏,再显示本人姓名“yang jia jia ”,再延时一段时间后清屏,显示本人学号208110732,最后用while循环显示主页面,主页面共有两个,一个是闹钟时间设置,另一个便是年月日及时间显示的页面,两个页面可以通过开关或者按钮输入“0”“1”信号进行控制切换。在本设计中两个主显示页面都是通过调用按键检测子函数来实现的,在按键检测子函数中可以通过开关和按钮选择需要显示的主页面,然后在相应的主页面中通过矩阵键盘来设置液晶显示器上显示的年月日及时间的值或者设定闹钟的时间。无论在哪个主页面下,都添加了打铃和整点报时子程序。具体的设计流程图如下图所示。
(2)主函数流程图
六、相关芯片和硬件设备简介
1 AT89C51
AT89C51是一种带4K字节FLASH 存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压、高性能CMOS 8位微处理器,俗称单片机。AT89C2051是一种带2K字节闪存可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除1000次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。AT89C单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
主要特性:
·与MCS-51 兼容 ·4K字节可编程FLASH存储器
·寿命:1000写/擦循环 ·数据保留时间:10年
·全静态工作:0Hz-24MHz ·三级程序存储器锁定
·128×8位内部RAM ·32可编程I/O线
·两个16位定时器/计数器 ·5个中断源
·可编程串行通道 ·低功耗的闲置和掉电模式
·片内振荡器和时钟电路
特性概述:
AT89C51 提供以下标准功能:4k 字节Flash 闪速存储器,128字节内部RAM,32 个I/O 口线,两个16位定时/计数器,一个5向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同时,AT89C51可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
管脚说明:
VCC:供电电压。 GND:接地。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P0口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的低八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须接上拉电阻。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为低八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
P3口也可作为AT89C51的一些特殊功能口,如下表所示:
口管脚 备选功能 P3.0 RXD(串行输入口)
P3.1 TXD(串行输出口) P3.2 /INT0(外部中断0)
P3.3 /INT1(外部中断1) P3.4 T0(记时器0外部输入)
P3.5 T1(记时器1外部输入) P3.6 /WR(外部数据存储器写选通)
P3.7 /RD(外部数据存储器读选通)
P3口同时为闪烁编程和编程校验接收一些控制信号。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的低位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想禁止ALE的输出可在SFR8EH地址上置0。此时, ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
振荡器特性:
XTAL1和XTAL2分别为反向放大器的输入和输出。该反向放大器可以配置为片内振荡器。石晶振荡和陶瓷振荡均可采用。如采用外部时钟源驱动器件,XTAL2应不接。有余输入至内部时钟信号要通过一个二分频触发器,因此对外部时钟信号的脉宽无任何要求,但必须保证脉冲的高低电平要求的宽度。
2 PCF8563
PCF8563是PHILIPS公司生产的低功耗CMOS实时时钟/日历芯片,芯片最大总线速度为400kbits/s,每次读写数据后,其内嵌的字地址寄存器器会自动产生增量。PCF8563可广泛应用于移动电话、便携仪器、传真机、电池电源等产品中。
PCF8563的引脚排列如图1所示,各引脚功能说明如表1所列。
PCF8563有16个8位寄存器,其中包括:可自动增量的地址寄存器、内置32.768kHz的振荡器(带有一个内部集成电容)、分频器(用于给实时时钟RTC提供源时钟)、可编程时钟输出、定时器、报警器、掉电检测器和400kHz的I2C总线接口。所有16个寄存器设计成可寻址的8位并行寄存器,但不是所有位都有用。当一个RTC寄存器被读时,所有计数器的内容将被锁存,因此,在传送条件下,可以禁止对时钟/日历芯片的错读。表2、表3所列为各寄存器概况及对应的内存地址和功能,同时列出了它们的BCD格式编码。表中“——”表示无效位,“0”表示此位应置逻辑。表3中的世纪位C=0指定世纪数为20XX,C=1指定世纪数为19XX。当年寄存器中的99变00时,世纪位才会改变。
主要特性有:
1、宽电压范围 1.0~5.5V, 复位电压标准值Vlow=0.9V。
2、超低功耗:典型值为 0.25uA (VDD=3.0V,Tamb=25℃)。
3、可编程时钟输出频率为:32.768KHz 、1024Hz 、32Hz 、1Hz。
4、四种报警功能和定时器功能。
5、内含复位电路、振荡器电容和掉电检测电路。
6、开漏中断输出。
7、400kHz I2C总线(VDD=1.8~5.5V),其从地址读 0A3H;写 0A2H。
基本工作原理
PCF8563 有 16 个位寄存器:一个可自动增量的地址寄存器,一个内置 32.768KHz的振荡器(带有一个内部集成的电容)一个分频器(用于给实时时钟RTC 提供源时钟)一个可编程时钟输出,一个定时器,一个报警器,一个掉电检测器和一个 400KHz I2C 总线接口。
所有16 个寄存器设计成可寻址的 8 位并行寄存器,但不是所有位都有用。前两个寄存器(内存地址 00H,01H)用于控制寄存器和状态寄存器,内存地址 02H~08H 用于时钟计数器(秒~年计数器) ,地址 09H~0CH 用于报警寄存器(定义报警条件) ,地址 0DH 控制CLKOUT 管脚的输出频率,地址 0EH 和 0FH 分别用于定时器控制寄存器和定时器寄存器。秒、分钟、小时、日、月、年、分钟报警、小时报警、日报警寄存器,编码格式为 BCD, 星期和星期报警寄存器不以 BCD 格式编码。当一个 RTC 寄存器被读时,所有计数器的内容被锁存,因此,在传送条件下,可以禁止对时钟日历芯片的错读。
寄存器概况:
地址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 00H 控制/状态寄存器1 TEST 0 STOP 0 TESTC 0 0 0 01H 控制/状态寄存器2 0 0 0 TI/TP AF TF AIE TIE 0DH CLKOUT频率寄存器 FE — — — — — FD1 FD0 0EH 定时器控制寄存器 TE — — — — — TD1 TD0 0FH 定时器倒计数数值寄存器 定时器倒计数数值
BCD格式寄存器概况:
地 址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 02H 秒 VL 00~59BCD码格式数03H 分钟 - 00~59BCD码格式数 04H 小时 - - 00~23BCD码格式数 05H 日 - - 01~31BCD码格式数06H 星期 - - - - - 0~6 07H 月/世纪 C - - 01~12BCD码格式数 08H 年 00~99BCD码格式数 09H分钟报警 AE 00~59BCD码格式数 0AH 小时报警 AE - 00~23BCD码格式数 0BH 日报警 AE -01~31BCD码格式数 0CH 星期报警 AE - - - - 0~6 2.2 启动和停止条件总线不忙时,数据线和时钟线保持在高电平。数据线(SDA)在下降沿而时钟线(SCL)为高电平时,为起动条件(S);数据线在上升沿而时钟线为高电平时为停止条件(P)。 2.3 位传送每个时钟脉冲传送一个数据位,SDA线上的数据在时钟脉冲高电平时应保持稳定,否则将成为控制信号。 2.4 标志位在起动条件和停止条件之间,传送器传送给接收器的数据数量没有限制。在每个8位字节后加一个标志位,传送器便产生一个高电平的标志位,这时主设备产生一个附加标志位时钟脉冲。从接受器必须在接收到每个字节后产生一个标志位,主接收器也必须在接收从传送器传送的每个字节后产生一个标志位。在标志位时钟脉冲出现时,SDA线应保持低电平(应考虑起动和保持时间)。传送器应在从设备接收到最后一个字节时变为低电平,而使接收器产生标志位,这时主设备即可产生停止条件。2.5 I2C总线协议 用I2C总线传递数据前,接收的设备应先标明地址,在I2C总线起动后,这个地址与第一个传送字节一起被传送出去。PCF8563可以作为一个从接收器或从传送器,此时的时钟信号线SCL只能输入信号线,数据信号线SDA则为一条双向信号线。
应用概述:
图7所示为PCF8563的具体应用电路图,对图中石英晶片频率的调整,笔者给出3种可行性方法,供参考: 方法1:定值OSCI电容。计算所需的电容平均值,用此值的定值电容,通电后在CLKOUT管脚上测出的频率应为32.768kHz,测出的频率值偏差取决于石英晶片本身,电容偏差和器件之间的偏差平均为±5×10 -6。平均偏差可达5分钟/年。 方法2:OSCI微调电容。可通过调整OSCI管脚的微调电容式振荡器的频率来获得更高的精度,此时可测出通电时管脚CLKOUT上的信号频率为32.768kHz。 方法3:OSCI输出。直接测量管脚OSCI的输出
3、 LCD1602
1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符。每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用,正因为如此所以他不能显示图形。
n1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
n目前市面上字符液晶绝大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。
管脚功能:
1602采用标准的16脚接口,其中:
第1脚:VSS为电源地 第2脚:VDD接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会 产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端。
第7~14脚:D0~D7为8位双向数据端。
第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。
(3)16进制ASCII码表
七、系统运行结果与分析
数据记录
编译成功后,显示器上显示了详细的年、月、日、星期及具体的时间,且蜂鸣器在到达整点时就会响五秒 。同时也在年和时的前面加了“D”和“T”,做了一些改进。
编译程序截图:
运行程序截图:
总接线图:
欢迎界面一:滚动播放“zong lao shi Nice to meet you”
欢迎界面二:显示我的姓名:
主界面一:闹钟显示界面
主界面二:年月日及时间显示界面
八、设计心得体会
本次课程设计与我们以往的相比难度有所增加,对编程能力和动手操作能力要求很高,这主要是此次设计对知识的要求较为综合,我们用到了单片机、keil-c51及C语言编程、LCD液晶显示、PCF8563实时钟芯片等知识,所以,刚开始时,我们不知道从何下手。不过后来在宗老师要求先从设计指导书上最基础的实验开始做起,以及自己不断的查找资料,和同学商量,终于开始有点头目了,慢慢的便进入了状态。
但是在做的过程中还是遇到了很多问题,例如将编写好的源程序输入电脑,编译后出现很多错误,这些错误有许多是平时的实验遇到过的,例如:输入的分号格式不正确,零和字母O弄混淆了等等,幸好这些错误在平时的实验中遇到了,所以改错误很容易,但同时也说明了,平时的错误现在还在犯,证明错误我还没有完全的改正,这点我们以后一定要注意了。争取错误犯了两次就不能再犯了。感觉最难的部分是液晶屏显示部分,因为以前从未遇到过,所以程序编写起来很生硬,好多例程的程序都不是太懂,但是经过和同学的讨论,基本上都能够掌握了。
经过多次的修改和向别人请教,错误都排除了,编译通过了,但功能没有达到设计的要求,最主要的就是设计的原理图太多错误,不能进行仿真。最后,经过几天在实验室的努力,终于实现了时钟的全部要求,并且添加了闹钟和按键及液晶屏滚动显示等功能。
通过本次设计,我们系统的了解了实时时钟的设计流程,尤其是硬、软件的设计方法,掌握了LCD液晶屏显示电路的基本功能及编程方法,掌握了键盘电路和显示电路的一般原理,也进一步掌握了实时钟芯片PCF8563的使用和和编程方法。开拓了思路,锻炼了实践动手能力,提高了分工协作能力和分析问题,解决问题的能力,达到了本次课程设计的目的。在调试电路的过程中也积累了一些宝贵的经验。在整个设计中我懂得了许多东西,也培养了我独立工作的能力,树立了对自己工作能力的信心,相信会对今后的学习工作生活有非常重要的影响。而且大大提高了动手的能力,使我充分体会到了在创造过程中探索的艰难和成功时的喜悦。虽然这个设计做的也不太好,但是在设计过程中所学到的东西是这次课程设计的最大收获和财富。
单片机课程设计虽然结束了,但通过设计所学到的东西将长久存在。相信这次设计带给我们的严谨的学习态度和一丝不苟的科学作风将会给我们未来的工作和学习打下一个更坚实的基础。
九、参考文献
1、《单片机原理及应用实验与课程设计指导书》南京工程学院,20##年
2、《nKDE51单片机实验教学系统实验指导书》南京邮电大学,20##年
3、《单片机原理与应用及C51程序设计》(第2版),谢维成等编著,清华大学出版社,20##年
4、《单片机原理及应用》(第2版),李建忠,西安电子科技大学出版社,20##年
5、单片机的C语言应用程序设计(第4版),马忠梅等编著,北京航空航天大学出版社,2007.1。
十、附录(源程序)
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar num;
sbit rw = P1^1;
sbit lcdrs = P1^2;
sbit lcden = P1^0;
sbit sda = P1^6;
sbit beep = P3^7;
sbit change = P1^4;
uint year;
uchar s,hour,min,sec,week,mon,day,hour2=9,min2=0,sec2=0;
sbit scl=P1^7;
uchar flag=0;
uchar flag1=0;
uchar code table[]={'0','1','2','3','4','5','6','7','8','9',':','-',' ','*'};
//table1显示的是星期 table1[]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
uchar code table1[]={'S','u','n','M','o','n','T','u','e','W','e','d','T','h','u','F','r','i','S','a','t'};
uchar code table2[]={"Jiajia"};
void delayus(); //延时微秒
void write_add(uchar address,uchar date);
void write_com(uchar com);
void write_data(uchar date);
void test_keyboard1();
void test_keyboard2();
void LCMclear();
/******************************************
延时模块
******************************************/
delay(uint t)
{
uint i,j;
for(i=0;i<t;i++)
{
for(j=0;j<120;j++)
{;}
}
return i;
}
/******************************************
将指令写入液晶显示器模块
******************************************/
void write_com(uchar com)
{
rw=0; //读写选择控制端口 rw=0进行写入操作
lcdrs=0;
P0=com;
delay(5);
lcden=1; //使能控制端口
delay(5);
lcden=0;
}
/******************************************
将写入的指令在液晶显示器显示模块
******************************************/
void write_data(uchar date)
{
lcdrs=1; //rs=1进行读入操作
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
/******************************************
程序的初始化模块
******************************************/
void init()
{
rw=0;
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80+0x10);
sda=1;
delayus();
scl=1;
delayus();
write_add(0x00,0x00);
write_add(0x01,0x00);
write_add(0x02,0x00); //秒
write_add(0x03,0x59); //分
write_add(0x04,0x08); //时
write_add(0x05,0x27); //日
write_add(0x06,0x05); //星期
write_add(0x07,0x12); //月
write_add(0x08,0x13); //年
}
/******************************************
延时微秒模块
******************************************/
void delayus()
{
;
}
/******************************************
程序的开始停止应答信号模块
******************************************/
void start() //开始信号
{
sda=1;
delayus();
scl=1;
delayus();
sda=0;
delayus();
}
void stop() //停止
{
sda=0;
delayus();
scl=1;
delayus();
sda=1;
delayus();
}
void respons() //应答
{
uchar i;
scl=1;
delayus();
while((sda==1)&&(i<250))i++;
scl=0;
delayus();
}
/******************************************
写一个字节子函数
******************************************/
void write_byte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delayus();
sda=CY;
delayus();
scl=1;
delayus();
}
scl=0;
delayus();
sda=1;
delayus();
}
/******************************************
读一个字节函数子程序
******************************************/
uchar read_byte()
{
uchar i,k;
scl=0;
delayus();
sda=1;
delayus();
for(i=0;i<8;i++)
{
scl=1;
delayus();
k=(k<<1)|sda;
scl=0;
delayus();
}
return k;
}
/******************************************
往一个单元里写内容函数
******************************************/
void write_add(uchar address,uchar date)
{
start();
write_byte(0xa2);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
/******************************************
读一个单元的内容
******************************************/
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa2);
respons();
write_byte(address);
respons();
start();
write_byte(0xa3);
respons();
date=read_byte();
stop();
return date;
}
/******************************************
将读出的数写入hour与min中
******************************************/
void read8563()
{
sec=read_add(0x02);
min=read_add(0x03);
hour=read_add(0x04);
day=read_add(0x05);
week=read_add(0x06);
mon=read_add(0x07);
year=read_add(0x08);
}
/******************************************
液晶显示器滚屏显示欢迎界面模块一
Zong lao shi
Nice to meet you
******************************************/
void display1()
{
if(flag!=0)
{
write_com(0x06);
switch(flag)
{
case 1: write_com(0x80+0x40+6);
write_com(0x0f);delay(800);break;
case 2: write_com(0x80+0x40+3);
write_com(0x0f);delay(800);break;
case 3: write_com(0x80+0x40+0);
write_com(0x0f);delay(800);break;
case 4: write_com(0x80+13);
write_com(0x0f);delay(800);break;
case 5: write_com(0x80+8);
write_com(0x0f);delay(800);break;
case 6: write_com(0x80+5);
write_com(0x0f);delay(800);break;
case 7: write_com(0x80+2);
write_com(0x0f);delay(800);break;
default:break;
}
}
write_com(0x80+0x02);
write_data('z');
write_data('o');
write_data('n');
write_data('g');
delay(1000);
LCMclear();
write_com(0x80+0x07);
write_data('l');
write_data('a');
write_data('o');
delay(1000);
LCMclear();
write_com(0x80+0x0b);
write_data('s');
write_data('h');
write_data('i');
delay(1000);
LCMclear();
write_com(0x80+0x40);
write_data('N');
write_data('i');
write_data('c');
write_data('e');
delay(1000);
LCMclear();
write_com(0x80+0x45);
write_data('t');
write_data('o');
delay(1000);
LCMclear();
write_com(0x80+0x48);
write_data('m');
write_data('e');
write_data('e');
write_data('t');
delay(1000);
LCMclear();
write_com(0x80+0x4d);
write_data('y');
write_data('o');
write_data('u');
delay(1000);
LCMclear();
write_com(0x80+0x02);
write_data('z');
write_data('o');
write_data('n');
write_data('g');
write_com(0x80+0x07);
write_data('l');
write_data('a');
write_data('o');
write_com(0x80+0x0b);
write_data('s');
write_data('h');
write_data('i');
write_com(0x80+0x40);
write_data('N');
write_data('i');
write_data('c');
write_data('e');
write_com(0x80+0x45);
write_data('t');
write_data('o');
write_com(0x80+0x48);
write_data('m');
write_data('e');
write_data('e');
write_data('t');
write_com(0x80+0x4d);
write_data('y');
write_data('o');
write_data('u');
}
/******************************************
液晶显示器显示欢迎界面模块二
My number is 208110732
******************************************/
void display3()
{
if(flag!=0)
{
write_com(0x06);
switch(flag)
{
case 1: write_com(0x80+0x40+6);
write_com(0x0f);delay(800);break;
case 2: write_com(0x80+0x40+3);
write_com(0x0f);delay(800);break;
case 3: write_com(0x80+0x40+0);
write_com(0x0f);delay(800);break;
case 4: write_com(0x80+13);
write_com(0x0f);delay(800);break;
case 5: write_com(0x80+8);
write_com(0x0f);delay(800);break;
case 6: write_com(0x80+5);
write_com(0x0f);delay(800);break;
case 7: write_com(0x80+2);
write_com(0x0f);delay(800);break;
default:break;
}
}
write_com(0x80+0x02);
write_data(0x4d);
write_data(0x79);
delay(500);
write_com(0x85);
write_data(0x6e);
write_data(0x75);
write_data(0x6d);
write_data(0x62);
write_data(0x65);
write_data(0x72);
delay(500);
write_com(0x8c);
write_data(0x69);
write_data(0x73);
delay(500);
write_data(0x3a);
delay(500);
write_com(0xc3);
write_data(0x32);
delay(50);
write_data(0x30);
delay(50);
write_data(0x38);
delay(50);
write_data(0x31);
delay(50);
write_data(0x31);
delay(50);
write_data(0x30);
delay(50);
write_data(0x37);
delay(50);
write_data(0x33);
delay(50);
write_data(0x32);
delay(50);
}
void display4()
{ write_com(0x82);
write_data(0x4d);
write_data(0x79);
delay(500);
write_com(0x85);
write_data(0x6e);
write_data(0x61);
write_data(0x6d);
write_data(0x65);
delay(500);
write_com(0x8a);
write_data(0x69);
write_data(0x73);
delay(500);
write_data(0x3a);
delay(500);
write_com(0xc1);
write_data('y');
write_data('a');
write_data('n');
write_data('g');
delay(500);
write_com(0xc6);
write_data('j');
write_data('i');
write_data('a');
delay(500);
write_com(0xca);
write_data('j');
write_data('i');
write_data('a');
delay(500);
}
/******************************************
液晶显示器显示时间模块
******************************************/
void display2()
{
if(flag!=0)
{
write_com(0x06);
switch(flag)
{
case 1: write_com(0x80+0x40+6);
write_com(0x0f);delay(800);break;
case 2: write_com(0x80+0x40+3);
write_com(0x0f);delay(800);break;
case 3: write_com(0x80+0x40+0);
write_com(0x0f);delay(800);break;
case 4: write_com(0x80+13);
write_com(0x0f);delay(800);break;
case 5: write_com(0x80+8);
write_com(0x0f);delay(800);break;
case 6: write_com(0x80+5);
write_com(0x0f);delay(800);break;
case 7: write_com(0x80+2);
write_com(0x0f);delay(800);break;
default:break;
}
}
write_com(0x80+0x00);
write_data('D');
write_data(table[10]); //显示“:”
write_com(0x80+0x02);
write_data(table[2]); //显示器上显示年份的2
write_data(table[0]); //显示器上显示年份的0
write_com(0x80+0x04);
write_data(table[year/16]);
write_data(table[year%16]);
write_data(table[11]); //显示“-”
write_data(table[(mon&0x1f)/16]);
write_data(table[(mon&0x1f)%16]);
write_data(table[11]); //显示“-”
write_data(table[(day&0x3f)/16]);
write_data(table[(day&0x3f)%16]);
write_com(0x80+0x0d);
for(num=0;num<3;num++)
{
write_data(table1[(week&0x07)*3+num]);
}
write_com(0x80+0x40);
write_data(table[(hour&0x3f)/16]);
write_data(table[(hour&0x3f)%16]);
write_data(table[10]);
write_data(table[(min&0x7f)/16]);
write_data(table[(min&0x7f)%16]);
write_data(table[10]);
write_data(table[(sec&0x7f)/16]);
write_data(table[(sec&0x7f)%16]);
write_com(0x80+0x49);
write_data(table2[0]);
write_data(table2[1]);
write_data(table2[2]);
write_data(table2[3]);
write_data(table2[4]);
write_data(table2[5]); //显示 “Jiajia”
}
/******************************************
液晶显示器显示闹钟模块
******************************************/
void display7()
{
if(flag!=0)
{
write_com(0x06);
switch(flag)
{
case 1: write_com(0x80+0x40+6);
write_com(0x0f);delay(800);break;
case 2: write_com(0x80+0x40+3);
write_com(0x0f);delay(800);break;
case 3: write_com(0x80+0x40+0);
write_com(0x0f);delay(800);break;
case 4: write_com(0x80+13);
write_com(0x0f);delay(800);break;
case 5: write_com(0x80+8);
write_com(0x0f);delay(800);break;
case 6: write_com(0x80+5);
write_com(0x0f);delay(800);break;
case 7: write_com(0x80+2);
write_com(0x0f);delay(800);break;
default:break;
}
}
write_com(0x80+0x01);
write_data('C');
write_data('L');
write_data('O');
write_data('C');
write_data('K');
write_data(table[10]);
write_com(0x80+0x45);
write_data(table[(hour2&0x3f)/9]);
write_data(table[(hour2&0x3f)%9]);
write_data(table[10]);
write_data(table[(min2&0x7f)/9]);
write_data(table[(min2&0x7f)%9]);
write_data(table[10]);
write_data(table[(sec2&0x7f)/10]);
write_data(table[(sec2&0x7f)%9]);
}
/******************************************
清屏模块
******************************************/
void LCMclear(void)
{
delay(100);
lcden=0;
lcdrs=0;
rw=0;
P0=0x01;
lcden=1;
_nop_();
_nop_();
lcden=0;
delay(100);
}
/******************************************
定时打铃模块
******************************************/
void ring()
{
flag1=0; //是,则标志位,flag1清零
while(!(flag1==15)) //判断flag1是否到15
{
beep=0; //没有,则,继续驱动蜂鸣器响,时间约为:5s
display2(); //调用显示子函数
flag1++;
}
beep=1; //关闭蜂鸣器
}
/******************************************
闹铃模块
******************************************/
void clock()
{
if(sec2==sec) //显判断秒的数值是否相等
if(min2==min) //是,在判断分是否相等
if(hour2==hour) //是,再判断时是否相等
ring();
}
/******************************************
整点报时模块
******************************************/
void baoshi()
{
if(min==0&&sec<6)
{
beep=0;
delay(500);
beep=1;
}
}
/******************************************
上下课时间打铃模块
******************************************/
void clock2() //
{
if((sec==0x00)&&(min==0x15)&&(hour==0x07)) ring();
else if((sec==0x00)&&(min==0x00)&&(hour==0x08)) ring();
else if((sec==0x00)&&(min==0x45)&&(hour==0x08)) ring();
else if((sec==0x00)&&(min==0x55)&&(hour==0x08)) ring();
else if((sec==0x30)&&(min==0x00)&&(hour==0x09)) ring();
else if((sec==0x00)&&(min==0x01)&&(hour==0x0a)) ring();
else if((sec==0x00)&&(min==0x55)&&(hour==0x0a)) ring();
else if((sec==0x00)&&(min==0x05)&&(hour==0x0b)) ring();
else if((sec==0x00)&&(min==0x50)&&(hour==0x0b)) ring();
else if((sec==0x00)&&(min==0x40)&&(hour==0x0d)) ring();
else if((sec==0x00)&&(min==0x25)&&(hour==0x0c)) ring();
else if((sec==0x00)&&(min==0x35)&&(hour==0x0c)) ring();
}
/******************************************
按键模块
******************************************/
void test_keyboard1()
{
uchar ScanCode,Line,Col,i,Mask,key;
P2 = 0xff;
Line = 1;
Mask = 0x01;
for(i = 0;i<4;i++)
{
Col = 0;
P2 = ~Mask;
ScanCode = P2 & 0xf0;
if(ScanCode != 0xf0)
{
delay(20);
}
ScanCode = P2 & 0xf0;
switch(ScanCode)
{
case 0xe0: key = (Line-1)*4;
break;
case 0xd0: key = 1+(Line-1)*4;
break;
case 0xb0: key = 2+(Line-1)*4;
break;
case 0x70: key = 3+(Line-1)*4;
break;
default:
break;
}
Mask <<=1;
Line ++;
}
switch(key) //输出矩阵按键所对应的数值
{
case 0:write_com(0x80+0x04); year++;
break;
case 1: write_com(0x80+0x04);mon++;
break;
case 2: day++;
break;
case 3: hour++;
break;
case 4: min++;
break;
case 5: sec++;
break;
case 6: hour2++;
break;
case 7: min2++;
break;
case 8: sec2++;
break;
}
switch((int)change ) //切换显示屏
{
case 1:display2();
break;
case 0:display7();
break;
}
}
/******************************************
主函数
******************************************/
void main()
{
init(); //初始化
display1(); //显示欢迎界面
delay(1000);
delay(1000);
delay(1000);
LCMclear(); //清屏
display4(); //显示姓名yangjiajia
delay(1000);
delay(1000);
delay(1000);
LCMclear(); //清屏
display3(); //显示学号208110732
delay(1000);
delay(1000);
delay(1000);
LCMclear() //清屏;
while(1)
{
switch((int)change)
{
case 0:
test_keyboard1(); //按键检测子函数
clock2(); //打铃子函数
baoshi(); //报时子函数
break;
case 1:
test_keyboard1(); //按键检测子函数
read8563(); //读取时间子函数
clock(); //闹钟子函数
clock2(); //打铃子函数
baoshi(); //报时子函数
}
}
}