10 51单片机之DS1302实时时钟

文章目录


1、前言

在前面的文章中介绍了51单片机之LED点阵屏,今天介绍单片机的LED点阵屏。


2、DS1302

2-1、芯片简介

DS1302是美国DALLAS公司推出的实时时钟电路。DS1302具有高性能、低功耗的特点,其芯片采用SPI三线接口与CPU进行同步通信 ,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能,工作电压宽达2.5~5.5V

2-2、RTC

RTC(Real Time Clock) :实时时钟,是一种集成电路,通常称为时钟芯片。

Figure1. Real Time Clock


3、DS1302 Datasheet

3-1、引脚定义及应用电路


Figure2. 管脚定义


Table1. 管脚定义

引脚名 作用
VCC2 主电源
VCC1 备用电源
GND 电源地
X1、X2 32.768KHz晶振
CE 芯片使能
IO 数据输入/输出
SCLK 串行时钟


Figure3. 典型工作电路


3-2、硬件电路

从下图可知 ,没有连接VCC1,则表示没有备用电源使用。下电后就不能计时。

Figure4. 原理图


3-3、内部结构框图


Figure5. 内部结构框图


3-4、寄存器定义


Figure6. 寄存器地址/定义


3-5、地址命令字

命令字启动每一次数据传输。MSB((位7)必须是逻辑1。如果是0,则禁止对DS1302写入。位6在逻辑0时规定为时钟/日历数据,逻辑1时为RAM数据 。位1至位5表示了输入输出的指定寄存器。LSB(位0)在逻辑0时为写操作(输出),逻辑1时为读操作(输入) 。命令字以LSB(位0)开始总是输入。

Figure7. 地址命令字


3-6、时序定义


Figure8. 时序定义


3-6-1、CE与时钟控制

所有数据传输开始驱动CE输入高电平。CE输入实现两个功能:第一,CE开启允许对地址/命令序列的移位寄存器进行读写的控制逻辑。第二,CE信号为单字节和多字节CE数据传输提供了终止的方法。

一个时钟周期是一系列的上升沿伴随随下降沿。要写入数据在时钟的上升沿数据必须有效,而且在下降沿要输出数据位。如果CE输入为低电平,则所有数据传输终止,并且I/O口成高阻抗状态。在上电时, CE必须为逻辑0直到VCC大于 2.0V时才变为逻辑1。同样,SCLK必须为逻辑0当CE变成逻辑1状态。

3-6-2、数据输入

输入写命令字的8个SCLK周期 后,接下来的8个SCLK周期的上升沿数据字节被输入,如不慎发生,多余的SCLK周期将被忽略,数据输入以位0开始。

3-6-3、数据输出

输入读命令字的8个SCLK周期后,随后的8个SCLK周期的下降沿,一个数据字节被输出 。注意第一个数据位的传送发生在命令字节被写完后的第一个下降沿。只要CE保持高电平,若不慎发生,多余的 SCLK周期会重新发送数据字节。此操作允许连续不断的脉冲串模式读取能力。并且I/O管脚在SCLK的每个上升沿被置为三态。数据输出从位 0开始。

3-6-4、脉冲串模式

通过寻址31(十进制)存储单元(地址/命令位1到位5为逻辑1),脉冲串模式可以指定时钟/日历或者RAM寄存器 。如前所述,位6指定时钟或者RAM,位0指定读写。时钟/日历寄存器的存储单元9至31和RAM寄存器的存储单元31无数技据存储能力。脉冲串模式下的读写从地址0的位0开始。在脉冲串模式下写时钟寄存器时,前8个寄存器必须按顺序写要发送的数据。然而,在脉冲串模式下写RAM时,不必写入要发送数据的所有31个字节。不管是否所有31个字节都被写入,每个写入字节都会被发送到RAM。

3-6-5、时钟/日历

读取适当的寄存器字节可以得到时间和日历信息。Figure6. 寄存器地址/定义说明了RTC寄存器。写入适当的寄存器字节可以设置或初始化时间和日历。时间和日历寄存器的内容是二进制编码的十进制(BCD)格式的。周中的天寄存器在午夜12点增加。周中的天相应的值可以由用户定义,但是必须是连续的(例如,如果1代表周日,那么2代表周一,等等。)。非法的时间和日期输入导致未定义操作。当读写时钟和日期寄存器时,第二(用户)缓存用来防1上内部寄存器更新时出错。读时钟和日期寄存器时,在CE上升沿用户缓存与内部寄存器同步。

每当秒寄存器被写入,递减计数电路被复位。写传输发生在CE的下降沿 。为了避免翻转问题,一旦递减计数电路复位,剩下的时间和日期寄存器必须不在一秒内被写入,DS1302可以工作在12小时制24小时制两种模式下。小时寄存器的位7定义为小时模式选择位。为高时是12小时制,12小时制模式下,位5是上午/下午位且高电平是下午。24小时制模式下,位5是第二10-小时位(20点-23点)。一旦12/24改变,小时数据必须被重新初始化。

3-6-6、时钟暂停标志

秒寄存器的位7被定义为时钟暂停标志。当此为置1时,时钟振荡器暂停,DS1302进入漏电流小于100nA的低功耗备用模式。当此为置0时,时钟开始。初始加电状态未定义。

3-6-7、写保护位

控制寄存器的位7是写保护位,前7位(位0至位6)被强制为0且读取时总是读0。在任何对时钟或RAM的写操作以前,位7必须为0 。当为高时,写保护位禁止任何寄存器的写操作。初始加电状态未定义,因此,在试图写器件之前应该清WP位


4、工程编码

4-1、基础功能


Figure9. Demo编码


c 复制代码
#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

c 复制代码
#include <REGX52.H>
#include "LCD1602.h"


//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

c 复制代码
#ifndef __DS1302_H__
#define __DS1302_H__

#define DS1302_SECONDS_ADDR 		0x80
#define DS1302_MINUTES_ADDR 		0x82
#define DS1302_HOUR_ADDR			0x84
#define DS1302_DATE_ADDR			0x86
#define DS1302_MONTH_ADDR			0x88
#define DS1302_DAY_ADDR				0x8A
#define DS1302_YEAR_ADDR			0x8C
#define DS1302_WP_ADDR				0x8E

#define DS1302_WP_DISABLE			0x00
#define DS1302_WP_ENABLE			0x01

#define DS1302_CURRENTTIME_LENGTH	7U

extern unsigned char DS1302_CurrentTime[DS1302_CURRENTTIME_LENGTH];

extern void DS1302_Init(void);
extern void DS1302_WriteByte(unsigned char WriteAddr, unsigned char Data);
extern unsigned char DS1302_ReadByte(unsigned char ReadAddr);
extern void DS1302_SetTime(void);
extern void DS1302_GetTime(void);
extern unsigned char DS1302_BCD2HEX(unsigned char InputData);
extern unsigned char DS1302_HEX2BCD(unsigned char InputData);


#endif

c 复制代码
#include <REGX52.H>
#include "DS1302.h"

sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
sbit DS1302_SCLK = P3^6;

unsigned char DS1302_CurrentTime[DS1302_CURRENTTIME_LENGTH] = {25,8,20,23,24,25,6};


void DS1302_Init(void)
{
	DS1302_CE = 0;
	DS1302_SCLK = 0;
}

void DS1302_WriteByte(unsigned char WriteAddr, unsigned char Data) /* 16 pulses */
{
	unsigned char i;
	
	DS1302_CE = 1; /* enable DS1302 */
	/* address command order */
	for(i = 0; i < 8; i++)
	{
		DS1302_IO = WriteAddr & (0x01 << i); /* Set bit0 */
		DS1302_SCLK = 1;	/* set rising edge to wirte bit */
		DS1302_SCLK = 0;	/* back to low level for next bit writing. */
	}
	
	for(i = 0; i < 8; i++)
	{
		DS1302_IO = Data & (0x01 << i); /* Set bit0 */
		DS1302_SCLK = 1;	/* set rising edge to wirte bit */
		DS1302_SCLK = 0;	/* back to low level for next bit writing. */
	}
	DS1302_CE = 0; /* disable DS1302 */
}

unsigned char DS1302_ReadByte(unsigned char ReadAddr) /* 15 pulses */
{
	unsigned char i;
	unsigned char Data = 0x00;
	
	ReadAddr |= 0x01; /* read ReadAddr lowest bit is 1. */

	DS1302_CE = 1; /* enable DS1302 */
	/* address command order */
	for(i = 0; i < 8; i++)
	{
		DS1302_IO = ReadAddr & (0x01 << i); /* Set bit0 */
		DS1302_SCLK = 0;	/* back to low level for next bit writing. */
		DS1302_SCLK = 1;	/* set rising edge to wirte bit */
	}
	for(i = 0; i < 8; i++)
	{
		DS1302_SCLK = 1; 	/* set rising edge to read bit starting */
		DS1302_SCLK = 0;	/* back to low level for bit reading. */
		if(DS1302_IO != 0)
		{
			Data |= (0x01 << i);
		}
	}
	DS1302_IO = 0;
	
	return Data;
}
	
void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP_ADDR, DS1302_WP_DISABLE); /* disable write protection */
	
	DS1302_WriteByte(DS1302_YEAR_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[0]));
	DS1302_WriteByte(DS1302_MONTH_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[1]));
	DS1302_WriteByte(DS1302_DATE_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[2]));
	DS1302_WriteByte(DS1302_HOUR_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[3]));
	DS1302_WriteByte(DS1302_MINUTES_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[4]));
	DS1302_WriteByte(DS1302_SECONDS_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[5]));
	DS1302_WriteByte(DS1302_DAY_ADDR, DS1302_BCD2HEX(DS1302_CurrentTime[6]));
	
	DS1302_WriteByte(DS1302_WP_ADDR, DS1302_WP_ENABLE); /* enable write protection */ 	
}

void DS1302_GetTime(void)
{
	DS1302_CurrentTime[0] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_YEAR_ADDR));
	DS1302_CurrentTime[1] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_MONTH_ADDR));
	DS1302_CurrentTime[2] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_DATE_ADDR));
	DS1302_CurrentTime[3] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_HOUR_ADDR));
	DS1302_CurrentTime[4] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_MINUTES_ADDR));
	DS1302_CurrentTime[5] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_SECONDS_ADDR));
	DS1302_CurrentTime[6] = DS1302_HEX2BCD(DS1302_ReadByte(DS1302_DAY_ADDR));
}
	

unsigned char DS1302_BCD2HEX(unsigned char InputData)
{
	return (InputData / 10 * 16 + InputData % 10);
}
	
unsigned char DS1302_HEX2BCD(unsigned char InputData)
{
	return (InputData / 16 * 10 + InputData % 16);
}

c 复制代码
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"


void main()
{
	LCD_Init();
	DS1302_Init();
	DS1302_SetTime();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");	
	while(1)
	{
		DS1302_GetTime();
		LCD_ShowNum(1,1,DS1302_CurrentTime[0],2);
		LCD_ShowNum(1,4,DS1302_CurrentTime[1],2);
		LCD_ShowNum(1,7,DS1302_CurrentTime[2],2);
		LCD_ShowNum(2,1,DS1302_CurrentTime[3],2);
		LCD_ShowNum(2,4,DS1302_CurrentTime[4],2);
		LCD_ShowNum(2,7,DS1302_CurrentTime[5],2);		
	}
}

4-2、按键操作


Figure10. 按键调节时间编码


c 复制代码
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"

unsigned char KeyNum;
unsigned char Mode;
unsigned char TimeSetSelect;
unsigned char TimeFlashFlag;

void TimeShow(void)
{
	DS1302_GetTime();
	LCD_ShowNum(1,1,DS1302_CurrentTime[0],2);
	LCD_ShowNum(1,4,DS1302_CurrentTime[1],2);
	LCD_ShowNum(1,7,DS1302_CurrentTime[2],2);
	LCD_ShowNum(2,1,DS1302_CurrentTime[3],2);
	LCD_ShowNum(2,4,DS1302_CurrentTime[4],2);
	LCD_ShowNum(2,7,DS1302_CurrentTime[5],2);	
}

void TimeSet(void)
{
	if(KeyNum == 2)
	{
		TimeSetSelect++; 
		TimeSetSelect %= 6; /* Out of range to clear. */
	}
	if(KeyNum == 3)
	{
		DS1302_CurrentTime[TimeSetSelect]++;
		if(DS1302_CurrentTime[0] > 99) /* Year */
		{
			DS1302_CurrentTime[0] == 0;
		}
		if(DS1302_CurrentTime[1] > 12) /* Month */
		{
			DS1302_CurrentTime[1] == 1;
		}
		
		if((DS1302_CurrentTime[1] == 1) || (DS1302_CurrentTime[1] == 3) || (DS1302_CurrentTime[1] == 5) || (DS1302_CurrentTime[1] == 7)
			|| (DS1302_CurrentTime[1] == 8) || (DS1302_CurrentTime[1] == 10) || (DS1302_CurrentTime[1] == 12))
		{
			if(DS1302_CurrentTime[1] > 31) /* Day */
			{
				DS1302_CurrentTime[2] == 1;
			}
		}
		else if ((DS1302_CurrentTime[1] == 4) || (DS1302_CurrentTime[1] == 6) || (DS1302_CurrentTime[1] == 9) || (DS1302_CurrentTime[1] == 11))
		{
			if(DS1302_CurrentTime[1] > 30) /* Day */
			{
				DS1302_CurrentTime[2] == 1;
			}
		}
		else if(DS1302_CurrentTime[1] == 2)
		{
			if(DS1302_CurrentTime[0] % 4 ==0 )
			{
				if(DS1302_CurrentTime[1] > 29) /* Day */
				{
					DS1302_CurrentTime[2] == 1;
				}
			}
			else
			{
				if(DS1302_CurrentTime[1] > 28) /* Day */
				{
					DS1302_CurrentTime[2] == 1;
				}
			}				
		}

		if(DS1302_CurrentTime[3] > 23)	/* Hour */
		{
			DS1302_CurrentTime[3] == 0;
		}
		if(DS1302_CurrentTime[4] > 59)	/* Mins */
		{
			DS1302_CurrentTime[4] == 0;
		}
		if(DS1302_CurrentTime[5] > 59)	/* Seconds */
		{
			DS1302_CurrentTime[5] == 0;
		}
	}
	if(KeyNum == 4)
	{
		DS1302_CurrentTime[TimeSetSelect]--;
		if(DS1302_CurrentTime[0] < 0) /* Year */
		{
			DS1302_CurrentTime[0] == 99;
		}
		if(DS1302_CurrentTime[1] < 1) /* Month */
		{
			DS1302_CurrentTime[1] == 12;
		}
		
		if((DS1302_CurrentTime[1] == 1) || (DS1302_CurrentTime[1] == 3) || (DS1302_CurrentTime[1] == 5) || (DS1302_CurrentTime[1] == 7)
			|| (DS1302_CurrentTime[1] == 8) || (DS1302_CurrentTime[1] == 10) || (DS1302_CurrentTime[1] == 12))
		{
			if(DS1302_CurrentTime[1] < 1) /* Day */
			{
				DS1302_CurrentTime[2] == 31;
			}
			else if(DS1302_CurrentTime[1] > 31) /* Day */
			{
				DS1302_CurrentTime[2] == 1;
			}
		}
		else if ((DS1302_CurrentTime[1] == 4) || (DS1302_CurrentTime[1] == 6) || (DS1302_CurrentTime[1] == 9) || (DS1302_CurrentTime[1] == 11))
		{
			if(DS1302_CurrentTime[1] < 1) /* Day */
			{
				DS1302_CurrentTime[2] == 30;
			}
			else if(DS1302_CurrentTime[1] > 30) /* Day */
			{
				DS1302_CurrentTime[2] == 1;
			}
		}
		else if(DS1302_CurrentTime[1] == 2)
		{
			if(DS1302_CurrentTime[0] % 4 ==0 )
			{
				if(DS1302_CurrentTime[1] < 1) /* Day */
				{
					DS1302_CurrentTime[2] == 29;
				}
				else if(DS1302_CurrentTime[1] > 29) /* Day */
				{
					DS1302_CurrentTime[2] == 1;
				}
			}
			else
			{
				if(DS1302_CurrentTime[1] < 1) /* Day */
				{
					DS1302_CurrentTime[2] == 28;
				}
				else if(DS1302_CurrentTime[1] > 28) /* Day */
				{
					DS1302_CurrentTime[2] == 1;
				}
			}				
		}

		if(DS1302_CurrentTime[3] < 0)	/* Hour */
		{
			DS1302_CurrentTime[3] == 23;
		}
		if(DS1302_CurrentTime[4] < 0)	/* Mins */
		{
			DS1302_CurrentTime[4] == 59;
		}
		if(DS1302_CurrentTime[5] < 0)	/* Seconds */
		{
			DS1302_CurrentTime[5] == 59;
		}
	}
	
	if((TimeSetSelect == 0) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(1,1,"  ");
	}
	else
	{
		LCD_ShowNum(1,1,DS1302_CurrentTime[0],2);
	}
	
	if((TimeSetSelect == 1) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(1,4,"  ");
	}
	else
	{
		LCD_ShowNum(1,4,DS1302_CurrentTime[1],2);
	}
	
	if((TimeSetSelect == 2) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(1,7,"  ");
	}
	else
	{
		LCD_ShowNum(1,7,DS1302_CurrentTime[2],2);
	}
	
	if((TimeSetSelect == 3) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(2,1,"  ");
	}
	else
	{
		LCD_ShowNum(2,1,DS1302_CurrentTime[3],2);
	}
	
	if((TimeSetSelect == 4) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(2,4,"  ");
	}
	else
	{
		LCD_ShowNum(2,4,DS1302_CurrentTime[4],2);
	}
	
	if((TimeSetSelect == 5) && (TimeFlashFlag == 1))
	{
		LCD_ShowString(2,7,"  ");
	}
	else
	{
		LCD_ShowNum(2,7,DS1302_CurrentTime[5],2);
	}

	LCD_ShowNum(2,10,TimeSetSelect,2);
	LCD_ShowNum(2,13,TimeFlashFlag,2);
}

void main(void)
{
	LCD_Init();
	DS1302_Init();
	Timer0_Init();
	
	DS1302_SetTime();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");	
	while(1)
	{	
		KeyNum = Key();
		if(KeyNum)
		{
			if(Mode == 0)
			{
				Mode = 1;
			}
			else if(Mode == 1)
			{
				Mode = 0;
				DS1302_SetTime();
			}
		}
		switch(Mode)
		{
			case 0:TimeShow();break;
			case 1:TimeSet();break;
		}
	}
}

void Timer0_Isr(void) interrupt 1
{
	static unsigned int T0Cnt;
	/* Inhibit timer0 count overflow. */
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	T0Cnt++;
	if(T0Cnt >= 500) //1s = 1000ms
	{
		T0Cnt = 0;
		TimeFlashFlag = !TimeFlashFlag; /* 0 or 1 */
	}
}

4-3、实验结果


Figure11. 按键调节时间实验结果


参考资料

  1. DS1302实时时钟
  2. 51单片机入门教程-2020版 程序全程纯手打 从零开始入门
相关推荐
CC呢14 小时前
基于单片机颜色识别分拣系统设计
单片机·嵌入式硬件·单片机设计
CC呢15 小时前
基于单片机雏鸡孵化恒温系统/孵化环境检测系统设计
单片机·嵌入式硬件·单片机设计
点灯小铭17 小时前
基于STM32单片机智能家居声音人体防盗GSM短信报警系统设计
stm32·单片机·毕业设计·智能家居·课程设计
清风66666617 小时前
基于STM32单片机智能家居wifi远程监控系统机智云app设计
stm32·单片机·毕业设计·智能家居·课程设计
Shang1809893572617 小时前
HI3519DRFCV500/HI3519DV500海思核心板IPC算力2.5T图像ISP超高清智能视觉应用提供SDK软件开发包
人工智能·嵌入式硬件·fpga开发·智能视频处理器·hi3519drfcv500·hi3519dv500
iotxiaohu1 天前
MCU上跑AI—实时目标检测算法探索
人工智能·单片机·yolo·目标检测·ai
亿道电子Emdoor1 天前
【ARM】MDK工程切换高版本的编译器后出现error: A1167E\A1159E\A1137E\A1517E\A1150E报错
stm32·单片机·嵌入式硬件
DS小龙哥1 天前
基于STM32与华为云联动的智能电动车充电桩管理系统
stm32·嵌入式硬件·华为云
lingzhilab1 天前
零知开源——STM32红外通信YS-IRTM红外编解码器集成灯控与显示系统
stm32·单片机·嵌入式硬件
会编程的果子君1 天前
平衡车-ADC采集电池电压
单片机·嵌入式硬件