点击链接获取Keil源码与Project Backups仿真图:
https://download.csdn.net/download/qq_64505944/87853675

源码获取
目 录

摘 要 1
1 方案论证 2
1.1 单片机芯片的选择方案和论证 2
1.2 显示模块选择方案和论证 2
1.3 时钟芯片的选择方案和论证 3
1.4 电路设计最终方案决定 3
2 系统的硬件设计与实现 3
2.1 电路设计框图 3
2.2 系统硬件概述 3
2.3 主要单元电路的设计 4
2.3.1 单片机主控制模块的设计 4
2.3.2 时钟电路模块的设计 5
2.3.3 电路原理及说明 5
2.3.4 显示模块的设计 7
3 系统的软件设计 8
3.1 程序流程框图 8
4 测试与结果分析 10
4.1 硬件测试 10
4.2 软件测试 10
4.3 测试结果分析与结论 10
4.3.1 测试结果分析 10
4.3.2 测试结论 11
5 课设总结 12
致 谢 13
参考文献 14
附录一:系统电路图 15
附录二:系统程序清单 16

摘 要
随着科技的快速发展,时间的流逝,至从观太阳、摆钟到现在电子钟,人类不断研究,不断创新纪录。美国DALLAS公司推出的具有涓细电流充电能的低功耗实时时钟电路DS1302。它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
综上所述此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。

关键词:时钟电钟,DS1302,动态扫描,单片机

1 方案论证
1.1 单片机芯片的选择方案和论证
方案一:
采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术, 当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。
方案二:
采用AT89S52,片内ROM全都采用Flash ROM;能以3V的超底压工作;同时也与MCS-51系列单片机完全该芯片内部存储器为8KB ROM 存储空间,同样具有89C51的功能,且具有在线编程可擦除技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,不需要对芯片多次拔插,所以不会对芯片造成损坏,所以选择采用AT89S52作为主控制系统。
1.2 显示模块选择方案和论证
方案一:
采用LED数码管动态扫描,LED数码管价格适中,对于显示数字合适,采用动态扫描法与单片机连接时,虽然占用的单片机口线少,但连线还需要花费一点时间,所以也不用此种作为显示。
方案二:
采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用在显示数字显得太浪费,且价格也相对较高,所以也不用此种作为显示。
方案三:
采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样,清晰可见,并且我做的最小系统上带一个TS1620-1,和AT89S52已经接好,省了很多麻烦,所以在此设计中采用LCD液晶显示屏。

1.3 时钟芯片的选择方案和论证
方案一:
直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。采用此种方案虽然减少芯片的使用,节约成本,但是,实现的时间误差较大,所以不采用此方案。
方案二:
采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、周、月、年进行计数,而且精度高,位的RAM做为数据暂存区,工作电压2.5V~5.5V范围内,2.5V时耗电小于300nA。
1.4 电路设计最终方案决定
综上各方案所述,对此次作品的方案选定: 采用AT89S52作为主控制系统; DS1302提供时钟;LCD液晶显示屏作为显示。

2 系统的硬件设计与实现
2.1 电路设计框图

图1系统原理图
2.2 系统硬件概述
本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;时钟电路由DS1302提供,它是一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31*8的用于临时性存放数据的RAM寄存器。可产生年、月、日、周日、时、分、秒,具有使用寿命长,精度高和低功耗等特点,同时具有掉电自动保存功能;温度的采集由DS18B20构成;显示部份由LCD液晶显示屏显示。
2.3 主要单元电路的设计
2.3.1 单片机主控制模块的设计
AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3, MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。
单片机的最小系统如下图所示,18引脚和19引脚接时钟电路,XTAL1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,XTAL2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出。第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端。 如图2 所示:

      ![在这里插入图片描述](https://img-blog.csdnimg.cn/d2f8bb9fefd842ab9e468013589ada83.png)

图2 主控制系统

2.3.2 时钟电路模块的设计
图.3示出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进行操作。如果在传送过程中RSTS置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电动行时,在Vcc大于等于2.5V之前,RST必须保持低电平。中有在SCLK 为低电平时,才能将RST置为高电平,I/O为串行数据输入端(双向)。SCLK始终是输入端。

            图3 DS1302的引脚图

2.3.3 电路原理及说明
(1) 时钟芯片DS1302的工作原理:
DS1302在每次进行读、写程序前都必须初始化,先把SCLK端置 “0”,接着把RST端置“1”,最后才给予SCLK脉冲;读/写时序如下图4所示。DS1302的控制字的位7必须置1,若为0则不能把对DS1302进行读写数据。对于位6,若对程序进行读/写时RAM=1,对时间进行读/写时,CK=0,位1至位5指操作单元的地址。位0是读/写操作位,进行读操作时,该位为1;该位为0则表示进行的是写操作。控制字节总是从最低位开始输入/输出的。表.2为DS1302的日历、时间寄存器内容:“CH”是时钟暂停标志位,当该位为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位为0时,时钟开始运行。“WP”是写保护位,在任何的对时钟和RAM的写操作之前,WP必须为0。当“WP”为1时,写保护位防止对任一寄存器的写操作。

(2) DS1302的控制字节:
DS1302控制字节的高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出
(3) 数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
(4) DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式。
此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。

2.3.4 显示模块的设计
如图.4为LCD显示模块,和最小系统上的连线一样,无需修改。

图-4 LCD液晶显示屏显示模块

3 系统的软件设计
3.1 程序流程框图

                         图5主程序流程图

图6 时间调整程序流程图

4 测试与结果分析
4.1 硬件测试
电子万年历的电路系统较大,对于焊接方面更是不可轻视,庞大的电路系统中只要出于一处的错误,则会对检测造成很大的不便,而且电路的交线较多,对于各种锋利的引脚要注意处理,否则会刺被带有包皮的导线,则会对电路造成短路现象。
在本成电子万年历的设计调试中遇到了很多的问题。回想这些问题只要认真多思考都是可以避免的,以下为主要的问题:
(1)LCD液晶显示屏显示部分已经连在最小系统上,节省了不少时间和精力。
(2)对万年历修改时间或日期时,有时LCD液晶显示屏被屏蔽掉,造成不亮现象。
解决:根据仪器的测试,发现电路的驱动能力不足,最后在DS1302时钟芯片的/CS、SCLK、RET端接入5.1K的上拉电阻后,电路的驱动能力才能满足,即可解决不亮现象。
4.2 软件测试
电子成年历是多功能的数字型,可以看当前日期,时间。电子成年历功能很多,所以对于它的程序也较为复杂,所以在编写程序和调试时出现了相对较多的问题。最后经过多次的模块子程序的修改,一步一步的完成,最终解决了软件。在软件的调试过程中遇到的主要问题是:
1.烧入程序后,LCD液晶显示屏显示亮度不好。
解决:一遍旋转10K欧的滑动变阻器,一遍观看LCD显示屏,知道看到合适的亮度为止。
4.3 测试结果分析与结论
4.3.1 测试结果分析
1.在测试中遇到LCD液晶显示屏为不显示时,首先使用试测仪对电路进行测试,观察是否存在漏焊,虚焊,或者元件损坏,滑动变阻器器没有调好:查看烧写的程序是否正确无误,对程序进行认真修改。
4.3.2 测试结论
经过多次的反复测试与分析,可以对电路的原理及功能更加熟悉,同时提高了设计能力与及对电路的分析能力。同时在软件的编程方面得到更到的提高,对编程能力得到加强,同时对所学的知识得到很大的提高与巩固。

5 课设总结
在整个设计过程中,充分发挥人的主观能动性,自主学习,学到了许多没学到的知识。较好的完成了作品,达到了预期的目的,完了最初的设想。在电路焊接时虽然没什么大问题,但从中也知道了焊接在整个作品中的重要性,电路工程量大,不能心急,一个个慢慢来不能急于求成。反而达到事半功倍的效果。对电路的设计、布局要先有一个好的构思,才显得电路板美观、大方。程序编写中,由于思路不清晰,开始时遇到了很多的问题,经过静下心来思考,和同组员的讨论,理清了思路,反而得心应手。在此次设计中,知道了做凡事要有一颗平常的心,不要想着走捷径,一步一脚印。也练就了我们的耐心,做什么事都在有耐心。此次比赛中学到了很多很多东西,这是最重要的。总之,此次课设使我的能力得到了全方位的提高。

致 谢

感谢学院给我提供了一个展现自己的舞台,给我一次难得煅炼的机会,使得我的动手能力和专业技能都有了很大的提高。
在做课设的日子里得到了陈老师王老师的悉心指导,在此向他们致以诚挚的谢意。感谢提供相关技术帮助的老师和同学,你们的支持和鼓励使我们对这次的作品完成有了信心和动力,也给了我们很多无私的帮助和支持,我们在此深表谢意。

参考文献

1刘勇 编 数字电路 电子工业出版社 2004
2陈正振 编 电子电路设计与制作 广西交通职业技术学院信息工程系 2007
3杨子文 编 单片机原理及应用 西安电子科技大学出版社 2006
4 王法能 编 单片机原理及应用 科学出版社 2004

附录一:系统电路图

附录二:系统程序清单

#include <REG51.H>
#include <intrins.h>
//#include "LCD1602.h"
//#include "DS1302.h"
#define uint unsigned int
#define uchar unsigned char
sbit  DS1302_CLK = P1^7;              //实时时钟时钟线引脚
sbit  DS1302_IO  = P1^6;              //实时时钟数据线引脚
sbit  DS1302_RST = P1^5;              //实时时钟复位线引脚
sbit  ACC0 = ACC^0;
sbit  ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;  //秒,分,时到日,月,年位闪的计数
sbit Set = P2^0;       //模式切换键
sbit Up = P2^1;        //加法按钮
sbit Down = P2^2;      //减法按钮
sbit out = P2^3;       //立刻跳出调整模式按钮
char done,count,temp,flag,up_flag,down_flag;
uchar TempBuffer[5],week_value[2];
void show_time();   //液晶显示程序
/***********1602液晶显示部分子程序****************/
//Port Definitions**********************************************************
sbit LcdRs      = P2^5;
sbit LcdRw      = P2^6;
sbit LcdEn      = P2^7;
sfr  DBPort     = 0x80;        //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
//内部等待函数**************************************************************************
unsigned char LCD_Wait(void)
{LcdRs=0;LcdRw=1; _nop_();LcdEn=1;   _nop_();    LcdEn=0;return DBPort; }
//向LCD写入命令或数据************************************************************
#define LCD_COMMAND         0      // Command
#define LCD_DATA            1      // Data
#define LCD_CLEAR_SCREEN    0x01      // 清屏
#define LCD_HOMING          0x02      // 光标返回原点
void LCD_Write(bit style, unsigned char input)
{LcdEn=0;LcdRs=style;LcdRw=0;        _nop_();DBPort=input;  _nop_();//注意顺序
LcdEn=1;       _nop_();//注意顺序
LcdEn=0;       _nop_();LCD_Wait();
}//设置显示模式************************************************************
#define LCD_SHOW            0x04    //显示开
#define LCD_HIDE            0x00    //显示关
#define LCD_CURSOR          0x02    //显示光标
#define LCD_NO_CURSOR       0x00    //无光标
#define LCD_FLASH           0x01    //光标闪动
#define LCD_NO_FLASH        0x00    //光标不闪动
void LCD_SetDisplay(unsigned char DisplayMode)
{LCD_Write(LCD_COMMAND, 0x08|DisplayMode);  }
//设置输入模式************************************************************
#define LCD_AC_UP           0x02
#define LCD_AC_DOWN         0x00      // default
#define LCD_MOVE            0x01      // 画面可平移
#define LCD_NO_MOVE         0x00      //default
void LCD_SetInput(unsigned char InputMode)
{LCD_Write(LCD_COMMAND, 0x04|InputMode);}
//初始化LCD************************************************************
void LCD_Initial()
{LcdEn=0;LCD_Write(LCD_COMMAND,0x38);           //8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);    //开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);       //AC递增, 画面不动}
//液晶字符输入的位置************************
void GotoXY(unsigned char x, unsigned char y)
{if(y==0)LCD_Write(LCD_COMMAND,0x80|x);if(y==1)LCD_Write(LCD_COMMAND,0x80|(x-0x40));}
//将字符输出到液晶显示
void Print(unsigned char *str)
{while(*str!='\0'){LCD_Write(LCD_DATA,*str);str++;}}
/***********DS1302时钟部分子程序******************/
typedef struct __SYSTEMTIME__
{unsigned char Second;unsigned char Minute;unsigned char Hour;unsigned char Week;unsigned char Day;unsigned char Month;unsigned char  Year;unsigned char DateString[11];unsigned char TimeString[9];
}SYSTEMTIME;    //定义的时间类型
SYSTEMTIME CurrentTime;
#define AM(X)   X
#define PM(X)   (X+12)               // 转成24小时制
#define DS1302_SECOND   0x80          //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE   0x82
#define DS1302_HOUR     0x84
#define DS1302_WEEK     0x8A
#define DS1302_DAY      0x86
#define DS1302_MONTH    0x88
#define DS1302_YEAR     0x8C
void DS1302InputByte(unsigned char d)   //实时时钟写入一字节(内部函数)
{ unsigned char i;ACC = d; for(i=8; i>0; i--){DS1302_IO = ACC0;               //相当于汇编中的 RRCDS1302_CLK = 1; DS1302_CLK = 0; ACC = ACC >> 1; } }
unsigned char DS1302OutputByte(void)    //实时时钟读取一字节(内部函数)
{  unsigned char i; for(i=8; i>0; i--){ ACC = ACC >>1;                   //相当于汇编中的 RRC ACC7 = DS1302_IO; DS1302_CLK = 1;DS1302_CLK = 0; } return(ACC); }
void Write1302(unsigned char ucAddr, unsigned char ucDa)    //ucAddr: DS1302地址, ucData: 要写的数据
{ DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr);          // 地址,命令 DS1302InputByte(ucDa);          // 写1Byte数据DS1302_CLK = 1;DS1302_RST = 0;
} unsigned char Read1302(unsigned char ucAddr)  //读取DS1302某地址的数据
{ unsigned char ucData;DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr|0x01);        // 地址,命令 ucData = DS1302OutputByte();         // 读1Byte数据DS1302_CLK = 1;DS1302_RST = 0;return(ucData);}
void DS1302_GetTime(SYSTEMTIME *Time)  //获取时钟芯片的时钟数据到自定义的结构型数组
{unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MINUTE);Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_WEEK);Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); }
void DateToStr(SYSTEMTIME *Time)    //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{   if(hide_year<2)                 //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22{   Time->DateString[0] = '2';Time->DateString[1] = '0';   Time->DateString[2] = Time->Year/10 + '0';Time->DateString[3] = Time->Year%10 + '0';}else{  Time->DateString[0] = ' '; Time->DateString[1] = ' ';       Time->DateString[2] = ' '; Time->DateString[3] = ' ';}Time->DateString[4] = '/';if(hide_month<2){Time->DateString[5] = Time->Month/10 + '0';Time->DateString[6] = Time->Month%10 + '0';}else{ Time->DateString[5] = ' '; Time->DateString[6] = ' ';}Time->DateString[7] = '/';if(hide_day<2){Time->DateString[8] = Time->Day/10 + '0';Time->DateString[9] = Time->Day%10 + '0';}else{Time->DateString[8] = ' ';Time->DateString[9] = ' ';        }if(hide_week<2){week_value[0] = Time->Week%10 + '0';  //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示}else { week_value[0] = ' ';}week_value[1] = '\0';Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符}
void TimeToStr(SYSTEMTIME *Time)  //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{   if(hide_hour<2){ Time->TimeString[0] = Time->Hour/10 + '0';Time->TimeString[1] = Time->Hour%10 + '0';}else{ Time->TimeString[0] = ' ';Time->TimeString[1] = ' ';}Time->TimeString[2] = ':';
if(hide_min<2){ Time->TimeString[3] = Time->Minute/10 + '0';Time->TimeString[4] = Time->Minute%10 + '0';}else {Time->TimeString[3] = ' ';Time->TimeString[4] = ' '; }Time->TimeString[5] = ':';if(hide_sec<2){Time->TimeString[6] = Time->Second/10 + '0';Time->TimeString[7] = Time->Second%10 + '0';}else{Time->TimeString[6] = ' ';Time->TimeString[7] = ' '; }Time->DateString[8] = '\0';}
void Initial_DS1302(void)   //时钟芯片初始化
{   unsigned char Second=Read1302(DS1302_SECOND);if(Second&0x80)         //判断时钟芯片是否关闭    {Write1302(0x8e,0x00); //写入允许Write1302(0x8c,0x07); //以下写入初始化时间 日期:07/07/25.星期: 3. 时间: 23:59:55Write1302(0x88,0x07);Write1302(0x86,0x25);Write1302(0x8a,0x07);Write1302(0x84,0x23);Write1302(0x82,0x59);Write1302(0x80,0x55);Write1302(0x8e,0x80); //禁止写入}}
void Delay1ms(unsigned int count)
{unsigned int i,j;for(i=0;i<count;i++)for(j=0;j<120;j++);}
/*延时子程序*/
void mdelay(uint delay)
{   uint i;for(;delay>0;delay--){for(i=0;i<62;i++) //1ms延时.
{;}}}
void outkey()                    //跳出调整模式,返回默认显示
{ uchar Second;if(out==0)         { mdelay(8); count=0;hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;Second=Read1302(DS1302_SECOND);Write1302(0x8e,0x00); //写入允许Write1302(0x80,Second&0x7f);Write1302(0x8E,0x80);          //禁止写入done=0;           while(out==0); }}

void Upkey()//升序按键
{      Up=1;if(Up==0){mdelay(8);
switch(count)
{case 1:temp=Read1302(DS1302_SECOND);  //读取秒数temp=temp+1;  //秒数加1up_flag=1;    //数据调整后更新标志if((temp&0x7f)>0x59)   //超过59秒,清零temp=0;                                 break;case 2:
temp=Read1302(DS1302_MINUTE);  //读取分数temp=temp+1;  //分数加1
up_flag=1;
if(temp>0x59)          //超过59分,清零
temp=0;break;
case 3:temp=Read1302(DS1302_HOUR);  //读取小时数
temp=temp+1;  //小时数加1
up_flag=1;
if(temp>0x23)   //超过23小时,清零temp=0; break;case 4:temp=Read1302(DS1302_WEEK);  //读取星期数temp=temp+1;  //星期数加1up_flag=1;if(temp>0x7)  temp=1;break;case 5:temp=Read1302(DS1302_DAY);  //读取日数temp=temp+1;  //日数加1up_flag=1;if(temp>0x31)temp=1;break;case 6:temp=Read1302(DS1302_MONTH);  //读取月数temp=temp+1;  //月数加1up_flag=1;if(temp>0x12)temp=1;break;case 7:temp=Read1302(DS1302_YEAR);  //读取年数temp=temp+1;  //年数加1up_flag=1;if(temp>0x85)temp=0;break;default:break;}
while(Up==0); }}

void Downkey()//降序按键
{       Down=1;if(Down==0){ mdelay(8);switch(count){case 1:temp=Read1302(DS1302_SECOND);  //读取秒数temp=temp-1;             //秒数减1down_flag=1;       //数据调整后更新标志if(temp==0x7f)     //小于0秒,返回59秒temp=0x59;break;case 2:temp=Read1302(DS1302_MINUTE);  //读取分数temp=temp-1;  //分数减1down_flag=1;if(temp==-1)temp=0x59;      //小于0秒,返回59秒break;case 3:temp=Read1302(DS1302_HOUR);  //读取小时数temp=temp-1;  //小时数减1down_flag=1;if(temp==-1)temp=0x23;break;case 4:temp=Read1302(DS1302_WEEK);  //读取星期数temp=temp-1;  //星期数减1down_flag=1;if(temp==0)temp=0x7;;break;case 5:temp=Read1302(DS1302_DAY);  //读取日数temp=temp-1;  //日数减1down_flag=1;if(temp==0)temp=31;break;case 6:temp=Read1302(DS1302_MONTH);  //读取月数temp=temp-1;  //月数减1down_flag=1;if(temp==0)temp=12;break;case 7:temp=Read1302(DS1302_YEAR);  //读取年数temp=temp-1;  //年数减1down_flag=1;if(temp==-1)temp=0x85;break;default:break;}while(Down==0); }}
void Setkey()//模式选择按键
{Set=1;if(Set==0){ mdelay(8); count=count+1;    //Setkey按一次,count就加1done=1;            //进入调整模式while(Set==0);    }}
void keydone()//按键功能执行
{        uchar Second;if(flag==0)    //关闭时钟,停止计时{ Write1302(0x8e,0x00); //写入允许temp=Read1302(0x80);Write1302(0x80,temp|0x80);Write1302(0x8e,0x80); //禁止写入flag=1; }Setkey();                          //扫描模式切换按键switch(count){case 1:do                           //count=1,调整秒{ outkey();              //扫描跳出按钮Upkey();                //扫描加按钮Downkey();              //扫描减按钮if(up_flag==1||down_flag==1)  //数据更新,重新写入新的数据{Write1302(0x8e,0x00); //写入允许Write1302(0x80,temp|0x80); //写入新的秒数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_sec++;          //位闪计数if(hide_sec>3)hide_sec=0;show_time();         //液晶显示数据}while(count==2);break;  case 2:do                          //count=2,调整分{ hide_sec=0;outkey();Upkey();Downkey();if(temp>0x60)temp=0;if(up_flag==1||down_flag==1){ Write1302(0x8e,0x00); //写入允许Write1302(0x82,temp); //写入新的分数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_min++;if(hide_min>3)hide_min=0;show_time();}while(count==3);break;case 3:do                           //count=3,调整小时{ hide_min=0; outkey();Upkey();Downkey();if(up_flag==1||down_flag==1){ Write1302(0x8e,0x00); //写入允许Write1302(0x84,temp); //写入新的小时数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_hour++;if(hide_hour>3)hide_hour=0;show_time();}while(count==4);break;case 4:do                         //count=4,调整星期{ hide_hour=0; outkey();Upkey();Downkey();if(up_flag==1||down_flag==1){ Write1302(0x8e,0x00); //写入允许Write1302(0x8a,temp); //写入新的星期数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0;}hide_week++;if(hide_week>3)hide_week=0;show_time();}while(count==5);break;case 5:do                         //count=5,调整日{hide_week=0; outkey();Upkey();Downkey();if(up_flag==1||down_flag==1){Write1302(0x8e,0x00); //写入允许Write1302(0x86,temp); //写入新的日数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_day++;if(hide_day>3)hide_day=0;show_time();}while(count==6);break;case 6:do                           //count=6,调整月{ hide_day=0; outkey();Upkey();Downkey();if(up_flag==1||down_flag==1){ Write1302(0x8e,0x00); //写入允许Write1302(0x88,temp); //写入新的月数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_month++;if(hide_month>3)hide_month=0;show_time();}while(count==7);break;case 7:do                            //count=7,调整年{ hide_month=0; outkey();Upkey();Downkey();if(up_flag==1||down_flag==1){ Write1302(0x8e,0x00); //写入允许Write1302(0x8c,temp); //写入新的年数Write1302(0x8e,0x80); //禁止写入up_flag=0;down_flag=0; }hide_year++;if(hide_year>3)hide_year=0;show_time();}while(count==8);break;case 8: count=0;hide_year=0;  //count8, 跳出调整模式,返回默认显示状态Second=Read1302(DS1302_SECOND);Write1302(0x8e,0x00); //写入允许Write1302(0x80,Second&0x7f);Write1302(0x8E,0x80);          //禁止写入done=0;break; //count=7,开启中断,标志位置0并退出default:break; }}
void show_time()   //液晶显示程序
{ DS1302_GetTime(&CurrentTime);  //获取时钟芯片的时间数据TimeToStr(&CurrentTime);       //时间数据转换液晶字符DateToStr(&CurrentTime);       //日期数据转换液晶字符GotoXY(0,1);Print(CurrentTime.TimeString); //显示时间GotoXY(0,0);Print(CurrentTime.DateString); //显示日期GotoXY(15,0);Print(week_value);             //显示星期GotoXY(11,0);Print("Week");   //在液晶上显示 字母 weekDelay1ms(400);                 //扫描延时}
main()
{ flag=1;           //时钟停止标志LCD_Initial();    //液晶初始化Initial_DS1302(); //时钟芯片初始化up_flag=0;down_flag=0;done=0;           //进入默认液晶显示while(1){   while(done==1) keydone();    //进入调整模式while(done==0){   show_time();                //液晶显示数据flag=0;                  Setkey();                 //扫描各功能键}}}

基于AT89C52单片机的多功能万年历设计相关推荐

  1. 基于AT89C52单片机的温度检测报警设计

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87708680?spm=1001.20 ...

  2. 基于AT89C52单片机的无线温度监测设计

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87848530?spm=1001.20 ...

  3. 万年历设计单片机c语言,数字万年历设计(80c51单片机、时钟芯片ds1320).pdf

    数字万年历设计(80c51单片机.时钟芯片ds1320) 德州科技职业学院青岛校区 2006 级毕业论文 多功能数字万年历设计 摘 要 : 本设计是一种基于 AT89C52 单片机控制的数字万年历设计 ...

  4. 基于51单片机的数字电子钟万年历闰年判断闹钟设计

    基于51单片机的数字电子钟万年历闰年判断闹钟设计 视频 1 开发环境 2 功能说明介绍 3 仿真图 4 程序 5 原理图 6 视频讲解 7 设计报告 7.1 设计目的 7.2 概述 8 资料清单下载链 ...

  5. 基于AT89C52单片机的温湿度检测设计

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87704704 源码获取 主要内容: ...

  6. 基于AT89C52单片机的数字电压表设计

    一.系统组成及工作原理 1.1 系统组成 该基于AT89C52单片机的数字电压表设计由AT89C51单片机,ADC0809芯片(A/D转换器),LED数码管显示电路以及蜂鸣器电路等几部分组成.(用到得 ...

  7. 多功能数字钟c语言单片机PPT,基于STC89C52单片机的多功能数字钟的设计

    2010年第35期.本刊重稿.科技信囊 基于STC89C52单片机的多功能数字钟的设计 张开碧王浩曾勇斌 (重庆邮电大学自动化学院中国重庆400065) I摘要]本文主要介绍了数字钟的功能以及相应的硬 ...

  8. 基于at89c52单片机温湿度c语言,基于AT89C52单片机的温度监控报警系统的设计

    本系统由无线发射与接收模块.语音播报.温度采集.自动报警以及显示模块组成.实现功能:温度实时显示:可设定温度的上限和下限,当温度超过设定域值时发出声光报警信号:测量温度值可通过语音播报:通过射频模块完 ...

  9. 基于51单片机的DS12C887电子钟万年历带农历温度

    基于51单片机的DS12C887电子钟万年历( proteus仿真+程序+讲解视频) 仿真图proteus 7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0028 ...

最新文章

  1. Pycharm增加新安装Python的路径
  2. Hdu 1029 Ignatius and the Princess IV
  3. uml+oopc嵌入式c语言开发精讲_当前火爆的嵌入式领域,为什么选择C语言作为开发语言?了解一下...
  4. JavaScript 复习之 事件模型 和 Event对象
  5. 判断一个男人穷还是富,只看这几点!
  6. CoreText使用介绍
  7. SharePoint2013升级SP1后,运行配置向导报错:未注册sharepoint服务
  8. Codeforces Round #172 (Div. 2) C. Rectangle Puzzle 数学题几何
  9. verilog 学习记(如何编写assert)
  10. 瑞星2009网络版-服务器端安装和配置
  11. NYOJ833 - 取石子(七)
  12. springboot之提高maven的速度
  13. js 编写一道程序题输入长和宽之后点击按钮可弹出长方形面积。
  14. Unity3D内容加密保护
  15. 导出期刊对应格式的参考_3.2怎样按照某个期刊的格式要求生成文后的参考文献.PDF...
  16. 普林斯顿陈丹琦团队最新论文:受GPT-3启发,用小样本学习给语言模型做微调,性能最高提升30% | AI 日报...
  17. Topaz Adjust AI(HDR渲染滤镜) v1.0.0直装破解版
  18. 怎么彻底关闭wps热点 wps热点弹窗怎么永久关闭
  19. html中document和Document的区别。
  20. 再谈Qt实现Rasdial拨号问题(说说项目中遇到的问题和解决方案)

热门文章

  1. 一般物品识别易语言代码
  2. 柳永利计算机学院,师德之星-汤永利
  3. 两步完成ubuntu18.04 下安装腾讯官网提供的QQ for linux
  4. 问题--在matplotlib的散点图中如何给不同种类颜色的点加标签?
  5. 通达信的系统BOLL-M
  6. cs61a 课时笔记 递归对象和集合
  7. Abbexa 山羊 F(ab‘)2 IgG 同种型对照
  8. excel表格数字乱码怎么恢复正常
  9. 程序猿必备工具或者技术论坛推荐(收藏)
  10. ubuntu 16.04 出现failed to start session解决方法