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

news2024/11/26 21:47:54

点击链接获取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;           	//相当于汇编中的 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();				 //扫描各功能键
 		}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/598470.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BitLocker加密卷“恢复密钥(数字密码)”提取还原

BitLocker是微软Windows自带的用于加密磁盘分卷的技术。 通常&#xff0c;解开后的加密卷通过Windows自带的命令工具“manage-bde”可以查看其恢复密钥串&#xff0c;如下图所示&#xff1a; 如图&#xff0c;这里的数字密码下面的一长串字符串即是下面要提取恢复密钥。 在计…

IMA/EVM完整性检测代码分析

IMA/EVM完整性检测 IMA&#xff08;Integrity Measurement Architecture&#xff09;是一个内核安全子系统&#xff0c;用于检测文件或数据的完整性和安全性。IMA的hook机制指的是内核接口钩子&#xff08;kernel interface hooks&#xff09;&#xff0c;用于向IMA注册和实现…

第三章 部署Web及WDS服务

♥️作者介绍&#xff1a;奇妙的大歪 ♥️个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01; ♥️个人简介&#xff1a;云计算网络运维专业人员 目录 一.什么是web 1.www(world wide web)万维网 世界 维度 2.www服务软件 3.info…

ElementUI-Form表单二次封装

一、Form组件二次封装考虑组件构成&#xff1a; form组件&#xff1a;input text passworldselectcheckboxradio文本域日期 二、实现Form表单的二次封装&#xff1a; 1. 分析出对应的位置 开始抽离组件 2. 如果需要产生多个form表单&#xff0c;则需要产生多个el-form-item…

学习路之gis--百度离线地图下载制作

在有些情况下需要使用地图&#xff0c;但又不能访问外网&#xff0c;这时你需要一个离线地图。本文介绍如何制作百度离线地图。 下面将介绍如何实现一个离线版百度地图&#xff1a; 1. 下载百度地图瓦片 下载网址&#xff1a;望远网-百度地图下载 首先需选择下载地图瓦片的样式…

BUG: scheduling while atomic: fpv_cams/605/0x00010001

IIO框架下IMU驱动的接口在定时器中断内调用报错&#xff0c;因调用IO读定时间较长会导致睡眠的发生&#xff0c;因为内核总是崩。 尝试了几种解决方法&#xff1a; 1.在IIO框架里&#xff0c;使用 spidev 的接口来读写&#xff0c;错误依旧&#xff1b; 2.去掉IIO框架&#x…

香橙派One(全志H3芯片)编译烧写U-boot、Linux内核zImage、dtb

一、编译烧写u-boot 1.1 源码和工具下载&#xff1a; 香橙派提供了u-boot源码和交叉编译链工具&#xff1a; &#xff08;1&#xff09;u-boot&#xff08;2020.04&#xff09;下载地址&#xff1a;https://github.com/orangepi-xunlong/u-boot-orangepi &#xff08;2&#…

MyBatis - MyBatis Generator

文章目录 1.什么是 MyBatis Generator2.使用 MyBatis Generator2.1 导入依赖2.2 application 配置2.3 添加 Java 配置2.4 MBG 配置2.5 生成代码2.6 基本 CRUD 操作 3.进阶使用 MyBatis Generator3.1 基于条件的 CRUD3.2 子查询、Group 与 Join 查询3.3 一对一查询、一对多查询 …

ANSYS Workbench中的网格优化方法

自 50 年代后期以来&#xff0c;有限元法 (FEM) 已被用作解决工程问题的强大工具。当时的计算是手工进行的&#xff0c;该方法是基于力的&#xff0c;而不是我们今天使用的基于位移的方法。由于计算机工业的进步&#xff0c;已经开发出各种有限元商业软件。Ansys 可以被认为是全…

Nginx网站部署

Nginx网站部署 一、访问状态统计配置二、基于授权的访问控制三、基于客户端的访问控制四、基于域名的 Nginx 虚拟主机五、基于IP 的 Nginx 虚拟主机六、基于端口的 Nginx 虚拟主机 一、访问状态统计配置 1.先使用命令/usr/local/nginx/sbin/nginx -V 查看已安装的 Nginx 是否包…

常用抓包工具使用-wireshark使用(二)

常用抓包工具使用-wireshark使用&#xff08;二&#xff09; 文章目录 常用抓包工具使用-wireshark使用&#xff08;二&#xff09;前言一、wireshark安装1.1 windows安装1.2 mac安装 二、wireshark抓包和过滤2.1 打开Wireshark2.2 选择网络接口&#xff1a;2.3 wireshark抓包页…

【Nginx 网络服务】

目录 一、Nginx和Apache的优点和缺点二、编译安装Nginx服务1.关闭防火墙&#xff0c;将安装nginx所需软件包传到/opt目录下2.安装依赖包3.创建运行用户、组4.编译安装Nginx5.检查、启动、重启、停止 nqinx服务 三、认识Nginx服务的主配置文件 nginx.conf1、系统文件支持数量2&a…

商场内怎么导航?商场导航图怎么画?

商场内怎么导航&#xff1f;大型购物商场是目前一二线城市最常见的购物场所&#xff0c;占地面积较大&#xff0c;布局错综复杂&#xff0c;商品比较齐全&#xff0c;如果没有商场地图导航&#xff0c;会导致新顾客难以找到想要的商品&#xff0c;那么大型购物商场商场地图怎么…

索引特性.

目录 没有索引&#xff0c;可能会有什么问题认识磁盘MySQL与存储先来研究一下磁盘在看看磁盘中一个盘片扇区定位扇区结论磁盘随机访问(Random Access)与连续访问(Sequential Access) MySQL 与磁盘交互基本单位建立共识索引的理解建立测试表插入多条记录查看插入结果中断一下---…

打跑个人开源转角的“拦路虎”——我的开源之路

从参与Apache 开源项目&#xff0c;到凭借业务需求独自开发个人开源项目&#xff1b;从项目开源出来无人问津到至今500star&#xff0c;多个企业级用户&#xff0c;在开源过程中&#xff0c;我也从走过低谷&#xff0c;一度想过放弃&#xff0c;但仍然选择坚持至今日。 这一路…

Data Distillation: A Survey

本文是蒸馏学习综述系列的第二篇文章&#xff0c;Data Distillation: A Survey的一个翻译 数据蒸馏&#xff1a;综述 摘要1 引言2 数据蒸馏框架2.1 元模型匹配的数据蒸馏2.2 梯度匹配的数据蒸馏2.3 轨迹匹配的数据蒸馏2.4 分布匹配的数据蒸馏2.5 因式分解的数据蒸馏 3 数据模态…

深度探索:Qt CMake工程编译后的自动打包策略

深度探索&#xff1a;Qt CMake工程编译后的自动打包策略 1. 引言&#xff08;Introduction&#xff09;1.1 Qt和CMake的基本概念&#xff08;Basic Concepts of Qt and CMake&#xff09;1.2 自动打包的重要性&#xff08;Importance of Automatic Packaging&#xff09; 2. Qt…

ELK +Filebeat日志分析系统

一、 ELK日志分析系统概述 1、ELK简介 ELK是三个开源软件的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件。新增了一个FileBeat&#xff0c;它是一个轻量级的日志收集处理工具(Agent)&#xff0c;Filebeat占用资源少&#xff0c…

我是如何将家里的台式机改成服务器的

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 文章目录 前言准备工作电脑宽带公网ip光猫给成桥接方式设置路由器设置服务器静态ip地址前言 搞研发的伙伴们,都知道服务器是个什么东西,以及服务器的作用、费用,相信都一清二楚。一般,我们用服务器说的简单点就是放一…

自动驾驶车载MCU开发修炼秘籍

目录 车载MCU开发修炼秘籍1、恩智浦 S32K1XX系列2、英飞凌 AURIX TC3XX3、嵌入式实时操作系统-FreeRTOS4、车载实时操作系统-AUTOSAR 车载MCU开发修炼秘籍 1、恩智浦 S32K1XX系列 S32K14X学习笔记&#xff08;一&#xff09;–S32K汽车MCU资源总结 S32K14X学习笔记&#xff1a…