(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屏显示的代码之前的文章有写.并且代码比较长,.在此省略.

相关推荐
@good_good_study1 小时前
STM32 TIM通道捕获配置函数及实验
stm32·单片机
TeleostNaCl1 小时前
Docker | 如何限制容器的 CPU/内存/磁盘IO 的资源利用以降低性能消耗
运维·经验分享·嵌入式硬件·docker·容器·智能路由器
偶像你挑的噻10 小时前
15-Linux驱动开发-PWM子系统
linux·驱动开发·stm32·嵌入式硬件
硅农深芯10 小时前
是时候跟GitBucket说再见了
git·单片机
未来之窗软件服务11 小时前
幽冥大陆(三十八)P50酒店门锁SDK C#仙盟插件——东方仙盟筑基期
开发语言·单片机·c#·东方仙盟·东方仙盟sdk·东方仙盟vos智能浏览器
Java小白,一起学习14 小时前
STM32新建工程(标准库官网下载)
stm32·单片机·嵌入式硬件
vickycheung314 小时前
RK3588增加Xenomai3实时补丁
经验分享·嵌入式硬件·arm 嵌入式开发
Bona Sun15 小时前
单片机手搓掌上游戏机(十五)—pico运行fc模拟器之编译环境
c语言·c++·单片机·游戏机
贝塔实验室15 小时前
红外编解码彻底解析
网络·嵌入式硬件·信息与通信·信号处理·代码规范·基带工程·精益工程