MCU-51:单片机实时时钟

news2024/12/26 23:32:47

目录

  • 一、什么是时钟
    • 1.1 实时时钟
    • 1.2 时序
  • 二、DS1302实时时钟
    • 2.1 DS1302介绍
    • 2.2 引脚定义和应用电路
  • 三、代码演示
    • 3.1 数字时钟
    • 3.2 DS1302可调时钟
  • 注意:一定要看

一、什么是时钟

1.1 实时时钟

real time clock,真实时间,就是所谓的xx年x月x日x时x分x秒星期x
RTC是SoC中一个内部外设,RTC有自己独立的晶振提供RTC时钟源,内部有一些寄存器用来记录时间(年月日时分秒星期)。一般情况下为了在系统关机时时间仍然在走,还会给RTC提供一个电池供电。
RTC在早期的单片机应用中是外置的,后来因为这个功能比较基础比较常用,比较高端的单片机或者SOC就将RTC直接内置了。

1.2 时序

时序:字面意思,时序就是时间顺序,实际上在通信中时序就是通信线上按照时间顺序发生的电平变化,以及这些变化对通信的意义就叫时序。
注意,时序的横轴的时间,所以对于字节是先发低位还是先发高位,可以看谁在前谁在后,在前的先发,在后的后发。

二、DS1302实时时钟

2.1 DS1302介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能

在这里插入图片描述

2.2 引脚定义和应用电路

在这里插入图片描述
DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:
RST 复位
I/O 数据线
SCLK 串行时钟

Vcc2为主电源,VCC1为后备电源。
X1和X2是振荡源,外接32.768kHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据传送的方法。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。

I/O为串行数据输入输出端(双向)。SCLK为时钟输入端。
1、时钟操作可通过AM/PM 指示决定采用24 或12 小时格式;
2、DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关;
3、寄存器中存放的数据位为BCD码形式;
操作DS1302的大致过程,就是将各种数据写入DS1302的寄存器,以设置它当前的时间和格式。然后使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简易电子钟。

DS1302的寄存器样式如下,我们看到:
第7 位永远都是1;
第6 位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;
第5位到第1位,为RAM或者寄存器的地址;
最低位,高电平表示RD:即下一步操作将要“读”;低电平表示W:即下一步操作将要“写”。
在这里插入图片描述
SEC:秒寄存器,注意具体右边内容:低四位为SEC,高的次三位为10SEC,最高位CH为DS1302 的运行标志,当CH=0时,DS1302内部时钟运行,反之CH=1时停止;

MIN:分寄存器;

HR:时寄存器,最高位为12/24 小时的格式选择位,该位为1时表示12小时格式。当设置为12小时显示格式时,第5位的高电平表示下午(PM);而当设置为24 小时格式时,第5位为具体的时间数据。

DATE:日寄存器;

MONTH:月寄存器;

DAY:周寄存器,注意一周只有7天,所以该寄存器只有低三位有效,周一到周日;

YEAR:年寄存器;

CONTROL:写保护寄存器,当该寄存器最高位WP为1时,DS1302 只读不写,所以要在往DS1302 写数据之前确保WP为0;

TRICKLE CHARGE REGISTER:涓细电流充电设置寄存器,我们知道,当DS1302掉电时,可以马上调用外部电源保护时间数据。该寄存器就是配置备用电源的充电选项的。其中高四位(4个TCS)只有在1010 的情况下才能使用充电选项;低四位的情况,与DS1302内部电路有关。

CLOCK BURST:批量读写操作设置寄存器,设置该寄存器后,可以对DS1302的各个寄存器进行连续写入。DS1302的另外一种读写方式。笔者还没用过,感兴趣的朋友可以尝试。

寄存器定义表:
在这里插入图片描述
单字节读写时序图如下:
在这里插入图片描述

三、代码演示

3.1 数字时钟

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"

unsigned char Second,Minute;

void main()
{ 
	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");
	
	
	DS1302_WriteByte(0x8e,0x00);//关闭写保护
	
	DS1302_SetTime();

	
        while(1)
        {
					DS1302_ReadTime();
	        LCD_ShowNum(1,1,DS1302_Time[0],2);
					LCD_ShowNum(1,4,DS1302_Time[1],2);
					LCD_ShowNum(1,7,DS1302_Time[2],2);
					LCD_ShowNum(2,1,DS1302_Time[3],2);
					LCD_ShowNum(2,4,DS1302_Time[4],2);
					LCD_ShowNum(2,7,DS1302_Time[5],2);
        
         }
}

DS1302.c

#include <REGX52.H>

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

#define DS1302_SECOND  0x80
#define DS1302_MINUTE  0x82
#define DS1302_HOUR  0x84
#define DS1302_DATE 0x86
#define DS1302_MONTHE  0x88
#define DS1302_DAY  0x8A
#define DS1302_YEAR  0x8C
#define DS1302_WP  0x8E

unsigned char DS1302_Time[]={22,12,29,16,35,55,6};

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

void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;

	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

unsigned DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command=Command|0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	}
	
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;
	DS1302_SCLK=0;
	if(DS1302_IO)
	{
		Data=Data|(0x01<<i);
	}
	}
	DS1302_CE=0;
	DS1302_IO=0;
	return Data;
}

void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTHE,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);
}

void DS1302_ReadTime(void)
{
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MONTHE);
	DS1302_Time[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
}

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

extern unsigned char DS1302_Time[];

void DS1302_Init();
void DS1302_WriteByte(unsigned char Command,Data);
unsigned DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);

#endif

LCD1602.c

#include <REGX52.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');
	}
}

LCD1602.h

#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

3.2 DS1302可调时钟

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "key.h"
#include "Timer0.h"

unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;

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

void TimeSet(void)
{
	if(KeyNum==2)
	{
		TimeSetSelect++;
		TimeSetSelect=TimeSetSelect%6;//越界清零
	}
	if(KeyNum==3)
	{
		DS1302_Time[TimeSetSelect]++;
		if(DS1302_Time[0]>99)
		{
			DS1302_Time[0]=0;
		}
		if(DS1302_Time[1]>12)
		{
			DS1302_Time[1]=1;
		}
		if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12)
		{
			if(DS1302_Time[2]>31)
		{
			DS1302_Time[2]=1;
		}
		}
		else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11)
		{
			if(DS1302_Time[2]>30)
		{
			DS1302_Time[2]=1;
		}
		}
		else if(DS1302_Time[1]==2)
		{
			if(DS1302_Time[0]%4==0)
			{
				if(DS1302_Time[2]>29)
		{
			DS1302_Time[2]=1;
		}
		else
		{
			if(DS1302_Time[2]>28)
		{
			DS1302_Time[2]=1;
		}
		}
			}
		}
		if(DS1302_Time[3]>23)
		{
			DS1302_Time[3]=0;
		}
		if(DS1302_Time[4]>59)
		{
			DS1302_Time[4]=0;
		}
		if(DS1302_Time[5]>59)
		{
			DS1302_Time[5]=0;
		}
	}
	if(KeyNum==4)
	{
		DS1302_Time[TimeSetSelect]--;
		if(DS1302_Time[0]<0)
		{
			DS1302_Time[0]=99;
		}
		if(DS1302_Time[1]<1)
		{
			DS1302_Time[1]=12;
		}
		if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12)
		{
			if(DS1302_Time[2]<1)
		{
			DS1302_Time[2]=31;
		}
		}
		else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11)
		{
			if(DS1302_Time[2]<1)
		{
			DS1302_Time[2]=30;
		}
		}
		else if(DS1302_Time[1]==2)
		{
			if(DS1302_Time[0]%4==0)
			{
				if(DS1302_Time[2]<1)
		{
			DS1302_Time[2]=29;
		}
		else
		{
			if(DS1302_Time[2]<1)
		{
			DS1302_Time[2]=28;
		}
		}
			}
		}
		if(DS1302_Time[3]<0)
		{
			DS1302_Time[3]=23;
		}
		if(DS1302_Time[4]<0)
		{
			DS1302_Time[4]=59;
		}
		if(DS1302_Time[5]<0)
		{
			DS1302_Time[5]=59;
		}
	}
	if(TimeSetSelect==0&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(1,1,"  ");
	}
	else {LCD_ShowNum(1,1,DS1302_Time[0],2);}
	
	if(TimeSetSelect==1&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(1,4,"  ");
	}
	else {LCD_ShowNum(1,4,DS1302_Time[1],2);}
	
	if(TimeSetSelect==2&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(1,7,"  ");
	}
	else {LCD_ShowNum(1,7,DS1302_Time[2],2);}
	
	if(TimeSetSelect==3&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(2,1,"  ");
	}
	else {LCD_ShowNum(2,1,DS1302_Time[3],2);}
	
	if(TimeSetSelect==4&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(2,4,"  ");
	}
	else {LCD_ShowNum(2,4,DS1302_Time[4],2);}
	
	if(TimeSetSelect==5&&TimeSetFlashFlag==1)
	{
		LCD_ShowString(2,7,"  ");
	}
	else {LCD_ShowNum(2,7,DS1302_Time[5],2);}
	
}

void main()
{ 
	LCD_Init();
	DS1302_Init();
	TImer0_Init();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");
	
	
	DS1302_WriteByte(0x8e,0x00);//关闭写保护
	
	DS1302_SetTime();

	
        while(1)
        {
					KeyNum=Key();
					if(KeyNum==1)
					{
						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_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0=0x18;//设置定时初值
	TH0=0xFC;//设置定时初值
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
	TimeSetFlashFlag=!TimeSetFlashFlag;
	}
}

DS1302.c

#include <REGX52.H>

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

#define DS1302_SECOND  0x80
#define DS1302_MINUTE  0x82
#define DS1302_HOUR  0x84
#define DS1302_DATE 0x86
#define DS1302_MONTHE  0x88
#define DS1302_DAY  0x8A
#define DS1302_YEAR  0x8C
#define DS1302_WP  0x8E

char DS1302_Time[]={22,12,29,16,35,55,6};

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

void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;

	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

unsigned DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command=Command|0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	}
	
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;
	DS1302_SCLK=0;
	if(DS1302_IO)
	{
		Data=Data|(0x01<<i);
	}
	}
	DS1302_CE=0;
	DS1302_IO=0;
	return Data;
}

void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTHE,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);
}

void DS1302_ReadTime(void)
{
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MONTHE);
	DS1302_Time[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
}

LCD1602.c

#include <REGX52.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');
	}
}

key.c

#include <REGX52.H>
#include "Delay.h"

unsigned char Key()
{
	unsigned char KeyNumber=0;
	if(P3_1==0)
	{
		Delay(20);while(P2_1==0);Delay(20);KeyNumber=1;
	}
  if(P3_0==0)
	{
		Delay(20);while(P2_0==0);Delay(20);KeyNumber=2;
	}
	if(P3_2==0)
	{
		Delay(20);while(P2_2==0);Delay(20);KeyNumber=3;
	}
	if(P3_3==0)
	{
		Delay(20);while(P2_3==0);Delay(20);KeyNumber=4;
	}
		
	return KeyNumber;
	
}

Timer0.c

#include <REGX52.H>
//简介:定时器0初始化,1毫秒@12.000MHZ
void TImer0_Init()
{
	//TMOD=0x01;//0000 0001
	TMOD=TMOD&0xF0;//把TM0D的低四位清零,高四位保持不变
	TMOD=TMOD|0x01;//把TM0D的最低位置置1,高四位保持不变
	TL0=0x18;//设置定时初值
	TH0=0xFC;//设置定时初值
	TF0=0;//清除TF0标志
	TR0=1;//计时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}


//定时器中断函数模板
//void Timer0_Routine() interrupt 1
//{
//	static unsigned int T0Count;
//	TL0=0x18;//设置定时初值
//	TH0=0xFC;//设置定时初值
//	T0Count++;
//	if(T0Count>=1000)
//	{
//		T0Count=0;
//	P2_0=~P2_0;
//	}
//}

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void TImer0_Init(void);

#endif

key.h

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

extern  char DS1302_Time[];

void DS1302_Init();
void DS1302_WriteByte(unsigned char Command,Data);
unsigned DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);

#endif

LCD1602.h

#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

注意:一定要看

千万不要直接复制代码,因为是模块化编写,模块的代码没有往上复制,大家一定要自己动手跟着教学视屏自己大!!!!!

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

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

相关文章

我的统计学学习笔记(持续更新)

目录数据&#xff1a;变量和观测统计学描述统计数据的收集数据的可视化数据的规律性特征统计推断参数估计假设检验贝叶斯统计基础知识&#xff1a;概率论数据&#xff1a;变量和观测 变量(column)、观测(row)、测量(assign number to observation)。 统计学 描述统计 数据…

YOLO-V5 系列算法和代码解析(四)—— 网络结构

文章目录辅助工具网络配置文件网络构建网络推理绘制网络结构辅助工具 借助辅助工具可视化网络结构&#xff0c;达到辅助阅读代码&#xff0c;进而辅助手动绘制结构清晰的网络结构&#xff0c;最终理解整个网络架构的目的&#xff0c;为深入学习【yolo-v5】提供有效的保障。 ten…

阿里妈妈内容风控模型预估引擎的探索和建设

作者&#xff1a;徐雄飞、金禄旸、滑庆波、李治 内容作为营销的重要载体&#xff0c;能够促进信息的交流和传播。在营销场景中&#xff0c;广告高曝光的特性放大了风险外漏带来的一系列问题&#xff0c;因此对内容的风控审核就显得至关重要。本文将为大家分享阿里妈妈内容风控模…

DOM节点操作

节点操作 改变元素节点中的内容可以使用两个相关属性&#xff1a;innerHTML innerText 注意字符串不能换行 innerHTML属性能以HTML语法设置节点中的内容 innerText属性只能以纯文本的形式设置节点中的内容 节点创建 document.createElement()方法用于创建一个指定tagname…

android studio编译慢

前言 android studio编译慢一直就是一个问题&#xff0c;很久以前使用eclipse&#xff0c;编译速度很快&#xff0c;在还没开始正式工作的时候就开始使用android studio&#xff0c;那时候还是0.8 很原始&#xff0c;主要那时候还没开始工作&#xff0c;所以编译快慢没感觉&am…

TikTok Shop跨境服务市场上线;俄罗斯速卖通发布延误通知

让我们一起来看看今日都有哪些新鲜事吧&#xff01;01 TikTok Shop跨境服务市场上线 12月28日消息&#xff0c;服务商是助力商家在TikTok Shop成长非常重要的合作伙伴&#xff0c;TikTok Shop希望通过上线服务市场帮助商家快速了解服务商&#xff0c;筛选符合自身需求的服务商…

【JavaSE成神之路】Java面向对象(上)

哈喽&#xff0c;我是兔哥呀&#xff0c;今天就让我们继续这个JavaSE成神之路&#xff01; 这一节啊&#xff0c;咱们要学习的内容是Java的面向对象。 首先我们回顾一下&#xff0c;之前的章节我们学到了哪些东西。 我们学会了写一个类&#xff0c;然后里面弄一个main方法&am…

layer2 实现方式之状态通道

状态通道也算是一种比较热门的扩容方案&#xff0c;状态通道解决方案通过将链下交互和链上清算隔离开&#xff0c;能够在保障一定程度的非中心化和资产安全性的同时&#xff0c;实现速度更快、费用更低的交易。状态通道作为一种链下扩容方案&#xff0c;从一般到特殊分为通用状…

时光飞逝,博客两周年啦

原文链接&#xff1a;时光飞逝&#xff0c;博客两周年啦 博客自 2020年12月10日 运营以来&#xff0c;已经成功走过两年啦&#xff08;差点成为两年半的博主&#xff09;。 在这两年中&#xff0c;曾替无数网友解答了各种关于建站的疑难杂症&#xff0c;此处略过 30000 字。 …

linux系统动态库的连接

前言&#xff1a;在应用程序开发过程中&#xff0c;难免会用到第三方库&#xff0c;有的是开源的第三方库&#xff0c;有的是不开源的&#xff0c;还有的是自己写的库。上篇文章总结了应用程序调用静态库《linux中静态库编译与使用》&#xff0c;本文总结了几种在应用程序中快速…

八、esp8266建立基本网络服务器

1、网络服务器 (1)网络服务器有很多类型&#xff0c;它们功能十分丰富。通常承担网络服务器工作的设备都是运算能力比较强大的电脑。 (2)ESP8266虽然也能实现网络服务器的一些功能&#xff0c;但是毕竟它的运算能力是无法与那些昂贵的服务器电脑相比较&#xff0c;因此ESP826…

STM32的升级--ICP/ISP/IAP

ICP/ISP/IAP 区别 ICP(In-Circuit Programing): 通过J-Link/SWD等下载器烧写程序&#xff0c;上位机需要借助其他硬件的参与才能更新固件&#xff0c;可以更新MCU的所有存储区域&#xff1b; ISP(In-System Programing): 通过MCU出厂时固化的一个bootloader升级程序&#xff0…

第四节 空间参考类的属性说明

空间参考类&#xff1a;SpatialReference 说明 空间参考类是arcpy下面的一级类&#xff0c;用于定义空间参考的各类信息&#xff0c;主要是坐标信息。 空间参考Spatial Reference与坐标系最大的区别&#xff0c;在于空间参考除了定义坐标系以外&#xff0c;还要定义一系列地理…

Java BigDecimal总结

文章目录Java BigDecimal总结概述float 和 double的问题创建BigDecimal对象BigDecimal.valueOf()源码分析equals() 和 compareTo()BigDecimal设置精度和舍入模式舍入模式介绍BigDecimal转字符串DecimalFormat 格式化总结Java BigDecimal总结 概述 BigDecimal类在Java的java.m…

一个简单的数学问题

这个东西发提问没人看就发在这里了 一个球体的体积V_Sphere是容易求的&#xff1a; 则我们很容易求出半径为1的圆球的体积为. 众所周知方程【】在三维笛卡尔坐标系中的图像为一个半径为R的圆&#xff0c; 则R取1时这个方程的图像就成了一个半径为1的圆。 那么我们就能推出f(x…

飞行机器人专栏(九)-- 多传感器固定端口分配

目录 ​编辑 1 /dev/设备列表 2 ttyUSB*端口ID 3 端口别名rules动态绑定 4 launch文件配置 1 /dev/设备列表 lsusblsusb -t 2 ttyUSB*端口ID 查看/dev/ttyUSB* 设备端口ID &#xff1a;0403&#xff1a;6014 找到对应USB的设备ID&#xff0c;这里是 0403&#xff1a;…

测试新风向|视频 AI 转流程图初体验

前言&#xff1a; &#x1f604;作者简介&#xff1a;小曾同学.com,小伙伴们也可以叫我小曾&#xff0c;一个致力于测试开发的博主⛽️ 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;…

极狐GitLab include 语法减少 CI/CD Pipeline 代码冗余,提升构建效率

项目经理&#xff1a;我们有个 Java 的新项目要开始了&#xff0c;需要你帮忙设置调试一下 CI/CD Pipeline DevOps 工程师&#xff1a;好的&#xff0c;没问题 ONE WEEK LATER... 项目经理&#xff1a;新项目的 CI/CD Pipeline 咋样了啊&#xff0c;我看研发还是手动人肉编译…

基于Vue+SpringBoot的在线考试系统,支持多种题型,含数据库文件

spring-boot-online-exam 完整代码下载地址&#xff1a;基于VueSpringBoot的在线考试系统 快速体验 在安装了docker的机器上执行如下命令&#xff1a; 安装mysql: docker run --name exam-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORDaA111111 -d mysql:5.7.15然后用doc/sql…

freeswitch的gateway实现出中继的主备方案

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 某些呼叫场景中&#xff0c;我们有2条出中继线路可选&#xff0c;2条出中继需要按照主备模式来配置&#xff0c;优先使用主中继呼叫&#xff0c;当主中继出现问题时&#xff0c;呼叫自动转移到备用中继呼叫。 本节中&a…