基于AT89C52单片机的多功能万年历设计

这篇具有很好参考价值的文章主要介绍了基于AT89C52单片机的多功能万年历设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

点击链接获取Keil源码与Project Backups仿真图:
https://download.csdn.net/download/qq_64505944/87853675
基于AT89C52单片机的多功能万年历设计

源码获取
目 录

摘 要 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始终是输入端。
基于AT89C52单片机的多功能万年历设计

            图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显示模块,和最小系统上的连线一样,无需修改。
基于AT89C52单片机的多功能万年历设计

图-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

附录一:系统电路图
基于AT89C52单片机的多功能万年历设计

附录二:系统程序清单文章来源地址https://www.toymoban.com/news/detail-467839.html

#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;           	//相当于汇编中的 RRC
        DS1302_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:55
	Write1302(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;  //秒数加1
 up_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;  //星期数加1
                                  up_flag=1;
								  if(temp>0x7)  
								  temp=1;
								  break;
				           case 5:
                                  temp=Read1302(DS1302_DAY);  //读取日数
								  temp=temp+1;  //日数加1
                                  up_flag=1;
								  if(temp>0x31)
								  temp=1;
								  break;
				           case 6:
                                  temp=Read1302(DS1302_MONTH);  //读取月数
								  temp=temp+1;  //月数加1
                                  up_flag=1;
								  if(temp>0x12)
								  temp=1;
								  break;
				           case 7:
                                  temp=Read1302(DS1302_YEAR);  //读取年数
								  temp=temp+1;  //年数加1
                                  up_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;			  //秒数减1
                                  down_flag=1;       //数据调整后更新标志
								  if(temp==0x7f)     //小于0秒,返回59秒
								  temp=0x59;
								  break;
				           case 2:
                                  temp=Read1302(DS1302_MINUTE);  //读取分数
								  temp=temp-1;  //分数减1
                                  down_flag=1;
								  if(temp==-1)
								  temp=0x59;      //小于0秒,返回59秒
								  break;
				           case 3:
                                  temp=Read1302(DS1302_HOUR);  //读取小时数
								  temp=temp-1;  //小时数减1
                                  down_flag=1;
								  if(temp==-1)
								  temp=0x23;
								  break;
				           case 4:
                                  temp=Read1302(DS1302_WEEK);  //读取星期数
								  temp=temp-1;  //星期数减1
                                  down_flag=1;
								  if(temp==0)
								  temp=0x7;;
								  break;
				           case 5:
                                  temp=Read1302(DS1302_DAY);  //读取日数
								  temp=temp-1;  //日数减1
                                  down_flag=1;
								  if(temp==0)
								  temp=31;
								  break;
				           case 6:
                                  temp=Read1302(DS1302_MONTH);  //读取月数
								  temp=temp-1;  //月数减1
                                  down_flag=1;
								  if(temp==0)
								  temp=12;
								  break;
				           case 7:
                                  temp=Read1302(DS1302_YEAR);  //读取年数
								  temp=temp-1;  //年数减1
                                  down_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就加1
		   done=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");	//在液晶上显示 字母 week
  Delay1ms(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单片机的多功能万年历设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于AT89C52单片机的计算器设计与仿真

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/88637995?spm=1001.2014.3001.5503 源码获取 B 源码+仿真图+课程设计+51 摘 要 计算器一般是指“电子计算器”,能进行数学运算的手持机器,拥有集成电路芯片,结构简单,功能较弱,但由于它使用方便、操

    2024年01月16日
    浏览(66)
  • 基于AT89C52单片机的简易电子琴设计与仿真

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87853299?spm=1001.2014.3001.5503 源码获取 主要内容: 本设计是基于51系列的单片机进行的设计,利用所给键盘的八个键,能够发出8个不同的音调,并且要求按下按键发声,松开延时一段时间停止,中间

    2024年02月04日
    浏览(50)
  • 【AT89C52单片机项目】数字密码锁设计

    实验目的 使用单片机设计数字密码锁。 实验仪器 一套STC89C52RC开发板套件,包括STC89C52RC开发板,以及USB烧录线。 设计要求 1、有设置密码、开锁工作模式; 2、可以每次都设置密码,也可以设置一次密码多次使用。 实验原理 本实验所需要的主要硬件电路介绍 1)、矩阵按键

    2024年02月07日
    浏览(43)
  • 【AT89C52单片机项目】音乐播放器的设计

    实验目的 用51系列单片机设计一个可以切歌的音乐播放器。 实验仪器 AT89C52单片机。 音乐播放模块。 设计要求 采用重装定时器计数方式1的初值来实现发出不同频率的声音,通过控制延时长度来实现不同的节拍,之后将音乐数据表填入,即可实现音乐播放。 可通过功能按键

    2024年02月16日
    浏览(87)
  • 利用AT89C52单片机实现数码管的静态与动态显示

            资源work1和work2(完整工程文件在笔者本人主页的资源中,免费欢迎下载)分别完成下面两个任务:         1、单片机接矩阵键盘和2个静态数码管,自行设计硬件电路,利用汇编语言,要求将按键值(0~15)在数码管显示。         主要代码: ……      

    2024年02月02日
    浏览(48)
  • 【嵌入式开发-8051】详细:基于AT89C52单片机设计的温控风扇(Proteus仿真设计-含设计原理图、程序源码)

    1、本设计是基于AT89C51/52单片机为核心的温控风扇系统,使用Proteus进行仿真分析。 2、由于上传后图片压缩,可以私信联系获取清晰图片。 3、本次为本人结课设计,整体比较简单,如有疑问欢迎大家交流讨论!   目录 【嵌入式开发-8051】详细:基于AT89C52单片机设计的温控风

    2024年02月07日
    浏览(60)
  • 基于STC89C52单片机的温度控制系统设计方案与软硬件实现

    目录 摘要 I Abstract II 第一章 前言 1 1.1 温度控制系统设计发展历史及意义 1.2 温度控制系统的目的 1.3 温度控制系统完成的功能 第二章 总体设计方案 2.1 方案一 2.2 方案二 3.1 DS18B20简介 3.1.1DS18B20封装与引脚 3.1.2 DS18B20的简单性能 3.2 DS18B20的工作原理 3.3 DS18B20的测温原理 3.3.1 测

    2024年02月12日
    浏览(44)
  • 什么是STC89C52单片机

    STC89C52是一个低功耗,高性能CMOS 8位单片机,片内含8k Bytes ISP(In-system programmable)的可反复擦写10000次的Flash只读程序存储器,器件采用ATMEL公司的高密度、非易失性存储技术制造,兼容标准MCS-51指令系统及80C51引脚结构[1],芯片内集成了通用8位中央处理器和ISP Flash存储单元,功

    2024年02月13日
    浏览(46)
  • 89C52RC普中单片机

    资料下载 普中科技--各型号产品资料下载链接 - STM8单片机 - 普中开源电子分享网 - Powered by Discuz! (prechin.net) 2023-06-28  1.开发板    2.软件 keil,stc-isp。 1.点亮led 89C52RC芯片LED模块是P2口。       2.led1一秒闪烁  3.LED流水灯  4.独立按键控制led亮灭(按下key1亮,松手灭) 5.独立按键

    2024年02月11日
    浏览(56)
  • 基于AT89S52单片机的多功能电子万年历

    基于AT89S52单片机的多功能电子万年历的硬件结构和软硬件设计方法。本设计由数据显示模块、温度采集模块、时间处理模块和调整设置模块四个模块组成。系统以AT89S52单片机为控制器,以串行时钟日历芯片DS1302记录日历和时间,它可以对年、月、日、时、分、秒进行计时,

    2024年02月03日
    浏览(82)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包