(10)普中A2 51单片机DS1302实时时钟

DS1302介绍

  • DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有润年补偿等多种功能
  • RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片

引脚定义和应用电路

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

我们在使用单片机进行计时,假如断电了,下次再开机就会重新计时。但是DS1302有备用的电源,就算单片机断电了,依然可以正常计时。下次单片机通电后再读取数据就可以了。

晶振使用32.768KHZ和我们使用11.0592HZ进行串口通信是一个道理,在某些方面精度会更高。

DS1302内部结构框图

DS1302寄存器定义

我们只需要对这些寄存器进行读写,就可以读时间,和修改时间了。


时序定义

时钟写入和读取的代码

只需要按照上面的时序图,读写开始的时候把CE置1,然后给SCLK一个上升沿读写数据。然后恢复到低电平。读写结束后把CE置0,SCLK置0,我们可以看原理图,使用sbit和sfr关键字,对P36和P34和P35重新定义下。方便我们后续使用

bash 复制代码
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

单片机在通电后会把寄存器都置为1.所以我们也要写一个初始化函数。让SCLK寄存器和CE寄存器初始状态为0.

bash 复制代码
void DS1302_Init()
{
	DS1302_SCLK=0;
	DS1302_CE=0;
}

然后我们就可以写写入数据的函数了。写入之前先把CE寄存器置1。然后使用一个for循环把控制命令发送过去。每次在IO写入一位。然后给SCLK一个上升沿把数据法出去。控制命令写完后用一样的方式把数据给发送过去。发送结束后把CE置0.

bash 复制代码
void DS1302_WriteByte(unsigned char Command,unsigned char 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;
}

读取数据的函数也是很类似的,但是根据时序图我们就可以发现。读取时15个周期。写入是16个周期。所以我们在写入命令的时候先让SCLK置0再置1,在读取数据的时候先置1再置0,等于最后就会少一个周期。然后在中间和结束我们要让IO置0.释放总线。避免后续出现问题。

bash 复制代码
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char Data=0x00;
	unsigned char i=0;
	Command|=0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
	DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	}
	DS1302_IO=0;
	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;
}

然后我们可以再写一个默认的写入数据的函数。根据DS1302写入的时候的命令定义一些变量。方便操作。然后DS1302_Time数组存储的是年月日,时分秒。和星期。至于为什么在写入的时候要对数据进行处理,是因为DS1302在传输的时候数据是采用的BCD码。所以我们要把正常的十六进制进行一些转换。包括读取的时候也是需要进行转换的。

bash 复制代码
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 	0x84
#define DS1302_DATE 	0x86
#define DS1302_MONTH 	0x88
#define DS1302_DAY 		0x8A
#define DS1302_YEAR	 	0x8C
#define DS1302_WP 		0x8E
unsigned char DS1302_Time[]={25,11,29,18,29,30,6};
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_MONTH,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); 
}

读取数据的函数如下:

bash 复制代码
void DS1302_ReadTime(void)
{
	unsigned char temp;
	temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_MONTH);
	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;
}

最后。完整的代码:

首先是main.c文件:

bash 复制代码
#include <REGX52.H>
#include "LCD1602.H"
#include "DS1302.H"
#include <INTRINS.H>
void Delay(unsigned char x)	//@11.0592MHz
{
	unsigned char data i, j;
while(x--)
	{
	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}
unsigned char Hour;
unsigned char Minute;
unsigned char Second;
void main()
{
	LCD_Init();
	DS1302_Init();
  DS1302_SetTime();
	LCD_ShowNum(1,1,20,2);
	LCD_ShowChar(1,5,'-');
	LCD_ShowChar(1,8,'-');
	LCD_ShowChar(2,4,':');
	LCD_ShowChar(2,7,':');

	while(1)
	{
	DS1302_ReadTime();
	LCD_ShowNum(1,3,DS1302_Time[0],2);
	LCD_ShowNum(1,6,DS1302_Time[1],2);
	LCD_ShowNum(1,9,DS1302_Time[2],2);
	LCD_ShowNum(2,2,DS1302_Time[3],2);
	LCD_ShowNum(2,5,DS1302_Time[4],2);	
	LCD_ShowNum(2,8,DS1302_Time[5],2);	
	Delay(50);
	}

}

其次是DS1302.c文件和DS1302.h文件:

bash 复制代码
#include <REGX52.H>
#include "DS1302.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_MONTH 	0x88
#define DS1302_DAY 		0x8A
#define DS1302_YEAR	 	0x8C
#define DS1302_WP 		0x8E
unsigned char DS1302_Time[]={25,11,29,18,29,30,6};
void DS1302_Init()
{
	DS1302_SCLK=0;
	DS1302_CE=0;
}
void DS1302_WriteByte(unsigned char Command,unsigned char 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 char DS1302_ReadByte(unsigned char Command)
{
	unsigned char Data=0x00;
	unsigned char i=0;
	Command|=0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
	DS1302_IO=Command&(0x01<<i);
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	}
	DS1302_IO=0;
	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_MONTH,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_MONTH);
	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;
}
bash 复制代码
#ifndef __DS1302_H__
#define __DS1302_H__
extern unsigned char DS1302_Time[];
void DS1302_Init();
void DS1302_ReadTime(void);
void DS1302_SetTime(void);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_WriteByte(unsigned char Command,unsigned char Data);
#endif

LCD1602屏显示的代码之前的文章有写.并且代码比较长,.在此省略.

相关推荐
小叶子来了啊3 分钟前
5Arduino 程序结构
单片机·嵌入式硬件
小叶子来了啊35 分钟前
1Arduino 简介
单片机·嵌入式硬件
渡我白衣1 小时前
计算机组成原理(7):定点数的编码表示
汇编·人工智能·嵌入式硬件·网络协议·机器学习·硬件工程
雾岛听风眠1 小时前
电路板维修
单片机·嵌入式硬件
少一倍的优雅1 小时前
hi3863(WS63) 智能小车 (一) 简单介绍
单片机·嵌入式硬件·harmonyos·hi3863
Vizio<2 小时前
STM32HAL库开发笔记-串口通信(UART)
笔记·stm32·嵌入式硬件
小幽余生不加糖2 小时前
步进电机、有刷直流电机以及无刷直流电机对比
笔记·单片机·嵌入式硬件·学习·能源
加成BUFF2 小时前
树莓派5-TB6612电机驱动模块完整实战教程
嵌入式硬件·pwm·树莓派5·tb6612·pwm波控制电机
DuanPenghao2 小时前
RISCV实战:实现基于Verilator模拟蜂鸟E203的加法器和卷积神经网络仿真
人工智能·嵌入式硬件·神经网络·cnn·risc-v
x976663 小时前
使用 HMAC-SHA256算法对MCU UID进行加密
单片机·嵌入式硬件·算法