电子钟说明书

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

单片机设计论文
《电子时钟》
学生姓名田伶俐
学号5011212412
所属学院信息工程学院
专业计算机科学与技术班级16-4班
日期2014. 11
目录
前言 (3)
正文 (4)
一.设计的目的与意义 (4)
二.电子时钟 (4)
2.1电子时钟简介 (4)
2.2 电子时钟的基本特点 (4)
2.3 电子时钟的原理 (4)
三. 单片机识的相关知识 (4)
3.1 单片机简介 (4)
3.2 单片机的特点 (5)
3.3 AT89C51单片机介绍 (5)
四.控制系统的硬件设计 (7)
4.1 单片机型号的选择 (7)
4.2 DS1302时钟芯片简介 (7)
4.3 LCD1602液晶模块简介 (8)
4.4 电路设计原理图 (8)
4.5 电路仿真图 (9)
五.控制系统的软件设计 (9)
5.1主程序流程图 (9)
5.2程序清单 (10)
5.3 仿真结果图 (10)
六.单片机效果图 (11)
七 .总结 (12)
参考文献 (12)
附录 (13)
前言
随着社会、科技的发展,人类得知时间,从观太阳、摆钟到现在电子钟,不断研究、创新。

为了在观测时间的同时,能够了解其它与人类密切相关的信息,比如温度、星期、日期等,电子时钟诞生了,它集时间、日期、星期和温度功能于一身,具有读取方便、显示直观、功能多样、电路简洁等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。

二十一世纪的今天,最具代表性的计时产品就是电子万年历,它是近代世界钟表业界的第三次革命。

第一次是摆和摆轮游丝的发明,相对稳定的机械振荡频率源使钟表的走时差从分级缩小到秒级,代表性的产品就是带有摆或摆轮游丝的机械钟或表。

第二次革命是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,使钟表的走时月差从分级缩小到秒级。

第三次革命就是单片机数码计时技术的应用,使计时产品的走时日差从分级缩小到1/600
万秒,从原有传统指针计时的方式发展为人们日常更为熟悉的夜光数字显示方式,直观明了,并增加了全自动日期、星期、温度以及其他日常附属信息的显示功能,它更符合消费者的生活需求!因此,电子万年历的出现带来了钟表计时业界跨跃性的进步……
我国生产的电子时钟有很多种,总体上来说以研究多功能电子时钟为主,使时钟除了原有的显示时间,日期等基本功能外,还具有闹铃,报警等功能。

商家生产的电子时钟更从质量,价格,实用上考虑,不断的改进电子时钟的设计,使其更加的具有市场。

本设计主要采用AT89C51单片机作为主控核心,由DS1302时钟芯片提供时钟、LED动态扫描显示屏显示。

AT89C51单片机是由Atmel公司推出的,功耗小,电压可选用4~6V电压供电;DS1302时钟芯片是美国DALLAS公司推出的具有涓细电流充电功能的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小;数字显示是采用的LED液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒和温度等信息。

此外,该电子万年历还具有时间校准等功能。

正文
一.设计的目的与意义
1.1 设计的目的
1)实时温度显示;
2) 年月日星期时分秒显示;
3) 年月日星期时分秒调整;
4) 闹钟定时小时分钟和秒;
1.2 设计的意义
可作为产品生产,作为居家的时钟显示与温度计。

二.电子时钟
2.1电子时钟简介
1957年,Ventura发明了世界上第一个电子表,从而奠定了电子时钟的基础,电子时钟开始迅速发展起来。

现代的电子时钟是基于单片机的一种计时工具,采用延时程序产生一定的时间中断,用于一秒的定义,通过计数方式进行满六十秒分钟进一,满六十分小时进一,满二十四小时小时清零。

从而达到计时的功能,是人民日常生活补课缺少的工具。

2.2 电子时钟的基本特点
现在高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟、石英钟、石英表都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要经常调试,数字式电子钟用集成电路计时,译码代替机械式传动,用LED显示器代替指针显示进而显示时间和日期,减小了误差,这种表具有时、分、秒显示时间的功能和年月日显示日期的功能,还可以进行校对,片选的灵活性好。

2.3 电子时钟的原理
该电子时钟由AT89C51,74LS373,BUTTON,数码管等构成,采用晶振电路作为驱动电路,由延时程序和循环程序产生的一秒定时,达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天,满三十天(闰年二月满二十九天,平年二月满二十八天)为一个月,满十二个月为一年。

电路中的键控1实现“年”和“分”的调节,键控2实现“月”和“时”的调节,键控3实现“日”和“分”的调节。

每按一次就加一。

三. 单片机识的相关知识
3.1 单片机简介
单片机全称为单片机微型计算机(Single Chip Microsoftcomputer)。

从应用领域来看,单片机主要用来控制,所以又称为微控制器(Microcontroller Unit)或嵌入式控制器。

单片机是将计算机的基本部件微型化并集成在一块芯片上的微型计算机。

3.2 单片机的特点
1 . 单片机的存储器ROM和RAM时严格区分的。

ROM称为程序存储器,只存放程序,固定常数,及数据表格。

RAM则为数据存储器,用作工作区及存放用户数据。

2 . 采用面向控制的指令系统。

为满足控制需要,单片机有更强的逻辑控制能力,特别是单片机具有很强的位处理能力。

3 . 单片机的I/O口通常时多功能的。

由于单片机芯片上引脚数目有限,为了解决实际引脚数和需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于何种功能,可由指
令来设置或由机器状态来区分。

4 . 单片机的外部扩展能力很强。

在内部的各种功能部件不能满足应用的需求时,均可在外部进行扩展,与许多通用的微机接口芯片兼容,给应用系统设计带来了很大的方便。

3.3 AT89C51单片机介绍
VCC:电源;GND:接地。

P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。

当P1口的管脚第一次写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)。

四.控制系统的硬件设计
4.1 单片机型号的选择
通过对多种单片机性能的分析,最终认为89C51是最理想的电子时钟开发芯片。

89C51是一种带4K字节闪烁可编程可擦除只读存储器的低电压,高性能CMOS8位微处理器,器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。

由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的89C51是一种高效微控制器,而且它与MCS-51兼容,且具有4K字节可编程闪烁存储器和1000写/擦循环,数据保留时间为10年等特点,是最好的选择。

4.2 DS1302时钟芯片简介
DS1302是美国DALLAS公司推出的一种高性能、低功耗的具有涓流充电功能的实时时钟芯片。

因具有其价格低廉、性能稳定的优点而被广泛应用于对时间精度有较高要求的各种智能化仪器仪表中。

DS1302实时时钟芯片的主要性能特点: 1.1 实时时钟/日历电路可提供秒、分、时、日、星期、月和年的信息,当某个月小于31天时可以自动调整,且具有闰年补偿功能 1.2 内含31字节静态RAM 1.3 采用SPI总线与CPU进行通信,只需要三个口线:(1)RST(复位线),(2)I/O(数据线),(3)SCLK(串行时钟线) 1.4 双电源(主电源和备用电源)供电,保证系统掉电时间数据不丢失,可设置备用电源涓流充电功能 1.5 电压宽度可达2.0~5.5V 1.6 体积小,8脚DIP封装或8脚SOIC封装 DS1302引脚分配图如图
(2)所示
4.3 LCD1602液晶模块简介
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。

它由若干个5×7或者5×11点阵字符位组图(3)LCD1602引脚分配图成,每个点阵字符位都可以显示一个字符。

模块采用数字式接口,能够方便地与单片机等控制类芯片进行通信。

由于其具有体积小、重量轻、显示质量高、功耗低等诸多优点而被广泛用于智能化仪器仪表的显示器件。

LCD1602引脚分配图各引脚功能为:
1(VSS)电源地
2(VCC)+5V电源
3(VO)液晶对比度调节端
4(RS)数据/命令选择端
5(R/W)读/写选择端
6(E)使能信号端
7~14(DB0~DB7)八位双向数据总线
15(BLA)背光源正极
15(BLK)背光源负极
4.4 电路设计原理图
4.5 电路仿真图
按设置键设置所需要调节的年,月,日,时,分,秒
加减键调节所需要的时间和日期
查看农历闹钟键可以查看农历时间,并发出用蜂鸣器警报五.控制系统的软件设计
5.1主程序流程图
5.2程序清单
备注:见附录5.3 仿真结果图
六.单片机效果图
七 .总结
进过不懈的努力,我顺利完成了这次单片机课程设计课题中的个性化电子时钟设计,本次仿真总的来说是实现了预期的效果。

功能还不够完善,设计还比较简单。

不过通过此次设计我们还是学会了不少东西。

首先,学会了keil和proteus软件。

然后,由于此次程序是用C语言编写的,以前的C语言知识的到了巩固。

同时,我们还领悟到了独自学习的重要性。

通过这次的设计使我认识到本人对单片机方面的知识知道的太少了,对于书本上的很多知识还不能灵活运用,尤其是对程序设计语句的理解和运用,不能够充分理解每个语句的具体含义总的来说,本次的设计使我从中学到了最重要的东西,那就是如何从理论到实践的转化,怎样将我所学到的知识运用到我以后的工作中去。

在大学的课堂的学习只是在给我们灌输专业知识,而我们应把所学的用到我们现实的生活中去,此次的电子时钟设计给我奠定了一个实践基础,我会在以后的学习、生活中磨练自己,使自己适应于以后的竞争,同时在查找资料的过程中我也学到了许多新的知识,在和同学协作过程中增进同学间的友谊,使我对团队精神的积极性和重要性有了更加充分的理解。

最后,我觉得应该感谢李京兵老师在平时课堂上的启发。

使得我们在课程设计过程中,巩固和学习了单片机知识。

相信这对我以后的课程设计和毕业设计将会有很大的帮助!
参考文献
[1]刘乐善等.微型计算机接口技术及应用.武汉:华中科技大学出版社,2009.
[2]胡汉才.单片机原理及其接口技术.北京:清华大学出版社,2009.
[3]李秉操等.单片机接口技术及在工业控制中的应用.西安:陕西电子编辑部,1991
附录
#include<reg52.h>
//#include"DS18B20_3.H"
#include <string.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define wd 1
#define yh 0x80 (100000000=80)
#define er 0x80+0x40
sbit en=P2^7;
sbit rw=P2^6;
sbit rs=P2^5;
sbit set=P3^0;
sbit add=P3^1;
sbit dec=P3^2;
sbit seeNL_NZ=P3^3;
sbit DQ=P3^7;
sbit buzzer=P2^0;
sbit led=P2^4;
bit led1=1;
bit ZDK=1,NZK=1;
bit zdkg=0,nzkg=0;
unsigned char temp_miao;
unsigned char bltime;
sbit IO=P1^1;
sbit SCLK=P1^0;
sbit RST=P1^2;
uchar a,miao,shi,fen,ri,yue,nian,week,setn,temp;
uint flag; bit c_moon;
uchar nz_shi=12,nz_fen=0,nz_miao=0,setNZn; uchar shangyimiao,bsn,temp_hour;
uchar T_NL_NZ;
bit timeron=0; bit baoshi=0;
bit p_r=0;
data uchar year_moon,month_moon,day_moon,week; sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
ACC
ACC.0=E0H
code uchar year_code[597]={
0x04,0x97,0x4f, //1991
0x06,0x4B,0x44, //1992
0x36,0xA5,0x37, //1993
0x0e,0xA5,0x4A, //1994
0x86,0xB2,0xBf, //1995
0x05,0xAC,0x53, //1996
0x0A,0xB6,0x47, //1997
0x59,0x36,0xBC, //1998
0x09,0x2e,0x50, //1999 294
0x0C,0x96,0x45, //2000 297
0x4d,0x4A,0xB8, //2001
0x0d,0x4A,0x4C, //2002
0x0d,0xA5,0x41, //2003
0x25,0xAA,0xB6, //2004
0x05,0x6A,0x49, //2005
0x7A,0xAd,0xBd, //2006
0x02,0x5d,0x52, //2007
0x09,0x2d,0x47, //2008
0x5C,0x95,0xBA, //2009
0x0A,0x95,0x4e, //2010
0x0B,0x4A,0x43, //2011
0x4B,0x55,0x37, //2012
0x0A,0xd5,0x4A, //2013
0x95,0x5A,0xBf, //2014
0x04,0xBA,0x53, //2015
0x0A,0x5B,0x48, //2016
0x65,0x2B,0xBC, //2017
0x05,0x2B,0x50, //2018
0x0A,0x93,0x45, //2019
0x47,0x4A,0xB9, //2020
0x06,0xAA,0x4C, //2021
0x0A,0xd5,0x41, //2022
0x24,0xdA,0xB6, //2023
0x04,0xB6,0x4A, //2024
0x69,0x57,0x3d, //2025
0x0A,0x4e,0x51, //2026
0x0d,0x26,0x46, //2027
0x5e,0x93,0x3A, //2028
0x0d,0x53,0x4d, //2029
0x05,0xAA,0x43, //2030};
code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3}; code uint day_code2[3]={0x111,0x130,0x14e};
)
bit c_moon;
data uchar year_moon,month_moon,day_moon,week;
bit get_moon_day(uchar month_p,uint table_addr) {uchar temp;
switch (month_p){
case 1:{temp=year_code[table_addr]&0x08;
if (temp==0)return(0);else return(1);} case 2:{temp=year_code[table_addr]&0x04;
if (temp==0)return(0);else return(1);} case 3:{temp=year_code[table_addr]&0x02;
if (temp==0)return(0);else return(1);} case 4:{temp=year_code[table_addr]&0x01;
if (temp==0)return(0);else return(1);} case 5:{temp=year_code[table_addr+1]&0x80;
if (temp==0) return(0);else return(1);} case 6:{temp=year_code[table_addr+1]&0x40;
if (temp==0)return(0);else return(1);} case 7:{temp=year_code[table_addr+1]&0x20;
if (temp==0)return(0);else return(1);} case 8:{temp=year_code[table_addr+1]&0x10;
if (temp==0)return(0);else return(1);} case 9:{temp=year_code[table_addr+1]&0x08;
if (temp==0)return(0);else return(1);} case 10:{temp=year_code[table_addr+1]&0x04;
if (temp==0)return(0);else return(1);} case 11:{temp=year_code[table_addr+1]&0x02;
if (temp==0)return(0);else return(1);} case 12:{temp=year_code[table_addr+1]&0x01;
if (temp==0)return(0);else return(1);} case 13:{temp=year_code[table_addr+2]&0x80;
if (temp==0)return(0);else return(1);}}} void Conversion(bit c,uchar year,uchar month,uchar day) { uchar temp1,temp2,temp3,month_p;
uint temp4,table_addr;
bit flag2,flag_y;
temp1=year/16;
temp2=year%16;
// year=temp1*10+temp2;
year=temp1*16+temp2;
temp1=month/16;
temp2=month%16;
//month=temp1*10+temp2;
month=temp1*16+temp2;
temp1=day/16;
temp2=day%16;
//day=temp1*10+temp2;
day=temp1*16+temp2;
if(c==0){
table_addr=(year+0x64-1)*0x3;}
else {table_addr=(year-1)*0x3; }
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
temp2=year_code[table_addr+2]&0x1f;
if(temp1==0x1){
temp3=temp2-1; }
else{temp3=temp2+0x1f-1;}
if (month<10){
temp4=day_code1[month-1]+day-1;}
else{temp4=day_code2[month-10]+day-1;}
if ((month>0x2)&&(year%0x4==0)){
temp4+=1;}
if (temp4>=temp3){
temp4-=temp3;
month=0x1;
month_p=0x1;
flag2=get_moon_day(month_p,table_addr);
flag_y=0;
if(flag2==0)temp1=0x1d; //小月29天
else temp1=0x1e; //大小30天
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
while(temp4>=temp1){
temp4-=temp1;
month_p+=1;
if(month==temp2){
flag_y=~flag_y;
if(flag_y==0)month+=1;}
else month+=1;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e; }
day=temp4+1 }
else{ temp3-=temp4;
if (year==0x0){year=0x63;c=1;}
else year-=1;
table_addr-=0x3;
month=0xc;
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
if (temp2==0)
month_p=0xc;
else
month_p=0xd; //
month_p
flag_y=0;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
while(temp3>temp1){
temp3-=temp1;
month_p-=1;
if(flag_y==0)month-=1;
if(month==temp2)flag_y=~flag_y;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e; }
day=temp1-temp3+1;}
c_moon=c;
temp1=year/10;
temp1=_crol_(temp1,4);
temp2=year%10;
year_moon=temp1|temp2;
temp1=month/10;
temp1=_crol_(temp1,4);
temp2=month%10;
month_moon=temp1|temp2;
temp1=day/10;
temp1=_crol_(temp1,4);
temp2=day%10;
day_moon=temp1|temp2;}
code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5};
void Conver_week(uchar year,uchar month,uchar day)
{//c=0 为21世纪,c=1 为19世纪输入输出数据均为BCD数据uchar p1,p2;
year+=0x64;
p1=year/0x4;
p2=year+p1;
p2=p2%0x7;
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 nlp[]={"NL: - - PING"}; //农历平年显示
uchar code nlr[]={"NL: - - RUN "}; //农历润年显示
uchar code NZd[]={"timer: - - "}; //显示闹钟固定点
uchar code qk[]= {" "}; //清空显示
uchar code tm[]= {"time"};
void Delayns(int num)//延时函数
{while(num--);}
void Init_DS18B20(void)//初始化ds1820
{unsigned char x=0;
DQ = 1; //DQ复位
Delayns(8); //稍做延时
DQ = 0; //单片机将DQ拉低
Delayns(80); //精确延时大于480us
DQ = 1; //拉高总线
Delayns(14);
x=DQ; //稍做延时后如果x=0则初始化成功x=1则初始化失败Delayns(20);}
unsigned char ReadOneChar(void)//读一个字节
{unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{DQ = 0; // 给脉冲信号
dat>>=1;
DQ = 1; // 给脉冲信号
if(DQ)
dat|=0x80;
Delayns(4);}
return(dat);}
void WriteOneChar(unsigned char dat)//写一个字节
{unsigned char i=0;
for (i=8; i>0; i--)
{DQ = 0;
DQ = dat&0x01;
Delayns(5);
DQ = 1;
dat>>=1;}}
unsigned int ReadTemperature(void)//读取温度
{unsigned char a=0;
unsigned char b=0;
unsigned int t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
a=ReadOneChar(); //读低8位
b=ReadOneChar(); //读高8位
t=b;
t<<=8;
t=t|a;
tt=t*0.0625;
t= tt*10+0.5; //放大10倍输出并四舍五入
return(t);}
void delay(uint xms)//延时函数,有参函数
{uint x,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);}
write_1602com(uchar com)//****液晶写入指令函数****
{rs=0;//数据/指令选择置为指令
rw=0; //读写选择置为写
P0=com;//送入数据
delay(1);
en=1;//拉高使能端,为制造有效的下降沿做准备
delay(1);
en=0;}
write_1602dat(uchar dat)//***液晶写入数据函数****
{rs=1;//数据/指令选择置为数据
rw=0; //读写选择置为写
P0=dat;//送入数据
delay(1);
en=1; //en置高电平,为制造下降沿做准备
delay(1);
en=0; //en由高变低,产生下降沿,液晶执行命令}
lcd_init()//***液晶初始化函数****
{write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据write_1602com(0x0c);//开显示不显示光标
write_1602com(0x06);//整屏不移动,光标自动右移
write_1602com(0x01);//清显示
write_1602com(yh+1);//日历显示固定符号从第一行第1个位置之后开始显示
for(a=0;a<14;a++)
{write_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分
delay(3);}
write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示
for(a=0;a<8;a++)
{write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号
delay(3);}}
void write_byte(uchar dat)//写一个字节
{ACC=dat;
RST=1;
for(a=8;a>0;a--)
{IO=ACC0;
SCLK=0;
SCLK=1;
ACC=ACC>>1;}}
uchar read_byte()//读一个字节
{RST=1;
for(a=8;a>0;a--)
{ACC7=IO;
SCLK=1;
SCLK=0;
ACC=ACC>>1;}
return (ACC);}
void write_1302(uchar add,uchar dat)//向1302芯片写函数,指定写入地址,数据{RST=0;
SCLK=0;
RST=1;
write_byte(add);
write_byte(dat);
SCLK=1;
RST=0;}
uchar read_1302(uchar add)//从1302读数据函数,指定读取数据来源地址{uchar temp;
RST=0;
SCLK=0;
RST=1;
write_byte(add);
temp=read_byte();
SCLK=1;
RST=0;
return(temp);}
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;
SCLK=0;
write_1302(0x8e,0x00); //允许写,禁止写保护
miao=read_1302(0x81);
miao=0x7F&miao;
write_1302(0x80,miao);
//write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00
//write_1302(0x82,0x00);//向DS1302内写分寄存器82H写入初始分数据00
//write_1302(0x84,0x12);//向DS1302内写小时寄存器84H写入初始小时数据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(0x80,0x00);
write_1302(0x8e,0x80); //打开写保护
}
void write_temp(uchar add,uint dat)//向LCD写温度数据,并指定显示位置
{uint gw,sw,bw;
bw=dat/100;//取得百位
sw=dat%100/10;//取得十位数字
gw=dat%10;//取得个位数字
write_1602com(er+add);//er是头文件规定的值0x80+0x40
write_1602dat(0x30+bw);
write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码
write_1602dat('.');
write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码
write_1602dat(0xdf);//显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码write_1602dat(0x43); //显示"C"符号,0x43是液晶屏字符库里大写C的地址码
}
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显示码
write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码
}
void write_nl(uchar add,uchar dat)//向LCD写时分秒,有显示位置加、现示数据,两个参数{uchar gw,sw;
//gw=dat%10;//取得个位数字
//sw=dat/10;//取得十位数字
gw=dat%16;//取得个位数字
sw=dat/16;//取得十位数字
write_1602com(er+add);//er是头文件规定的值0x80+0x40
// write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码// write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码write_1602dat('0'+sw);//数字+30得到该数字的LCD1602显示码
write_1602dat('0'+gw);//数字+30得到该数字的LCD1602显示码}
void write_week(uchar week)//写星期函数
{write_1602com(yh+0x0c);//星期字符的显示位置
switch(week)
{case 1:write_1602dat('M');//星期数为1时,显示
write_1602dat('O');
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');
write_1602dat('D');
break;
case 4:write_1602dat('T');//星期数据为4是显示
write_1602dat('H');
write_1602dat('U');
break;
case 5:write_1602dat('F');//星期数据为5时显示
write_1602dat('R');
write_1602dat('I');
break;
case 6:write_1602dat('S');//星期数据为6时显示
write_1602dat('T');
write_1602dat('A');
break;
case 0:write_1602dat('S');//星期数据为7时显示
write_1602dat('U');
write_1602dat('N');
break;}
write_1602dat(' ');}
void keyscan()
{uint nian_temp;
if(seeNL_NZ==0){
delay(9);
if(seeNL_NZ==0)
{led1=0;
bltime=0;
if(timeron==1)
{TR2=~TR2;
if(TR2==0)
{buzzer=1;}}
else{if((setn==0)&&(setNZn==0)) //在没有进入调时模式时才可按动
{buzzer=0;//蜂鸣器短响一次
delay(20);buzzer=1;if(TR1==1){
TR1=0; }
else
{ T_NL_NZ++;
if(T_NL_NZ==3)
{ setn=0;
setNZn=0;
T_NL_NZ=0; }} }}
while(seeNL_NZ==0);
}}
if(set==0)//---------------set为功能键(设置键)--------------------
{delay(9);//延时,用于消抖动
if(set==0)//延时后再次确认按键按下
{led1=0;
bltime=0;
do
{if(add==0)
zdkg=1;
if(dec==0)
nzkg=1;}
while((!set)||(!add)||(!dec));
if((nzkg==1)||(zdkg==1))
{if(nzkg==1)
{NZK=~NZK;
if(NZK==0)
{TR2=0;
buzzer=1;}}
else
{if(zdkg==1)
{
ZDK=~ZDK;
if(ZDK==0)
{
TR1=0;
buzzer=1;
}}}
if(((NZK==1)&&(nzkg==1))||((ZDK==1)&&(zdkg==1)))
{
buzzer=0;
delay(10);
buzzer=1;
}
else
{
buzzer=0;delay(5);
buzzer=1;delay(5);
buzzer=0;delay(5);
buzzer=1;
}
nzkg=0;zdkg=0;
}
else
{
buzzer=0;//蜂鸣器短响一次delay(20);
buzzer=1;
if(T_NL_NZ==0x02) //证明是对闹钟进行设置
{
setNZn++;
if(setNZn==4) //闹钟设定成功,退回到正常显示并开启闹钟
{
setNZn=0;
setn=0;
// timerOn=1;
}
switch(setNZn)
{
case 0: //正常显示日期时间
write_1602com(0x0c); // 置光标不闪?
write_1602com(er); //时间显示固定符号写入位置?
for(a=0;a<16;a++)
write_1602dat(NZd[a]); //写显示时间固定符号,两个冒号
write_sfm(8,nz_shi); //闹钟时
write_sfm(11,nz_fen); //闹钟分
write_sfm(14,nz_miao); //闹钟秒
break;
case 3: //闹钟秒光标闪烁
write_1602com(er+15); //设置按键按动一次,秒位置显示光
write_1602com(0x0f); //设置光标为闪烁
break;
case 2: //闹钟分光标闪烁
write_1602com(er+12); //设置按键按动一次,秒位置显示光
write_1602com(0x0f); //设置光标为闪烁
break;
case 1: //闹钟时光标闪烁
write_1602com(er+9); //设置按键按动一次,秒位置显示光write_1602com(0x0f); //设置光标为闪烁
break;
} }
else //证明是对时间及日期进行设置
{
if(T_NL_NZ==0)
{
setn++;
if(setn==7)
setn=0; switch(setn)
{
case 6: //TR0=0;//关闭定时器
//TR1=0;
write_1602com(er+7);
break;
case 5:
write_1602com(er+4);
//write_1602com(0x0f);
break;
case 4:
write_1602com(er+1); //按动3次,shi
//write_1602com(0x0f);
break;
// case 4: write_1602com(yh+0x0e);//按动4次,week
//write_1602com(0x0f);
// break;
case 3: write_1602com(yh+0x0a);//按动4次,ri
//write_1602com(0x0f);
break;
case 2: write_1602com(yh+0x07);//按动5次,yue
//write_1602com(0x0f);
break;
case 1: TR0=0;
write_1602com(yh+0x04);//按动6次,nian
write_1602com(0x0f);//设置光标为闪烁
temp=(miao)/10*16+(miao)%10;//秒数据写入
write_1302(0x8e,0x00);
write_1302(0x80,0x80|temp);//miao
write_1302(0x8e,0x80);
//write_1602com(0x0f);
break;
case 0:
write_1602com(0x0c); //按动到第7次,设置光标不闪烁
// temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00); //允许写,禁止写保护
write_1302(0x80,0x00|temp); //miao数据写入DS1302
write_1302(0x8e,0x80); //打开写保护
TR0=1;//打开定时器
break;
} }}}}}
if((setn!=0)&&(setNZn==0))//当set按下以下。

再按以下键才有效(按键次数不等于零){
if(add==0) //上调键
{
delay(10);
if(add==0)
{
led1=0;
bltime=0;
buzzer=0;//蜂鸣器短响一次
delay(20);
buzzer=1;
while(!add);
switch(setn)
{
case 6:miao++;//设置键按动1次,调秒
if(miao==60)
miao=0;//秒超过59,再加1,就归零
write_sfm(0x06,miao);//令LCD在正确位置显示"加"设定好
temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求
write_1302(0x8e,0x00); //允许写,禁止写保护
write_1302(0x80,0x80|temp); //向DS1302内写秒寄存器80H
write_1302(0x8e,0x80); //打开写保护
write_1602com(er+7);//因为设置液晶的模式是写入数据后,
//write_1602com(0x0b);
break;
case 5:fen++;
if(fen==60)
temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302内写分寄存器82H写入
write_1302(0x8e,0x80);//打开写保护
write_1602com(er+4);//
break;
case 4:shi++;
if(shi==24)
shi=0;
write_sfm(0x00,shi);//令LCD在正确的位置显示"加"设定好
temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x84,temp);//向DS1302内写小时寄存器84H写
write_1302(0x8e,0x80);//打开写保护
write_1602com(er+1);//因为设置液晶的模式是写入数据后,
break;
case 4:week++;
if(week==8)
week=1;
write_1602com(yh+0x0C);//指定'加'后的周数据显示位置
write_week(week);//指定周数据显示内容
temp=(week)/10*16+(week)%10;//十进制转换成DS1302要
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入write_1302(0x8e,0x80);//打开写保护
write_1602com(yh+0x0e);//因为设置液晶的模式是写入
break;
case 3:ri++;
if((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12))
{
if(ri==32)
ri=1;
}
else
{
if(yue==2)
{
if(p_r==1)
{
if(ri==30)
ri=1;
}
else
if(ri==29)
ri=1;
}
}
else
{
if(ri==31)
ri=1;
}}
Conver_week(nian,yue,ri);
write_week(week);
write_nyr(9,ri);//令LCD在正确的位置显示"加"设定好的日
temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x86,temp);//向DS1302内写日期寄存器86H写
write_1302(0x8e,0x80);//打开写保护
write_1602com(yh+10);//因为设置液晶的模式是写入数据break;
case 2:yue++;
if(yue==13)
yue=1;
if((yue==4)||(yue==6)||(yue==9)||(yue==11))
{
if(ri>30)
ri=1;
}
else
{
if(yue==2)
{
if(p_r==1)
{
if(ri>29)
ri=1;
}
else
{
if(ri>28)
ri=1;
}}}
Conver_week(nian,yue,ri);
write_week(week);
write_nyr(6,yue);//令LCD在正确的位置显示"加"设定好的
temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x88,temp);
write_1602com(yh+7);//因为设置液晶的模式是写入数据后,break;
case 1:nian++;
if(nian==100)
nian=0;
nian_temp=2000+nian;
if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0))) //判断是否为闰年
p_r=1;
else
p_r=0;
Conver_week(nian,yue,ri);
write_week(week);
write_nyr(3,nian);//令LCD在正确的位置显示"加"设定好的
temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写
write_1302(0x8e,0x80);//打开写保护
write_1602com(yh+4);//因为设置液晶的模式是写入数据后,
break;
}
}
}
if(dec==0)
{
delay(10);//调延时,消抖动
if(dec==0)
{
led1=0;
bltime=0;
buzzer=0;//蜂鸣器短响一次
delay(20);
buzzer=1;
while(!dec);
switch(setn)
{
case 6:
miao--;
if(miao==-1)
miao=59;//秒数据减到-1时自动变成59
write_sfm(0x06,miao);//在LCD的正确位置显示改变后新的秒数
write_1602com(er+7);//因为设置液晶的模式是写入数据后,指针
temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的
write_1302(0x8e,0x00); //允许写,禁止写保护
write_1302(0x8e,0x80); //打开写保护
//write_1602com(0x0b);
break;
case 5:
fen--;
if(fen==-1)
fen=59;
write_sfm(3,fen);
write_1602com(er+4);//因为设置液晶的模式是写入数据后,指针
temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整
write_1302(0x8e,0x80);//打开写保护
break;
case 4:
shi--;
if(shi==-1)
shi=23;
write_sfm(0,shi);
temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB
write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调
write_1302(0x8e,0x80);//打开写保护
write_1602com(er+1);//因为设置液晶的模式是写入数据后,指针
break;
/*
case 4:week--;
if(week==0)
week=7;
write_1602com(yh+0x0C);//指定'加'后的周数据显示位置
write_week(week);//指定周数据显示内容
temp=(week)/10*16+(week)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00);//允许写,禁止写保护
write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入调整后的周数据BCD码
write_1302(0x8e,0x80);//打开写保护
write_1602com(yh+0x0e);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
break;
*/
case 3:
ri--;
if((yue==1)||(yue==3)||(yue==5)||(yue==7)||(yue==8)||(yue==10)||(yue==12))
{
if(ri==0)
ri=31;
}
else
{
if(yue==2)
{
if(p_r==1)
{
if(ri==0)
ri=29;
}
else
{
if(ri==0)
ri=28;
}
}
else
{
if(ri==0)
ri=30;
}
}
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写入调
write_1302(0x8e,0x80);//打开写保护
write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指
break;
case 2:。

相关文档
最新文档