[请输入学校名称]
[请输入专业]
基于单片机的GPS时间校准设计
姓 名: [请输入姓名] 学 号: [请输入学号] 指导教师:[请输入指导教师]
ﻩ
--
--
2:55 AM
摘 要:ﻩ2 Abstractﻩ4 第一章 概述5ﻩ
1.1实时时钟研究的背景及意义 ........................................................................................ 5 1.2论文主要研究内容ﻩ错误!未定义书签。
1.2.1 系统设计实现的目标ﻩ错误!未定义书签。 1.2.2 系统的总体设计5ﻩ
第二章 硬件电路设计 ................................................................................................................... 7
2.1单片机控制部分ﻩ7
2.2 DS1302时钟芯片部分10ﻩ
2.3 LCD1602液晶显示部分......................................................................................... 12
2.5.2 1602引脚功能说明 ...................................................................................... 12 2.5.3 1602LCD的指令说明及时序13ﻩ
2.5.4 1602LCD的RAM地址映射及标准字库表 .................................................... 14 2.5.5 1602LCD的一般初始化(复位)过程16ﻩ
--
--
2
.4.6 1602LCD的电路连接16ﻩ
2.4 GPS模块VK2828U7G5LF部分 ............................................................................... 17 第三章 软件部分设计 ................................................................................................................. 21
3.1 按键程序流程图 ............................................................................. 错误!未定义书签。 结束语 ............................................................................................................................................ 30 致谢词ﻩ31
参考文献....................................................................................................................................... 32 附录 .............................................................................................................................................. 33
硬件原理图与PCB图ﻩ错误!未定义书签。
源程序: ................................................................................................................................... 35
--
--
摘 要:
本文介绍了基于STC89C52单片机的多功能电子万年历的硬件结构和软硬件设计方法。本设计由数据显示模块、GPS模块、时间处理模块和按键输入模块四个模块组成。系统以STCC52单片机为控制器,以DS1302时钟日历芯片DS1302记录日历和时间,它可以对年、月、日、时、分、秒进行计时,还具有闰年补偿等多种功能。GPS模块采用了VK2828U7G5LF,万年历采用直观的数字显示,数据显示采用1602液晶显示模块,可以在LCD1602上同时显示年、月、日、周日、时、分、秒,和GPS模块的工作模式。此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,具有广阔的市场前景。
关键字:单片机,时钟芯片, 温度传感器, 1602液晶显示器
--
--
Abstract
ﻫ This paper introduces the hardware structure of the electronic calendar based on STC89C52 single-chip microcomputer and the hardware and software design method.This design by the dSTCa display module, GPS module, time processing module and key input module of four modules.System with STCC52 single-chip microcomputer as the controller, with DS1302 clock chip DS1302 calendar calendar and time, it can be for years, months, days, hours, minutes, seconds time, also has a leap year compensSTCion and other.
Key words: single chip, the clock chip, temperSTCure sensor, 1602 liquid crystal display
--
--
--
--
第一章 概述
1.1实时时钟研究的背景及意义
在现实我们生活中每个人都可能有自己的时钟,光阴在永不停息的流逝,有了时钟人们就能随着时间有计划的过着每一天。然而现在绝大部分的时钟有的需要不断地跟换电池,有些时钟需要外接电源,如果一旦电池没电或者外接电源无法供电,时钟就会停止计时了。而美国DALLAS 公司的新型时钟日历芯片DS1302就能解决这一问题。该器件能提供实时时钟(RTC)/日历、定时闹钟。少于31天的月份,月末日期可自动调整,其中包括闰年补偿。该器件还可以工作于24小时货代/PM指示的12小时格式。一个精密的温度补偿电路用来监视Vcc的状态。还有就是一旦时间数据出现错误,我们总是手动的进行调整时间数据,比较麻烦,那么,一款不用手动调整,自动校准的实时时钟势必在行。
本时钟还具有环保、走时无噪音、低功耗等非实时时钟不具有的功能。该实时时钟不但可以作为家用,而且更可以在公共场合使用,如车站、码头、商场等场所。
1.2论文主要研究内容
1.2.1 系统设计实现的目标
本文是以实时时钟芯片DS1302和STCC52单片机为主要研究对象,着重进行51单片机控制系统的设计研究和如何读取DS1302内部时钟信息的研究。以及运用GPS模块进行时间数据与卫星的自动同步。主要内容包括: 1.年月日星期时分秒显示; 2.手动年月日星期时分秒调整; 3.自动年月日星期时分秒调整;
1.2.2 系统的总体设计
采用STC89C52作为主控单片机,时钟模块选用DS1302作为时钟芯片,温度模块选用DS18B20作为温度传感器,显示模块选用LCD1602,设置部分选用按键电路。
STC89C52与MCS-51单片机产品兼容 、8K字节在系统可编程Flash存储器、 1000次擦写周期、 全静态操作:0Hz~33Hz 、 三级加密程序存储器 、 32个可编程I/O口线 、
--
--
三个16位定时器/计数器 八个中断源 、全双工UART串行通道、 低功耗空闲和掉电模式 、掉电后中断可唤醒 、看门狗定时器 、双数据指针 、掉电标识符 。
DS1302 实时时钟芯片功能丰富,可以用来直接代替IBM PC 上的时钟日历芯片DS12887,同时,它的管脚也和MC146818B、DS12887 相兼容。由于DS1302 能够自动产生世纪、年、月、日、时、分、秒等时间信息,其内部又增加了世纪寄存器,从而利用硬件电路解决子“千年”问题;DS1302 中自带有锂电池,外部掉电时,其内部时间信息还能够保持10 年之久;对于一天内的时间记录,有12 小时制和24 小时制两种模式。用户还可对DS1302 进行编程以实现多种方波输出,并可对其内部的三路中断通过软件进行屏蔽。
GPS模块就是集成了RF射频芯片、基带芯片和核心CPU,并加上相关外围电路而组成的一个集成电路。目前GPS模块的GPS芯片大部分还是采用全球市占率第一的SiRFIII系列为主。由于GPS模块采用的芯片组不一样,性能和价格也有区别,采用SIRF三代芯片组的GPS模块性能最优,价格也要比采用MTK或者MSTAR等GPS芯片组的贵很多。 ﻩ
第二章 硬件电路设计
本次设计主要有单片机主控部分、DS1302时钟芯片部分、LCD1602液晶显示部分、GPS模块、按键输入部分。整体硬件框图如下:
GPS模块LCD1602液晶显示单片机按键输入DS1320时钟芯片
本系统以STC89C52单片机为核心,本系统选用11.0592MHZ的晶振,,使得单片机
--
--
有合理的运行速度。起振电容30pF对振荡器的频率高低、振荡器的稳定性和起振的快速性影响较合适,复位电路为按键高电平复位。
下面简单的介绍一下单片机控制部分、DS1302部分、LCD1602部分以及GPS模块。
2.1单片机控制部分
STC89C52是一个低功耗,高性能CMOS 8位单片机,片内含8k BytesISP(In-system programmable)的可反复擦写1000次的Flash只读程序存储器,器件采用STC公司的高密度、非易失性存储技术制造,兼容标准 MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位处理器和ISP Flash存储单元,功能强大的微型计算机的STC89C52可为许多嵌入式控制应用系统提供高性价比的解决方案。STCC52具有如下特点:40个引脚,8k Bytes Flash片内程序存储器,256 bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,片内时钟振荡器。
另外,STCC52可降至0Hz静态逻 辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
STCC52共有四个8位的并行I/O口:P0、P1、P2、P3端口,对应的引脚分别是P0.0 ~ P0.7,P1.0 ~ P1.7,P2.0 ~ P2.7,P3.0 ~ P3.7,共32根I/O线。每根线可以单独用作输入或输出。
P0 口:P0口是一个8位漏极开路的双向I/O口。作为输出口,每位能驱动8个TTL逻 辑电平。对P0端口写“1”时,引脚用作高阻抗输入。当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。在这种模式下,P0不具有内部上拉电阻。在flash编程时,P0口也用来接收指令字节;在程序校验时,输出指令字节。程序校验时,需要外部上拉电阻。
P1 口:P1口是一个具有内部上拉电阻的8 位双向I/O口,p1输出缓冲器能驱动4 个TTL逻辑电平。对P1 端口写“1”时,内部上拉电阻把端口拉
--
--
高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。此外,P1.0和P1.1分别作定时器/计数器2的外部计数输入(P1.0/T2)和定时器/计数器2的触发输入(P1.1/T2EX)。在flash编程和校验时,P1口接收低8位地址字节。此外,P1.0和P1.1分别作定时器/计数器2的外部计数输入(P1.0/T2)和定时器/计数器2 的触发输入(P1.1/T2EX)。
P2口:P2口是一个具有内部上拉电阻的8位双向I/O口,P2输出缓冲器能驱动4个TTL逻辑电平。对P2 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流(IIL)。在访问外部程序存储器或用16位地址读取外部数据存储器时,P2口送出高八位地址。在这种应用中,P2口使用很强的内部上拉发送1。在使用8位地址访问外部数据存储器时,P2口输出P2锁存器的内容。在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。
P3 口:P3口是一个具有内部上拉电阻的8位双向I/O口,p3 输出缓冲器能驱动4 个 TTL逻辑电平。对P3 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。P3口亦作为STC89C52特殊功能使用,在flash编程和校验时,P3口也接收一些控制信号。 单片机的引脚图如图3.3所示。
--
--
图3.3 STCC52单片机引脚图
单片机最小系统,是指用最少的元件与单片机组成的可以工作的系统。对52单片机来说,最小系统一般应该包括:单片机、晶振电路、复位电路。单片机接口电路主要用来连接计算机和其他外部设备,各功能模块及原理如下:
复位电路:单片机最小系统复位电路的极性电容C3的大小直接影响单片机的复位时间,一般采用10-30μF,51单片机最小系统容值越大需要的复位时间越短。单片机工作之后,只要在RST引线上加载10ms以上的高电平,单片机就能有效地复位。CS-51单片机通常采用自动复位和按键复位两种方式。这里采用按键复位和上电复位两种电路结合。
晶振电路:典型的晶振取11.0592MHZ或者12MHZ,晶振越大,则单片机的处理速度越快,考虑到本次设计的通信问题,采用了11.0592MHZ晶振。单片机的最小起振电容C1,C2一般采用15-33pF,并且电容离晶振越近越好。单片机最小系统的设计电路如图3.4所示。
--
--
图3.4 单片机最小系统的设计电路
2.2 DS1302时钟芯片部分
DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后背电源双电源引脚,同时提供了对后背电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST
--
--
是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),。SCLK始终是输入端。 DS1302的引脚图如图5.4所示:
图5.4 DS1302引脚图
调试中问题说明:
DS1302 与微处理器进行数据交换时,首先由微处理器向电路发送命令字节,命令字节最高位MSB(D7)必须为逻辑1,如果D7=0,则禁止写DS1302,即写保护;D6=0,指定时钟数据,D6=1,指定RAM数据;D5~D1指定输入或输出的特定寄存器;最低位LSB(D0)为逻辑0,指定写操作(输入), D0=1,指定读操作(输出)。
在DS1302的时钟日历或RAM进行数据传送时,DS1302必须首先发送命令字节。若进行单字节传送,8位命令字节传送结束之后,在下2个SCLK周期的上升沿输入数据字节,或在下8个SCLK周期的下降沿输出数据字节。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;再一类为突发方式下的RAM寄存器,在此方式下可一次性读、写所有的RAM的31个字节。
--
--
要特别说明的是备用电源B1,可以用电池或者超级电容器(0.1F以上)。虽然DS1302在主电源掉电后的耗电很小,但是,如果要长时间保证时钟正常,最好选用小型充电电池。可以用老式电脑主板上的3.6V充电电池。如果断电时间较短(几小时或几天)时,就可以用漏电较小的普通电解电容器代替。100 μF就可以保证1小时的正常走时。DS1302在第一次加电后,必须进行初始化操作。初始化后就可以按正常方法调整时间。原理图如图3-9所示:
2.3 LCD1602液晶显示部分
字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,本设计采用16列*2行的字符型LCD1602带背光的液晶显示屏。 1602LCD主要技术参数: 1. 显示容量:16×2个字符 2. 芯片工作电压:4.5—5.5V 3. 工作电流:2.0mA(5.0V) 4. 模块最佳工作电压:5.0V
5. 字符尺寸:2.95×4.35(W×H)mm
2.3.2 1602引脚功能说明
--
--
各引脚接口说明如表所示:
表2-1
编号 1 2 3 4 5 6 7 8
符号 VSS VDD VL RS R/W E D0 D1
引脚说明 电源地 电源正极 液晶显示偏压 数据/命令选择 读/写选择 使能信号 数据 数据
10 11 12 13 14 15 16 编号
9
符号 D2 D3 D4 D5 D6 D7 BLA BLK
引脚说明 数据 数据 数据 数据 数据 数据 背光源正极 背光源负极
表2-1:引脚接口说明: 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。 第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。
2.3.3 1602LCD的指令说明及时序
--
--
1602液晶模块内部的控制器共有11条控制指令,如表2-2所示:
表2-2
序号 1 2 3 4 5 6 7 8 9 10 11
指令 清显示 光标返回 置输入模式 显示开/关控制 光标或字符移位 置功能
置字符发生存贮器地址 置数据存贮器地址 读忙标志或地址
RS 0 0 0 0 0 0 0 0 0
R/W D7 D6 0 0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 1 BF
0 0 0 0 0 0 1
D5 D4 0 0 0 0 0 1
0 0 0 0 1 DL
D3 D2 0 0 0 1
0 0 1 D
D1 D0 0 1
1 *
I/D S C * *
B * *
S/C R/L N
F
字符发生存贮器地址
显示数据存贮器地址 计数器地址
写数到CGRAM或DDRAM) 1 从CGRAM或DDRAM读数
1
要写的数据内容 读出的数据内容
表2-2字符控制命令说明:
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)
指令1:清显示,指令码01H,光标复位到地址00H位置。 指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有
文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示
C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行
显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x
--
--
10的点阵字符。
指令7:字符发生器RAM地址设置。 指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者
数据,如果为低电平表示不忙。
指令10:写数据。 指令11:读数据。 芯片时序表如下:
读状态 写指令 读数据 写数据
输入 输入 输入 输入
RS=L,R/W=H,E=H
RS=L,R/W=L,D0—D7=指令码,E=高脉冲 RS=H,R/W=H,E=H
RS=H,R/W=L,D0—D7=数据,E=高脉冲
表2-3
输出 输出 输出 输出
D0—D7=状态字 无
D0—D7=数据 无
基本操作时序表
读写操作时序如图2-7和2-8所示:
图2-7读操作时序
--
--
图2-8 写操作时序
2.3.4 1602LCD的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图2-9是1602的内部显示地址。
图2-9液晶内部显示地址
例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。 在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如图
--
--
10-58所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
图2-10 字符代码与图形对应图
2.3.5 1602LCD的一般初始化(复位)过程
1. 延时15mS
4. 写指令38H(不检测忙信号) 5. 延时5mS
8. 写指令38H(不检测忙信号) 9. 延时5mS
13. 写指令38H(不检测忙信号)以后每次写指令、读/写数据操作均需要检测忙信号 15. 写指令38H:显示模式设置
--
--
17. 写指令08H:显示关闭 19. 写指令01H:显示清屏
22. 写指令06H:显示光标移动设置 25. 写指令0CH:显示开及光标设置
2.3.6 1602LCD的电路连接
图2-11 1602的电路连接
2.4 GPS模块VK2828U7G5LF部分
GPS模块就是集成了RF射频芯片、基带芯片和核心CPU,并加上相关外围电路而组成
的一个集成电路。在本次设计采用了设计要求的VK2828U7G5LF模块,这个模块主芯片是UBX-G7020-KT,通过串口通信与单片机相连接,当使他工作的时候,就会开始定位,
--
--
并将数据通过串口送给单片机,数据遵守NMEA0183协议,里面有时间、位置、地面速度信息等,我们可以直接对送过来的数据进行解读,就可以获取我们所先要的时间信息。
1.正常工作条件:
2.RF射频属性:
3.NMEA0183协议 NMEA 0183 输出
GGA:时间、位置、定位类型 GLL:经度、纬度、 UTC 时间
GSA:GPS 接收机操作模式,定位使用癿卫星,DOP 值
--
--
GSV:可见 GPS 卫星信息、仰角、方位角、信噪比(SNR) RMC:时间、日期、位置、速度 VTG:地面速度信息 MSS:信号强度等
注意:输出癿信息、频率不设置有关 样例数据:
$GPGGA,060826.00,2236.91284,N,11403.24705,E,2,08,1.03,107.8,M,-2.4,M,,0000*4A
$GPGSA,A,3,24,22,14,12,15,25,18,42,,,,,2.20,1.03,1.95*01
$GPGSV,3,1,11,12,31,117,47,14,30,290,46,15,19,060,42,18,70,010,45*78
$GPGSV,3,2,11,21,47,207,,22,40,326,43,24,44,036,43,25,24,159,42*70
$GPGSV,3,3,11,31,03,218,,42,51,128,35,50,46,122,45*4E $GPGLL,2236.91284,N,11403.24705,E,060826.00,A,D*66
$GPRMC,060827.00,A,2236.91267,N,11403.24701,E,0.001,,130214,,,D*79
$GPVTG,,T,,M,0.029,N,0.0,K,D*2C 4.样例数据详解
GGA样例数据:ﻫ$GPGGA,060826.00,2236.91284,N,11403.24705,E,2,08,1.03,107.8,M,-2.4,M,,0000*4A
序号 0 1 名称 消息ID UTC时间 样例 $GPGGA 060826.00 单位 描述 GGA协议头 hhmmss.ss 2 纬度 2236.9128--
ddmm.mmmmm -- 4 3 4 5 6 N/S指示 经度 E/W指示 定位指示 N 11403.24705 E 2 N=北,S=南 dddmm.mmmmm W=西,E=东 0:未定位1:SPS模式,定位有效 2:差分,SPS模式,定位有效3:PPS模式,定位有效 7 8 9 卫星数目 HDOP MSL 08 1.03 幅度107.8 范围0到12 水平精度 平均海平面高度 米 10 11 12 13 单位 大地 单位 差分时间 M -2.4 M 米 米 单位:米 平均海平面 单位:米 当没有DGPS时,无效 秒 14 差分ID 0000 当没有DGPS时,无效 15 校验和 *4A $不*之间所有字符ASCII码癿校验和 16 -- GSA样例数据:ﻫ$GPGSA,A,3,24,22,14,12,15,25,18,42,,,,,2.20,1.03,1.95*01 序号 0 1 名称 消息ID 模式1 样例 $GPGSA A 单位 描述 GSA协议头 M=手劢(强制操作在2D或3D模式),A=自动 2 模式2 3 1:定位无效2:2D定位3:3D定位 3 4 5 6 7 8 9 10 11 12 13 14 15 16 卫星使用 卫星使用 卫星使用 卫星使用 卫星使用 卫星使用 卫星使用 卫星使用 ,,, 卫星使用 PDOP HDOP VDOP 校验和 24 22 14 12 15 25 18 42 ,,, 2.20 1.03 1.95 *01 ,,, 通道1 通道2 通道3 通道4 通道5 通道6 通道7 通道8 ,,, 通道12 位置精度 水平精度 垂直精度 $不*之间所有-- -- 字符ASCII码癿校验和 17 GSV 样例数据: $GPGSV,3,1,11,12,31,117,47,14,30,290,46,15,19,060,42,18,70,010,45*78 $GPGSV,3,2,11,21,47,207,,22,40,326,43,24,44,036,43,25,24,159,42*70 $GPGSV,3,3,11,31,03,218,,42,51,128,35,50,46,122,45*4E 序号 0 1 2 3 4 5 名称 消息ID 消息数目 消息编号 卫星数目 卫星ID 仰角 样例 $GPGSV 3 1 11 12 31 单位 度 描述 GSV协议头 范围1到3 范围1到3 卫星的数目 卫星ID 仰角(范围0°到90°) 6 方位角 117 度 方位角(范围0°到359°) 7 载噪比(C/No) 47 dBHz 信号强度(范围0到99)没有跟踪时为空 8 9 卫星ID 仰角 14 30 度 卫星ID 仰角(范围0°到90°) 10 方位角 290 度 方位角(范围0°<CR> -- 到359°) 11 载噪比(C/No) 46 dBHz 信号强度(范围0到99)没有跟踪时为空 12 13 卫星ID 仰角 15 19 度 卫星ID 仰角(范围0°到90°) 14 方位角 060 度 方位角(范围0°到359°) 15 载噪比(C/No) 42 dBHz 信号强度(范围0到99)没有跟踪时为空 16 17 ,,, 校验和 ,,, *78 ,,, ,,, $不*之间所有字符ASCII码癿校验和 18 GLL样例数据:$GPGLL,2236.91284,N,11403.24705,E,060826.00,A,D*66 序号 0 1 名称 消息ID 纬度 样例 $GPGLL 2236.91284 单位 描述 GLL协议头 ddmm.mmmm 2 3 N/S指示 经度 N 11403.24705 N=北,S=南 dddmm.mmmm 4 E/W指示 E W=西,E=东 m<CR> -- 5 6 UTC位置 状态 060826.00 A hhmm.mmmm A=数据有效;V=数据无效 7 模式指示 D A=自主定位,D=差分,E=估算,N=数据无效 8 校验和 *18 $不*之间所有字符ASCII码癿校验和 9 <CR><LF> 消息结束 RMC样例数据: $GPRMC,060827.00,A,2236.91267,N,11403.24701,E,0.001,,130214,,,D*79 序号 0 1 2 名称 消息ID UTC时间 状态 样例 $GPRMC 060827.00 A 单位 描述 RMC协议头 hhmmss.ss A=数据有效;V=数据无效 3 纬度 2236.91267 ddm.mmmmm m4 5 N/S指示 经度 N 11403.24701 N=北,S=南 dddmm.mmmmm 6 7 8 E/W指示 地面速度 方位 E 0.001 Knot(节) 度 W=西,E=东 地面速度 地面航线 -- -- 9 日期 130214 日,月,年癿格式日期 10 磁变量 磁场变化值(空白-丌支持) 11 模式指示 D A=自主定位,D=差分,E=估算,N=数据无效 12 校验和 *79 $不*之间所有字符ASCII码癿校验和 13 序号 0 1 2 3 名称 消息ID 方位 参考 参考 样例 $GPVTG T 单位 度 - 描述 VTG协议头 地面航线 真北 地面航线(磁癿),丌输出 4 5 6 7 8 9 参考 速度 单位 速度 单位 模式指示 M 0.029 N 0.001 K D Knots(节) 公里/小时 磁 地面速度 固定字节 地面速度 公里/小时 A=自主定位,D=差分,E=估算,-- -- N=数据无效 10 校验和 *2C $不*之间所有字符ASCII码癿校验和 11 <CR><LF> 消息结束 ﻬ 第三章 软件部分设计 本系统主要包括五个模块编程: 1.时钟芯片DS1302的编程 2.液晶显示屏1602的编程 3.按键编程 4.GPS模块的编程 首先单片机初始化读取DS1302里面的时钟信息,将其显示到LCD1602上,然后通过按键模块部分,一方面可以手动调整DS1302里面的时钟信息。另一方面可以手动控制GPS模块的工作与不工作。整体程序流程图如下: -- -- 开始初始化按键输入数据处理LCD1602显示结束 3.1 按键程序流程图 按键一共分为两大块,一块用来手动设置DS1302的时间信息,一块就是用来控制GPS模块的工作状态。 一共有四个按键,前三个按键用来控制时间信息,第一个按键是进入设置界面的按键,并且在进入设置界面之后再次按下就是切换所选中的数据,当按下7次时,退出设置界面。第二、三个按键是用来对选中的数据在设置界面分别进行加减。第四个按键就是来控制GPS模块的工作状态的,每一次按下都会改变GPS的工作状态。另外额外增加了,每一次按键有效按下时,蜂鸣器短响提示。 -- -- 开始YKey1是否按下进入设置界面,选中一位数据,每按一次切换选中一位数据。按7次,退出设置界面NYKey2是否按下在设置界面,对选中数据进行数据加NKey3是否按下Y在设置界面,对选中数据进行数据加NKey4是否按下改变GPS模块工作状态N结束 程序如下: //****************键盘扫描有关函数********************** void keyscan() { if(set==0)//---------------set为功能键(设置键)-------------------- { ﻩﻩdelay(9);//延时,用于消抖动 ﻩﻩif(set==0)//延时后再次确认按键按下 ﻩ { buzz=0;//蜂鸣器短响一次 delay(200); -- -- ﻩ buzz=1; ﻩﻩ setn++; ﻩﻩﻩif(setn>=7) ﻩ ﻩsetn=0; ﻩﻩ//设置按键共有秒、分、时、日、月、年、返回,7个功能循环 ﻩﻩﻩ{ ﻩ ﻩﻩ ﻩcase 1: TR0=0;//关闭定时器 ES=0; switch(setn) ﻩ ﻩﻩ//TR1=0; ﻩﻩ write_1602com(er+8);//设置按键按动一次,秒位置显示光标 //er+0x09; ﻩﻩ write_1602com(0x0f);//设置光标为闪烁 // ﻩ temp=(miao)/10*16+(miao)%10;//秒数据写入DS1302 ﻩﻩ ﻩ write_1302(0x8e,0x00); //ﻩ ﻩwrite_1302(0x80,0x80|temp);//miao ﻩ ﻩ write_1302(0x8e,0x80); ﻩ ﻩ break; ﻩﻩ case 2: ﻩ ﻩwrite_1602com(er+5); //按2次fen位置显示光标 //er+0x06ﻩ ﻩ ﻩ //write_1602com(0x0f); break; ﻩﻩ case 3: ﻩwrite_1602com(er+2); //按动3次,shi -- -- ﻩ ﻩ //write_1602com(0x0f); break; ﻩ ﻩ//ﻩcase 4: write_1602com(yh+0x0e);//按动4次,week ﻩ //write_1602com(0x0f); ﻩ ﻩ// break; ﻩﻩ case 4: write_1602com(yh+0x0a);//按动4次,ri ﻩ //write_1602com(0x0f); ﻩﻩbreak; ﻩﻩ ﻩcase 5: write_1602com(yh+0x07);//按动5次,yue ﻩﻩﻩ //write_1602com(0x0f); ﻩ ﻩﻩbreak; ﻩﻩ ﻩcase 6: write_1602com(yh+0x04);//按动6次,nian ﻩ ﻩ //write_1602com(0x0f); ﻩ ﻩ ﻩ ﻩ ﻩﻩ ﻩ break; case 0: ﻩﻩwrite_1602com(0x0c);//按动到第7次,设置光标不闪烁 ES=1; TR0=1;//打开定时器 ﻩ temp=(miao)/10*16+(miao)%10; ﻩ write_1302(0x8e,0x00); ﻩﻩ ﻩ write_1302(0x80,0x00|temp);//miao数据写入DS1302 ﻩ ﻩﻩwrite_1302(0x8e,0x80); ﻩ } -- break;ﻩ -- ﻩﻩﻩwhile(!set); ﻩ } } //------------------------------加键add----------------------------ﻩﻩ if(setn!=0)//当set按下以下。再按以下键才有效(按键次数不等于零) ﻩ{ ﻩif(add==0) //上调键 ﻩ { delay(10); ﻩﻩ if(add==0) ﻩ ﻩ{ ﻩﻩbuzz=0;//蜂鸣器短响一次 ﻩﻩdelay(200); ﻩ ﻩ buzz=1; ﻩ ﻩﻩﻩ { ﻩﻩ ﻩ ﻩﻩﻩﻩﻩﻩ 的秒数 ﻩ case 1:miao++;//设置键按动1次,调秒 if(miao>=60) miao=0;//秒超过59,再加1,就归零 ﻩswitch(setn) ﻩﻩﻩﻩ write_sfm(0x07,miao);//令LCD在正确位置显示\"加\"设定好 ﻩ ﻩ ﻩ temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码 ﻩ 护 -- ﻩ ﻩwrite_1302(0x8e,0x00); //允许写,禁止写保 -- ﻩﻩﻩ ﻩ ﻩwrite_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码 ﻩ ﻩ write_1302(0x8e,0x80); //打开写保护 ﻩ ﻩ ﻩwrite_1602com(er+8);//因为设置液晶的模式是写入数据后,光标自动右移,所以要指定返回 ﻩﻩ ﻩﻩ ﻩ ﻩﻩ ﻩ ﻩ //write_1602com(0x0b); ﻩﻩ break; ﻩﻩcase 2:fen++; ﻩ ﻩif(fen>=60) fen=0; ﻩﻩﻩ ﻩ 的分数据 write_sfm(0x04,fen);//令LCD在正确位置显示\"加\"设定好 ﻩ ﻩﻩﻩﻩﻩtemp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩﻩﻩ ﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩ ﻩﻩﻩ write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码 ﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩﻩﻩﻩﻩﻩwrite_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 ﻩ ﻩ ﻩbreak; ﻩﻩ ﻩﻩcase 3:shi++; ﻩﻩﻩﻩﻩﻩﻩif(shi>=24) ﻩﻩﻩﻩ ﻩshi=0; ﻩ ﻩwrite_sfm(0x01,shi);//令LCD在正确的位置显示\"加\"设定好的小时数据 ﻩﻩ ﻩ ﻩﻩtemp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码 -- -- ﻩ 护 ﻩﻩ ﻩwrite_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码 ﻩ ﻩ ﻩ write_1302(0x8e,0x80);//打开写保护 ﻩﻩ write_1302(0x8e,0x00);//允许写,禁止写保 ﻩ ﻩﻩﻩ write_1602com(er+2);//因为设置液晶的模式是写入数据 后,指针自动加一,所以需要光标回位 ﻩﻩ ﻩ ﻩﻩ ﻩﻩ ﻩ ﻩ ﻩ ﻩ ﻩbreak; case 4:ri++; ﻩ if(ri>=32) ﻩﻩ ri=1; ﻩConver_week(nian,yue,ri); ﻩﻩwrite_week(week); write_nyr(9,ri);//令LCD在正确的位置显示"加\" ﻩ ﻩ 设定好的日期数据 ﻩ ﻩﻩ ﻩtemp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩ ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ ﻩ write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入调整后的日期数据BCD码 ﻩﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩ ﻩ write_1602com(yh+10);//因为设置液晶的模式 是写入数据后,指针自动加一,所以需要光标回位 ﻩ ﻩ ﻩ ﻩ break; ﻩﻩcase 5:yue++; if(yue>=13) -- ﻩﻩ ﻩ -- ﻩﻩﻩﻩﻩﻩﻩyue=1; ﻩﻩ ﻩConver_week(nian,yue,ri); ﻩﻩﻩ ﻩwrite_week(week); ﻩﻩ ﻩ write_nyr(6,yue);//令LCD在正确的位置显示\"加\"设定好的月份数据 ﻩﻩﻩﻩ temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩ ﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩ ﻩﻩ ﻩwrite_1302(0x88,temp);//向DS1302内写月 份寄存器88H写入调整后的月份数据BCD码 ﻩﻩﻩﻩﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩ ﻩwrite_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 ﻩ ﻩ ﻩ ﻩ break; ﻩcase 6:nian++; if(nian>=100) ﻩﻩﻩﻩﻩ nian=0; ﻩﻩﻩ ﻩﻩConver_week(nian,yue,ri); ﻩ ﻩﻩﻩﻩﻩwrite_week(week); ﻩ ﻩ ﻩ 好的年份数据 write_nyr(3,nian);//令LCD在正确的位置显示\"加\"设定 ﻩ temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码 止写保护 write_1302(0x8e,0x00);//允许写,禁 ﻩﻩ ﻩwrite_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码 -- -- ﻩ write_1302(0x8e,0x80);//打开写保护 ﻩ ﻩwrite_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 ﻩ ﻩ ﻩ ﻩ ﻩ ﻩ} ﻩ//------------------减键dec,各句功能参照'加键'注释--------------- ﻩif(dec==0) { ﻩ ﻩ ﻩﻩ} while(!add); } break; ﻩﻩdelay(10);//调延时,消抖动 ﻩ ﻩ ﻩﻩ if(dec==0) { buzz=0;//蜂鸣器短响一次 delay(200); ﻩ ﻩﻩ buzz=1; ﻩ ﻩﻩswitch(setn) ﻩﻩ ﻩ{ ﻩﻩﻩﻩﻩcase 1: ﻩ ﻩﻩmiao--; if(miao<0) ﻩﻩﻩ ﻩﻩﻩ ﻩﻩmiao=59;//秒数据减到-1时自动变成59 -- -- ﻩ 改变后新的秒数 ﻩwrite_sfm(0x07,miao);//在LCD的正确位置显示 ﻩ temp=(miao)/10*16+(miao)%10;//十进制 转换成DS1302要求的DCB码 保护 ﻩ write_1302(0x8e,0x00); //允许写,禁止写 ﻩﻩ ﻩﻩ ﻩwrite_1302(0x80,temp); //向DS1302内写秒寄存 器80H写入调整后的秒数据BCD码 ﻩ ﻩwrite_1302(0x8e,0x80); //打开写保护 ﻩﻩﻩwrite_1602com(er+8);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 ﻩ ﻩﻩﻩ ﻩ ﻩﻩ//write_1602com(0x0b); break; ﻩﻩﻩﻩcase 2: ﻩ ﻩ ﻩ ﻩ ﻩﻩﻩ fen--; if(fen<0) ﻩﻩ ﻩfen=59; ﻩ write_sfm(4,fen); ﻩ ﻩtemp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码 ﻩ ﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ ﻩ ﻩwrite_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码 ﻩﻩ ﻩﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 ﻩﻩ ﻩwrite_1602com(er+5);//因为设置液晶的模式是写入数 据后,指针自动加一,在这里是写回原来的位置 ﻩ -- ﻩ break; -- ﻩ ﻩ ﻩ ﻩ ﻩ case 3: ﻩﻩshi--; ﻩﻩif(shi<0) ﻩﻩﻩﻩ ﻩshi=23; ﻩ DCB码 护 ﻩwrite_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码 ﻩ write_1302(0x8e,0x80);//打开写保护 ﻩﻩ write_sfm(1,shi); ﻩﻩﻩtemp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的 ﻩ write_1302(0x8e,0x00);//允许写,禁止写保 ﻩ ﻩ write_1602com(er+2);//因为设置液晶的模式是 写入数据后,指针自动加一,所以需要光标回位 ﻩ ﻩ break; ﻩﻩcase 4: ﻩ ﻩri--; ﻩﻩﻩﻩ if(ri<1) ﻩ ri=31; ﻩﻩ ﻩ ﻩ ﻩﻩ DCB码 ﻩ 护 ﻩ ﻩ Conver_week(nian,yue,ri); ﻩﻩwrite_week(week); ﻩﻩ write_nyr(9,ri); ﻩﻩtemp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的 write_1302(0x8e,0x00);//允许写,禁止写保 ﻩ write_1302(0x86,temp);//向DS1302内写日期寄存器 -- -- 86H写入调整后的日期数据BCD码 ﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 ﻩﻩ ﻩﻩ ﻩﻩ break; ﻩcase 5: ﻩ yue--; ﻩﻩﻩ if(yue<1) ﻩ yue=12; ﻩﻩConver_week(nian,yue,ri); write_week(week); write_nyr(6,yue); ﻩ ﻩﻩ ﻩ ﻩﻩﻩ 求的DCB码 ﻩ ﻩ temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要 ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩﻩﻩ ﻩwrite_1302(0x88,temp);//向DS1302内写月份寄存器88H写入调整后的月份数据BCD码 ﻩ ﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩ ﻩ ﻩwrite_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 ﻩ ﻩ ﻩﻩ break; ﻩﻩ ﻩcase 6: ﻩﻩﻩ nian--; ﻩﻩﻩif(nian<0) ﻩﻩnian=99; -- -- ﻩ ﻩ ﻩConver_week(nian,yue,ri); write_week(week); write_nyr(3,nian); ﻩ ﻩﻩ ﻩ ﻩ ﻩ ﻩ ﻩtemp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩ ﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码 ﻩﻩﻩ ﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 ﻩ ﻩ write_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 ﻩﻩﻩﻩﻩ ﻩ ﻩ ﻩ} break; ﻩ ﻩﻩwhile(!dec); ﻩ ﻩ } ﻩ} else ﻩ{ ﻩﻩif(on==0) { } ﻩﻩ delay(20); ﻩﻩﻩif(on==0) ﻩ ﻩ { ﻩbuzz=0;//蜂鸣器短响一次 -- -- ﻩdelay(200); ﻩ ﻩbuzz=1; ﻩ GPS_EN=!GPS_EN; ﻩ ES=GPS_EN; ﻩ while(!on); ﻩﻩﻩ} ﻩ} }ﻩ } -- -- 结束语 在整个设计过程中学到了许多没学到的知识,在电路焊接时虽然没什么大问题,但从中也知道了焊接在整个作品中的重要性,电路工程量大,不能心急,一个个慢慢来不能急于求成。反而达到事半功倍的效果。对电路的设计、布局要先有一个好的构思,才显得电路板美观、大方。程序编写中,由于思路不清晰,开始时遇到了很多的问题,经过静下心来思考,理清了思路,反而得心应手。在此次设计中,知道了做事要有一颗平常的心,不要想着走捷径,一步一脚印。也练就了我的耐心,做什么事都要有耐心。在本次设计中学到了很多很多东西,这是最重要的。总之,此次毕业设计使我的能力得到了全方位的提高,次设计的万年历也存在的不足的地方,有待于以后的改进。 -- -- -- -- 致谢词 这篇论文的完成在一定意义上也代表我大学生涯的结束,在此我要感谢学校为我带来的一切,没有学校为我提供的平台,我也不可能顺利地完成大学的学习,更不可能完成本次毕业设计。 这篇毕业论文是在我的导师张祥莉老师的亲切关怀和悉心指导下完成的。没有张老师的指导我想我不可能顺利地完成此次毕业设计,在此我想对他表示由衷的感谢。 最后 ,我想表达对所有任职老师的感谢,是你们在这大学四年时间里给了我们知识和力量,给了我们踏足社会的能力。 在论文即将完成之际,我的心情无法平静,从不知道毕业论文怎么写,到开始进入课题到论文的完成,再到顺利完成了毕业论文答辩稿,有很多老师,同学,朋友向我提供的帮助,在这里请接受我诚挚的谢意! -- -- 参考文献 [1] 余锡存,曹国华,单片机原理及接口技术. 西安:西安电子科技大学出版社,2000 [2] 郭天祥,新概念51单片机c语言教程。北京:电子工业出版社,2009 [3] 杨拴科, 模拟电子技术基础. 北京:高等教育出版社, 2003。 [4] 李光才,楼然笛.单片机课程设计实例指导. 北京:北京航空航天大学出版社,2004。 [6] 杨立民,单片机技术及应用.西安:西安电子科技大学出版社,1997.9~12。 [7] 马忠梅,单片机的C语言应用程序设计.北京:北京航空航天大学出版社,1997。 [8]王天曦 ,李洪儒.电子技术工艺基础.北京:清华大学出版社,2000。 [9] 弘道工作室,融会贯通 Protel99电路设计.北京: 人民交通出版设,2000。 -- -- [10] 张伟,王力,赵晶,ProtelDXP 入门与提高.北京:人民邮电出版社, 2003.2。 [11] 李广弟,朱月秀,王秀山.单片机基础[M]. 北京:北京航空航天大学出版社, 2001.7。 [12] 谭浩强,C程序设计(第二版)[M].北京:清华大学出版社,2003。 [13] 付家才,单片机控制工程实践技术[M]. 北京:化学工业出版社,2004.3。 [14] W.Simpson,Editor,The Point-to-Point Protocol, RFC1661 [EB/OL]. July 1994。 [15] WAVECOM,AT Commands Interface Guide, Revision 002[EB/OL].6th November 2003。 -- -- 附录 硬件原理图与PCB图 -- -- ﻩ 源程序: #include //#include"DS18B20_3.H\" #include <string.h> #include #define uint unsigned int #define uchar unsigned char #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^4; //设置键 sbit add=P3^5; //加键 sbit dec=P3^6; ﻩ//减键 sbit on= P3^7; sbit buzz=P1^4; sbit GPS_EN=P2^0; //DS1302时钟芯片与C51之间的引脚连接定义 sbit IO=P1^1; sbit SCLK=P1^0; sbit RST=P1^2; char a,miao,shi,fen,ri,yue,nian,week,setn; char miao_1,shi_1,fen_1,ri_1,yue_1,nian_1; uchar temp; bit start=0,stop=0; #define RsBuf_Nﻩ 800 // 键 -- -- unsigned char xdata RsBuf[RsBuf_N]; //定义串口接收数据缓冲区 uint RsPoint; uchar douhao=0; uchar qq=0,qq1=0; 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代表的是累加器的地址。 ***************************************************************/ /* 函数功能:输入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数据 */ 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+=0x; //如果为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[]={\"20 - - "}; //年显示的固定字符 uchar code tab2[]={\" : : \ﻩ //时间显示的固定字符 uchar code qk[]= {\" "}; //清空显示 //延时函数,后面经常调用 void delay(uint xms)//延时函数,有参函数 { uint x,y; ﻩfor(x=xms;x>0;x--) } /********液晶写入指令函数与写入数据函数,以后可调用**************/ /*在这个程序中,液晶写入有关函数会在DS1302的函数中调用,所以液晶程序要放在前面*/ for(y=10;y>0;y--); -- -- void write_1602com(uchar com)//****液晶写入指令函数**** { ﻩrs=0;//数据/指令选择置为指令 ﻩrw=0; //读写选择置为写 P0=com;//送入数据 ﻩen=1;//拉高使能端,为制造有效的下降沿做准备 ﻩdelay(1); ﻩen=0;//en由高变低,产生下降沿,液晶执行命令 } void write_1602dat(uchar dat)//***液晶写入数据函数**** { rs=1;//数据/指令选择置为数据 ﻩrw=0; //读写选择置为写 ﻩP0=dat;//送入数据 en=1; //en置高电平,为制造下降沿做准备 delay(1); ﻩen=0; //en由高变低,产生下降沿,液晶执行命令 } -- -- void lcd_init()//***液晶初始化函数**** { ﻩwrite_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据 write_1602com(0x0c);//开显示不显示光标 ﻩwrite_1602com(0x06);//整屏不移动,光标自动右移 write_1602com(0x01);//清显示 delay(300); ﻩwrite_1602com(yh+1);//日历显示固定符号从第一行第1个位置之后开始显示 ﻩ{ ﻩwrite_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分 // delay(3); } for(a=0;a<14;a++) ﻩwrite_1602com(er+1);//时间显示固定符号写入位置,从第2个位置后开始显示 ﻩfor(a=0;a<8;a++) { write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号 // delay(3); } } -- -- /*********************over***********************/ /*和DS1302时钟芯片有关的函数*/ /*************写一个数据到对应的地址里***************/ void write_1302(uchar add,uchar dat) { ﻩuchar i;ﻩﻩ ﻩRST = 1;ﻩﻩ //把复位线拿高 for(i=0;i<8;i++) ﻩ{ ﻩﻩ //低位在前 ﻩ SCLK = 0;ﻩ //时钟线拿低开始写数据 ﻩIO = add & 0x01; ﻩﻩadd >>= 1; ﻩ //把地址右移一位 ﻩﻩSCLK = 1;ﻩ //时钟线拿高 ﻩ }ﻩ for(i=0;i<8;i++) { SCLK = 0; ﻩ //时钟线拿低开始写数据 -- -- ﻩ} ﻩRST = 0;ﻩ ﻩSCLK = 0; } /*************从对应的地址读一个数据出来***************/ uchar read_1302(uchar add) { ﻩuchar value,i; RST = 1; ﻩﻩ //把复位线拿高 for(i=0;i<8;i++) ﻩ //低位在前 IO = 0; //复位线合低 IO = dat & 0x01; ﻩdat >>= 1;ﻩﻩ //把数据右移一位 SCLK = 1; //时钟线拿高 ﻩ{ﻩﻩ ﻩﻩSCLK = 0;ﻩﻩ //时钟线拿低开始写数据 ﻩIO = add & 0x01; //把地址右移一位 ﻩﻩadd >>= 1; ﻩ SCLK = 1;ﻩﻩ //时钟线拿高 } ﻩ -- -- for(i=0;i<8;i++) { //时钟线拿低开始读数据 ﻩﻩSCLK = 0;ﻩ ﻩﻩvalue >>= 1; ﻩﻩif(IO == 1) ﻩﻩ value |= 0x80; } SCLK = 1; //时钟线拿高 ﻩRST = 0;ﻩﻩﻩ //复位线合低 SCLK = 0; ﻩIO = 0; ﻩreturn value;ﻩ //返回读出来的数据 } uchar BCD_Decimal(uchar bcd)//BCD码转十进制函数,输入BCD,返回十进制 { uchar Decimal; ﻩ Decimal=bcd>>4; } return(Decimal=Decimal*10+(bcd&=0x0F)); -- -- //-------------------------------------- void ds1302_init() //1302芯片初始化子函数(2010-01-07,12:00:00,week4) { ﻩRST=0; ﻩ ﻩwrite_1302(0x8e,0x00); //允许写,禁止写保护 0 //write_1302(0x84,0x12);//向DS1302内写小时寄存器84H写入初始小时//write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00 //write_1302(0x82,0x00);//向DS1302内写分寄存器82H写入初始分数据0SCLK=0; 数据12 ﻩ//write_1302(0x8a,0x04);//向DS1302内写周寄存器8aH写入初始周数据4 ﻩ//write_1302(0x86,0x07);//向DS1302内写日期寄存器86H写入初始日期数据07 //write_1302(0x88,0x01);//向DS1302内写月份寄存器88H写入初始月份数 据01 //write_1302(0x8c,0x10);//向DS1302内写年份寄存器8cH写入初始年份数据10 ﻩwrite_1302(0x8e,0x80); //打开写保护 } //------------------------------------ //时分秒显示子函数 -- -- void write_sfm(uchar add,uchar dat)//向LCD写时分秒,有显示位置加、现示数据,两个参数 { uchar gw,sw; ﻩgw=dat%10;//取得个位数字 ﻩsw=dat/10;//取得十位数字 write_1602com(er+add);//er是头文件规定的值0x80+0x40 ﻩwrite_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码 ﻩwrite_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码 } //------------------------------------- //年月日显示子函数 void write_nyr(uchar add,uchar dat)//向LCD写年月日,有显示位置加数、显示数据,两个参数 { uchar gw,sw; ﻩ ﻩgw=dat%10;//取得个位数字 sw=dat/10;//取得十位数字 ﻩwrite_1602com(yh+add);//设定显示位置为第一个位置+add ﻩwrite_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码 -- -- } //------------------------------------------- void write_week(uchar week)//写星期函数 { ﻩwrite_1602com(yh+0x0c);//星期字符的显示位置 ﻩswitch(week) ﻩ{ ﻩ ﻩ ﻩ ﻩ ﻩ case 1:write_1602dat('M');//星期数为1时,显示 write_1602dat('O'); write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码ﻩ ﻩ write_1602dat('N'); ﻩ break; case 2:write_1602dat('T');//星期数据为2时显示 ﻩ write_1602dat('U'); ﻩ write_1602dat('E'); ﻩﻩﻩ break; ﻩ ﻩﻩcase 3:write_1602dat('W');//星期数据为3时显示 ﻩﻩ write_1602dat('E'); -- -- ﻩ ﻩ ﻩﻩ ﻩ case 4:write_1602dat('T');//星期数据为4是显示 ﻩ write_1602dat('H'); write_1602dat('D'); ﻩ break; ﻩﻩﻩ write_1602dat('U'); ﻩ ﻩ ﻩ ﻩﻩ break; case 5:write_1602dat('F');//星期数据为5时显示 ﻩ write_1602dat('R'); write_1602dat('I'); ﻩﻩ break; ﻩﻩcase 6:write_1602dat('S');//星期数据为6时显示 ﻩ ﻩﻩ ﻩcase 0:write_1602dat('S');//星期数据为7时显示 ﻩ ﻩ write_1602dat('T'); write_1602dat('A'); break; ﻩﻩ write_1602dat('U'); write_1602dat('N'); -- -- ﻩﻩ break; ﻩ} } //****************键盘扫描有关函数********************** void keyscan() { if(set==0)//---------------set为功能键(设置键)-------------------- { ﻩﻩdelay(9);//延时,用于消抖动 ﻩ ﻩ if(set==0)//延时后再次确认按键按下 ﻩ{ buzz=0;//蜂鸣器短响一次 delay(200); ﻩ buzz=1; ﻩ setn++; ﻩﻩif(setn>=7) ﻩsetn=0;ﻩﻩﻩ//设置按键共有秒、分、时、日、月、年、返回,7个功能循环 ﻩﻩﻩswitch(setn) ﻩ { -- -- ﻩﻩﻩﻩcase 1: TR0=0;//关闭定时器 ﻩ ﻩ ﻩ ﻩ ES=0; ﻩ//TR1=0; write_1602com(er+8);//设置按键按动一次,秒位置显示光标 //e r+0x09; ﻩ write_1602com(0x0f);//设置光标为闪烁 //ﻩ ﻩtemp=(miao)/10*16+(miao)%10;//秒数据写入DS1302 ﻩ ﻩ write_1302(0x8e,0x00); ﻩ ﻩwrite_1302(0x80,0x80|temp);//miao ﻩ write_1302(0x8e,0x80); ﻩ break; case 2: // ﻩﻩ ﻩﻩﻩ write_1602com(er+5); //按2次fen位置显示光标 //er+0x06ﻩ ﻩ ﻩ //write_1602com(0x0f); ﻩbreak; ﻩﻩ ﻩcase 3: ﻩ ﻩwrite_1602com(er+2); //按动3次,shi ﻩﻩ ﻩ//write_1602com(0x0f); ﻩﻩ break; ﻩ // case 4: write_1602com(yh+0x0e);//按动4次,week ﻩﻩ //write_1602com(0x0f); -- -- ﻩﻩ //ﻩbreak; ﻩ ﻩﻩcase 4: write_1602com(yh+0x0a);//按动4次,ri //write_1602com(0x0f); ﻩﻩ break; ﻩﻩ case 5: write_1602com(yh+0x07);//按动5次,yue ﻩﻩﻩ //write_1602com(0x0f); ﻩ ﻩ ﻩ break; case 6: write_1602com(yh+0x04);//按动6次,nian //write_1602com(0x0f); break; ﻩﻩ ﻩ ﻩ ﻩ ﻩﻩcase 0: ﻩ write_1602com(0x0c);//按动到第7次,设置光标不闪烁 ﻩﻩﻩES=1; ﻩ TR0=1;//打开定时器 ﻩtemp=(miao)/10*16+(miao)%10; ﻩﻩ write_1302(0x8e,0x00); ﻩwrite_1302(0x80,0x00|temp);//miao数据写入DS1302 ﻩﻩ ﻩﻩwrite_1302(0x8e,0x80); ﻩbreak;ﻩ ﻩ ﻩ} ﻩﻩﻩwhile(!set); -- -- ﻩﻩ} ﻩ} //------------------------------加键add----------------------------ﻩ ﻩ if(setn!=0)//当set按下以下。再按以下键才有效(按键次数不等于零) { ﻩ{ ﻩﻩdelay(10); ﻩif(add==0) if(add==0) //上调键 ﻩﻩﻩ{ ﻩﻩ ﻩbuzz=0;//蜂鸣器短响一次 ﻩﻩdelay(200); buzz=1; ﻩ ﻩ ﻩﻩﻩswitch(setn) ﻩ { case 1:miao++;//设置键按动1次,调秒 if(miao>=60) ﻩﻩﻩﻩ ﻩﻩ ﻩﻩﻩ miao=0;//秒超过59,再加1,就归零 ﻩﻩ ﻩﻩ write_sfm(0x07,miao);//令LCD在正确位置显示\"加\"设定好的秒数 ﻩﻩtemp=(miao)/10*16+(miao)%10;//十进制转换成DS130 2要求的DCB码 -- -- ﻩ ﻩﻩﻩ ﻩwrite_1302(0x8e,0x00); //允许写,禁止写保护 ﻩ ﻩwrite_1302(0x80,temp); //向DS1302内写秒寄存器 80H写入调整后的秒数据BCD码 ﻩ ﻩ write_1302(0x8e,0x80); //打开写保护 ﻩﻩ write_1602com(er+8);//因为设置液晶的模式是写入数据后,光标自动 右移,所以要指定返回 ﻩﻩﻩﻩ //write_1602com(0x0b); break; ﻩﻩ ﻩﻩﻩ case 2:fen++; ﻩﻩ ﻩﻩﻩﻩif(fen>=60) ﻩﻩﻩ ﻩﻩ ﻩfen=0; ﻩﻩﻩﻩ ﻩﻩwrite_sfm(0x04,fen);//令LCD在正确位置显示\"加\"设定好的分数据 temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求 ﻩﻩ 的DCB码 ﻩ ﻩ ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩwrite_1302(0x82,temp);//向DS1302内写分寄存器82H写 ﻩﻩ 入调整后的分数据BCD码 ﻩ ﻩ ﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 write_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动 ﻩﻩ 加一,在这里是写回原来的位置 ﻩ ﻩ ﻩ ﻩﻩﻩ break; ﻩcase 3:shi++; -- -- ﻩﻩﻩ ﻩﻩif(shi>=24) ﻩshi=0; ﻩwrite_sfm(0x01,shi);//令LCD在正确的位置显示\"加\"设定好的小时 ﻩﻩ ﻩ ﻩ ﻩ 数据 码 ﻩ ﻩ ﻩﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩwrite_1302(0x84,temp);//向DS1302内写小时寄存器8 ﻩ ﻩﻩ temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB 4H写入调整后的小时数据BCD码 ﻩﻩﻩﻩﻩ ﻩﻩﻩﻩ write_1302(0x8e,0x80);//打开写保护 write_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自 动加一,所以需要光标回位 ﻩﻩ ﻩﻩﻩﻩbreak; ﻩﻩ ﻩﻩcase 4:ri++; ﻩ ﻩ ﻩ ﻩ ﻩ ﻩ ﻩ if(ri>=32) ri=1; ﻩﻩ ﻩﻩConver_week(nian,yue,ri); ﻩ ﻩ write_week(week); ﻩﻩﻩwrite_nyr(9,ri);//令LCD在正确的位置显示"加\"设定好的日期数据 ﻩ temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的 DCB码 ﻩ ﻩﻩﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 -- -- ﻩ ﻩﻩﻩﻩ write_1302(0x86,temp);//向DS1302内写日期寄存器86H 写入调整后的日期数据BCD码 ﻩﻩﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩﻩﻩ ﻩwrite_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针自动加一, 所以需要光标回位 ﻩﻩ ﻩ ﻩ ﻩ ﻩ ﻩﻩﻩ ﻩbreak; ﻩ ﻩ case 5:yue++; ﻩif(yue>=13) yue=1; ﻩConver_week(nian,yue,ri); ﻩﻩﻩﻩﻩ ﻩ ﻩ ﻩﻩﻩﻩ ﻩwrite_week(week); ﻩ write_nyr(6,yue);//令LCD在正确的位置显示"加\"设定好的月份 数据 ﻩ ﻩﻩﻩtemp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的D CB码 ﻩﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩﻩﻩﻩ write_1302(0x88,temp);//向DS1302内写月份寄存器88H写入 调整后的月份数据BCD码 ﻩﻩ ﻩﻩ ﻩ ﻩ write_1302(0x8e,0x80);//打开写保护 ﻩﻩwrite_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自动加一, 所以需要光标回位 ﻩ -- -- ﻩ ﻩ ﻩﻩ ﻩ break; case 6:nian++; ﻩﻩﻩ ﻩ if(nian>=100) ﻩ nian=0; ﻩConver_week(nian,yue,ri); write_week(week); ﻩﻩ ﻩ ﻩﻩ ﻩ ﻩﻩ ﻩﻩ write_nyr(3,nian);//令LCD在正确的位置显示\"加"设定好的年份数据 ﻩﻩ ﻩ temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩﻩ ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ ﻩﻩﻩ ﻩwrite_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码 ﻩ ﻩ ﻩﻩﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 ﻩwrite_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针自 动加一,所以需要光标回位 ﻩﻩﻩﻩ ﻩ ﻩ ﻩ } ﻩbreak; ﻩﻩﻩﻩwhile(!add); ﻩﻩ} ﻩﻩ//------------------减键dec,各句功能参照'加键'注释--------------- ﻩ} -- -- ﻩ if(dec==0) ﻩ{ ﻩdelay(10);//调延时,消抖动 ﻩﻩ if(dec==0) ﻩ ﻩ ﻩﻩ{ ﻩ ﻩbuzz=0;//蜂鸣器短响一次 ﻩdelay(200); ﻩ ﻩ buzz=1; ﻩﻩ{ ﻩ case 1: switch(setn) ﻩﻩ ﻩmiao--; ﻩ ﻩ if(miao<0) ﻩﻩ 数 miao=59;//秒数据减到-1时自动变成59 write_sfm(0x07,miao);//在LCD的正确位置显示改变后新的秒 ﻩﻩ temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要 求的DCB码 ﻩ ﻩwrite_1302(0x8e,0x00); //允许写,禁止写保护 ﻩﻩﻩﻩ ﻩwrite_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后 的秒数据BCD码 ﻩ ﻩﻩ ﻩwrite_1302(0x8e,0x80); //打开写保护 -- -- ﻩ ﻩwrite_1602com(er+8);//因为设置液晶的模式是写入数据后,指针自 动加一,在这里是写回原来的位置 ﻩﻩﻩﻩﻩﻩ//write_1602com(0x0b); ﻩﻩ ﻩﻩ break; ﻩ ﻩ ﻩ ﻩ ﻩ case 2: fen--; if(fen<0) ﻩﻩﻩ ﻩ fen=59; write_sfm(4,fen); ﻩﻩ ﻩﻩﻩtemp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码 ﻩﻩﻩ write_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ ﻩwrite_1302(0x82,temp);//向DS1302内写分寄存器82H写入调 整后的分数据BCD码 ﻩﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 ﻩﻩ ﻩﻩﻩwrite_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 ﻩﻩﻩ ﻩ ﻩ ﻩﻩ ﻩcase 3: ﻩﻩ shi--; ﻩﻩ ﻩﻩif(shi<0) ﻩﻩﻩshi=23; ﻩbreak; -- -- ﻩ ﻩﻩﻩ ﻩﻩﻩﻩ ﻩ write_sfm(1,shi); temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码 ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩﻩ ﻩwrite_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整 后的小时数据BCD码 ﻩﻩ ﻩﻩﻩ write_1302(0x8e,0x80);//打开写保护 ﻩwrite_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自动加一, 所以需要光标回位 ﻩﻩﻩbreak; ﻩﻩ ﻩcase 4: ﻩri--; ﻩ ﻩ ﻩﻩif(ri<1) ﻩri=31; Conver_week(nian,yue,ri); ﻩﻩﻩ ﻩ ﻩ ﻩ ﻩﻩ ﻩ write_week(week); ﻩ write_nyr(9,ri); ﻩﻩ ﻩtemp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码 ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入 ﻩﻩ ﻩ 调整后的日期数据BCD码 ﻩ ﻩﻩﻩ ﻩ write_1302(0x8e,0x80);//打开写保护 write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针 -- -- 自动加一,所以需要光标回位 ﻩ ﻩﻩ ﻩﻩ ﻩ ﻩﻩﻩﻩ ﻩ ﻩbreak; case 5: yue--; ﻩ if(yue<1) ﻩﻩ ﻩ ﻩ ﻩ ﻩ ﻩ ﻩyue=12; ﻩﻩConver_week(nian,yue,ri); ﻩwrite_week(week); write_nyr(6,yue); ﻩﻩtemp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要 求的DCB码 ﻩﻩ ﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩ ﻩwrite_1302(0x88,temp);//向DS1302内写月份寄存器88H写入 调整后的月份数据BCD码 ﻩ ﻩ ﻩﻩ ﻩwrite_1302(0x8e,0x80);//打开写保护 ﻩ write_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自 动加一,所以需要光标回位 ﻩ ﻩ ﻩ break; ﻩﻩ case 6: nian--; ﻩﻩﻩﻩﻩ ﻩ ﻩ ﻩﻩif(nian<0) -- -- ﻩ ﻩﻩﻩnian=99; ﻩﻩ ﻩﻩﻩConver_week(nian,yue,ri); ﻩ ﻩ ﻩ ﻩﻩwrite_week(week); write_nyr(3,nian); temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求 ﻩﻩﻩ 的DCB码 ﻩﻩﻩﻩﻩ ﻩwrite_1302(0x8e,0x00);//允许写,禁止写保护 ﻩﻩ ﻩ write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整 后的年份数据BCD码 ﻩ ﻩ ﻩﻩ write_1302(0x8e,0x80);//打开写保护 write_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针 自动加一,所以需要光标回位 ﻩ ﻩ ﻩﻩ } ﻩbreak; ﻩﻩ ﻩ ﻩﻩﻩﻩwhile(!dec); ﻩﻩ } ﻩ } } ﻩelse ﻩ{ if(on==0) -- -- ﻩﻩ{ ﻩ ﻩﻩ{ delay(20); if(on==0) ﻩﻩ ﻩbuzz=0;//蜂鸣器短响一次 ﻩ ﻩ delay(200); buzz=1; ﻩﻩﻩGPS_EN=!GPS_EN; ﻩ ﻩES=GPS_EN; ﻩﻩﻩ while(!on); ﻩ } ﻩ} ﻩ} } // 通讯中断接收程序 中断函数无返回值 void uart_rx(void) interrupt 4ﻩusing 3 { //ﻩES=0; ﻩif(RI) //必须判断RI是否为1 -- -- { ﻩif(SBUF=='$'&&start==0) ﻩ { ﻩstart=1; ﻩ RsPoint=0; ﻩ ﻩstop=0; ﻩﻩﻩdouhao=0; ﻩ} if(start==1) ﻩﻩ{ ﻩﻩ if(SBUF==',') ﻩﻩ { ﻩ ﻩﻩdouhao++; ﻩ } ﻩﻩRsBuf[RsPoint++]=SBUF; ﻩﻩif(douhao==9) ﻩ { ﻩ ﻩ qq1=RsPoint; ﻩdouhao=0; ﻩ } ﻩﻩﻩif(SBUF=='\\n') -- -- ﻩ { ﻩﻩﻩﻩRsPoint=0; ﻩﻩ start=0; ﻩ ﻩ douhao=0; ﻩﻩ if(RsBuf[5]=='C') ﻩﻩ { ﻩﻩ ﻩstop=1; ﻩ ﻩREN=0; ﻩﻩ ﻩﻩstart=0; ﻩ ﻩ ﻩqq=qq1; ﻩ ﻩﻩ} ﻩﻩ } ﻩﻩ} } ﻩRI=0; // ES=1; } void GPS_TIME() { ﻩif(stop==1&&RsBuf[5]=='C') -- -- ﻩ{ ﻩ ES=0; //接收到有效数据 if(RsBuf[17]=='A')ﻩ { ﻩﻩﻩmiao_1 = (RsBuf[11]-0x30)*10+(RsBuf[12]-0x30); ﻩﻩﻩfen_1 = (RsBuf[9]-0x30)*10+(RsBuf[10]-0x30); ﻩ 充 ﻩﻩ if(shi_1>=0&&shi_1<8) ﻩ ﻩ if(yue_1==1||yue_1==3||yue_1==5||yue_1==7||yue_1==8||yue_1=ﻩﻩ{ ﻩﻩ nian_1= (RsBuf[qq+4]-0x30)*10+(RsBuf[qq+5]-0x30); yue_1 = (RsBuf[qq+2]-0x30)*10+(RsBuf[qq+3]-0x30); ﻩshi_1 =((RsBuf[7]-0x30)*10+(RsBuf[8]-0x30)+8)%24; //时间差补 ﻩﻩ ri_1 = (RsBuf[qq]-0x30)*10+(RsBuf[qq+1]-0x30); =10||yue_1==12) ﻩﻩ { ﻩﻩﻩ ﻩ if(ri_1<31) ri_1++; ﻩ else ﻩ { ﻩﻩﻩ ri_1=1; -- -- ﻩ ﻩ ﻩﻩﻩ ﻩ ﻩ if(yue_1<12) yue_1++; ﻩelse ﻩﻩ ﻩﻩﻩ { ﻩ ﻩ yue_1=1; ﻩﻩ ﻩ ﻩ ﻩﻩﻩ ﻩ ﻩ ﻩ if(nian_1<100) nian_1++; } } } ﻩ if(yue_1==4||yue_1==6||yue_1==9||yue_1==11) { ﻩ if(ri_1<30)ﻩri_1++; else ﻩﻩ ﻩ ﻩﻩ { ﻩﻩﻩ ﻩ ri_1=1; ﻩ ﻩ ﻩ ﻩ ﻩ yue_1++; ﻩﻩ } } //闰年ﻩﻩ if(yue_1==2)ﻩ ﻩ { -- -- ﻩ if((nian_1%4==0&&nian_1%100!=0)||nian_1%400==0)ﻩ ﻩﻩﻩ { ﻩﻩ if(ri_1<29) ri_1++; ﻩﻩﻩelse ﻩ ﻩ ﻩ ﻩ { ﻩﻩ ri_1=1; ﻩ } ﻩyue_1=3; } ﻩﻩﻩ else ﻩ ﻩ { ﻩ if(ri_1<28)ﻩri_1++; ﻩﻩﻩ else { ﻩﻩﻩ ri_1=1; ﻩ ﻩ yue_1=3; ﻩﻩﻩ } ﻩﻩ } } } ﻩﻩ else -- -- ﻩﻩﻩ { ﻩﻩﻩ ri_1 = (RsBuf[qq]-0x30)*10+(RsBuf[qq+1]-0x30); ﻩ ﻩ yue_1 = (RsBuf[qq+2]-0x30)*10+(RsBuf[qq+3]-0x30); nian_1= (RsBuf[qq+4]-0x30)*10+(RsBuf[qq+5]-0x30);ﻩﻩﻩ ﻩﻩﻩ } ﻩ ﻩ ﻩ ﻩnian=nian_1; yue=yue_1; ri=ri_1; ﻩﻩshi=shi_1; ﻩfen=fen_1; miao=miao_1; ﻩﻩ ﻩ write_1302(0x8e,0x00); //允许写,禁止写保护 ﻩﻩif(((ri!=BCD_Decimal(read_1302(0x87)))||(yue!=BCD_Decimal(read_1 302(0x89)))||(nian!=BCD_Decimal(read_1302(0x8d))))&&(ri>0&&ri<32&&yue>0&&yue<13&&nian>=0&&nian<100)) ﻩ{ write_1302(0x86,((ri)/10*16+(ri)%10));//向DS1302内写日期寄存器86 ﻩﻩ H写入初始日期数据07 ﻩ write_1302(0x88,((yue)/10*16+(yue)%10));//向DS1302内写月份寄 存器88H写入初始月份数据01 -- -- ﻩ write_1302(0x8c,((nian)/10*16+(nian)%10));//向DS1302内写年 份寄存器8cH写入初始年份数据10ﻩ ﻩﻩ } ﻩﻩﻩif((miao!=BCD_Decimal(read_1302(0x81)))||(fen!=BCD_Decimal(read_1302(0x83)))||(shi!=BCD_Decimal(read_1302(0x85)))) { ﻩﻩ write_1302(0x80,((miao)/10*16+(miao)%10)); //向DS1302内写 秒寄存器80H写入初始秒数据00 ﻩﻩ write_1302(0x82,((fen)/10*16+(fen)%10));//向DS1302内写分寄存器 82H写入初始分数据00 ﻩ ﻩﻩwrite_1302(0x84,((shi)/10*16+(shi)%10));//向DS1302内写小时寄存器84H 写入初始小时数据12 ﻩﻩﻩ} ﻩ ﻩ ﻩ} ﻩelse if(RsBuf[17]!='A')ﻩﻩﻩ ﻩ{ ﻩwrite_1602com(0x80+0x40+14); ﻩ //不是有效数据,不显示 ﻩﻩwrite_1602com(0x80+0x40+14); ﻩwrite_1602dat('A');ﻩﻩﻩ ﻩ ﻩ //接收并处理有效数据时显示ﻩﻩﻩ ﻩ ﻩ write_1302(0x8e,0x80); //打开写保护 -- -- ﻩﻩwrite_1602dat(' ');ﻩﻩ ﻩﻩ}ﻩﻩﻩ ﻩ} ﻩelse ﻩ { miao = BCD_Decimal(read_1302(0x81)); REN=1;stop=0; ES=1; ﻩﻩfen = BCD_Decimal(read_1302(0x83)); ﻩﻩshi = BCD_Decimal(read_1302(0x85)); ﻩﻩri = BCD_Decimal(read_1302(0x87)); ﻩyue = BCD_Decimal(read_1302(0x)); ﻩnian=BCD_Decimal(read_1302(0x8d)); ﻩﻩ//week=BCD_Decimal(read_1302(0x8b)); //不读取,直接通过年月日数据计算得到 } void display() { write_sfm(7,miao);//秒,从第二行第8个字后开始显示(调用时分秒显示子函数) write_sfm(4,fen);//分,从第二行第5个字符后开始显示 } -- -- ﻩwrite_sfm(1,shi);//小时,从第二行第2个字符后开始显示ﻩ //显示日、月、年数据: write_nyr(9,ri);//日期,从第二行第9个字符后开始显示 ﻩwrite_nyr(6,yue);//月份,从第二行第6个字符后开始显示 write_nyr(3,nian);//年,从第二行第3个字符后开始显示 Conver_week(nian,yue,ri); ﻩwrite_week(week); ﻩwrite_1602com(0x80+0x40+11); ﻩ{ ﻩ write_1602dat('O'); if(GPS_EN==1) ﻩﻩwrite_1602dat('N'); ﻩ ﻩ} ﻩ else { ﻩwrite_1602dat('O'); write_1602dat('F'); write_1602dat(' '); write_1602dat('F'); ﻩwrite_1602dat(' '); write_1602dat(' '); -- -- ﻩ ﻩ} } //*******************主函数************************** //*************************************************** void main() { uint i; write_1602dat(' '); ﻩlcd_init(); //调用液晶屏初始化子函数 ds1302_init(); //调用DS1302时钟的初始化子函数 for(i=0;i<RsBuf_N;i++) RsBuf[i]='0'; ﻩUart_init(); //调用定时计数器的设置子函数 ﻩwhile(1) //无限循环下面的语句: ﻩ{ ﻩ keyscan(); //调用键盘扫描子函数 GPS_TIME(); } } -- -- void timer0() interrupt 1 //取得并显示日历和时间 { display(); }ﻩﻩ -- 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务