DS1302实时时钟
原理图
DS1302封装图
DS1302主要性能
- SD1302实时时钟能够计算2100年之前的秒、分、时、日、日期、星期、月、年(闰年可自动调整),还可以通过配置AM/PM来决定采用24小时格式还是12小时格式。
- 内部含有31个字节静态数据存储RAM,可供用户访问。
- 采用串行I/O通信方式,使得管脚数量最少,简单SPI3线接口。
- 工作电压范围宽:2.0~5.5V.
- 工作电流小,功耗低:工作电压为2.0V时,小于300NA.
- 时钟或RAM数据的读/写有两种传送方式:单字节传送和多字节传送方式。
- 采用8脚DIP封装(双列直插式封装)或SOIC封装。
- 供电电压Vcc=5V时,与标准TTL兼容,可与单片机通信。
- 具有涓流充电能力。
- 采用主电源和备份电源双电源供应。备用电源可以是电池或者大电容,确保在系统掉电的情况下,始终还可以走。
各引脚功能:
- Vcc2 :主电源引脚,当Vcc2比Vcc1高0.2V以上时,DS1302由Vcc2供电,当Vcc2低于Vcc1时,由Vcc1供电。
- X1 X2:这两个引脚需要接一个32.768K的晶振,给DS1302提供一个基准。特别注意,要求这个晶振的引脚负载电容必须是6pF,而不是要加6pF的电容。如果要使用有源晶振的话,接到X1上即可,X2悬空。
- GND:接地。
- CE:DS1302的使能输入引脚。当读写DS1302时,这个引脚必须是高电平,DS1302这个引脚内部有一个40K的下拉电阻。
- I/O:这个引脚是一个双向通信引脚。读写数据都是通过这条引脚完成。DS1302这个引脚内部有一个40K的下拉电阻。
- SCLK:输入引脚。SCLK是用来作为通信的时钟信号,DS1302这个引脚内部有一个40K的下拉电阻。
- Vcc1:备用电源引脚。
其中只有5脚(CE使能)、6脚(I/O)、7脚(SCLK时钟)需接到单片机I/O口上。
DS1302的典型电路:
DS1302寄存器
1.命令字节
DS1302的一条指令一个字节共8位,其中第7位固定为1,0无效,第6位是RAM/CLOCK选择端,第5位到第1位是寄存器的地址,第0位是读写控制位。
2.寄存器
时钟日历寄存器包含在7个读/写寄存器内,读/写寄存器的数据是BCD码。
- 寄存器0:最高位CH时钟停止标志位,通过该位判断时钟在单片机系统掉电后是否正常运(0为有备用电源,正常运行) 。剩余7位的高三位是秒的十位,低四位是秒的个位。由于DS1302内部是BCD码,秒的十位最大是5,所以为3个二进制位。
- 寄存器1:最高位未使用,剩余7位的高三位是分钟的十位,低四位是分钟的个位。
- 寄存器2:BIT7为1代表采用12小时制,为0代表采用24小时制;BIT6固定为0里BIT5在12小时制下,0表示上午,1表示下午;在24小时制下,和BIT4一起表示小时的十位;低四位表示小时的个位。
- 寄存器3:高两位固定为0,BIT5和BIT4是日期的十位,低四位是日期的个位。
- 寄存器4:高三位固定为0,BIT4是月的十位,第四位是月的个位。
- 寄存器5:高五位固定是0,第三位表示星期。
- 寄存器6:高四位表示年的十位,低四位表示年的个位。00~99指的是2000年~2099年。
- 寄存器7:最高位为写保护位。如果此位为1,则禁止给任何其它寄存器或者31个字节的RAM写数据,因此在写数据之前,此位必须写成0。
DS1302中附加31字节RAM的地址:
突发模式(Brust)
在读取这7个寄存器的过程中,在一个极端的情况下会出现,比如当前时间是00:00:59,我们先读秒,是59,然后再去读分钟,而就在读完秒到还未开始读分钟的这个时间段内,刚好时间进位了,变成00:01:00这个时间,我们读到的分钟就是01,这个时间显然是错误的,出现这种问题的概率极小,但却是实实在在可能存在的。
解决方案:写操作用0XBE,读操作用0XBF,DS1302收到指令后,会自动识别出来是Brust模式,马上把所有的8个字节同时锁存到另外的8个寄存器缓冲区内,这样时钟继续走,而我们读数据是从另外一个缓冲区内读取的。同理,用Brust写数据,也是先写到这个缓冲区内,最终DS1302会把这个缓冲区内的数据一次性送到它的始终寄存器内。
用Brust突发模式连续写入8个寄存器数据
//向DS1302中写入一个字节数据
void DS1302WriteByte(uchar dat)
{
uchar i;
for(i = 0; i < 8; i++)
{
TSCLK = 0;//拉低时钟总线
TIO = dat & 0x01;//写一个字节,从最低位开始
TSCLK = 1;//拉高时钟总线,产生上升沿数据被DS1302读走
dat >>= 1;
}
}
void DS1302_BrustWrite(uchar *dat)
{
uchar i;
TRST = 0;
TSCLK = 0;
TRST = 1;
DS1302WriteByte(0XBE);
for(i = 0; i < 8; i++)
DS1302WriteByte(dat[i]);
TRST = 0;
}
用Brust突发模式连续读取8个寄存器数据
//从DS1302中读一个字节
uchar DS1302ReadByte()
{
uchar i,dat;
for(i = 0; i < 8; i++)
{
TSCLK = 0;//拉低时钟总线,产生下降沿,DS1302把数据放到TIO上
dat >>= 1;
if(TIO) dat |= 0x80;//读取数据
TSCLK = 1;//拉高时钟总线,以备下一次产生下降沿
}
TIO = 0;//释放数据线
return dat;
}
void DS1302_BrustRead(uchar *dat)
{
uchar i;
TRST = 0;
TSCLK = 0;
TRST = 1;
DS1302WriteByte(0XBF);
for(i = 0; i < 8; i++)
dat[i] = DS1302ReadByte();
TRST = 0;
}
DS1302的读写时序,数据的传输是从最低位开始,数据是以位(BIT)为单位依次写入或读出,读写数据操作中SCLK上升沿时写入数据,下降沿时执行读出数据。
读数据:CE端从低到高的一个上升沿开始允许开始读数据,拉低CE端则禁止读写数据,开始的8个SCLK周期,写命令字节,数据的后8个SCLK周期读出数据。
//从DS1302中读数据
uchar Read_DS1302(uchar cmd)
{
uchar dat;
TRST = 0;
TSCLK = 0;
TRST = 1;
DS1302WriteByte(cmd);
dat = BCD_chg_DAT(DS1302ReadByte());
return dat;
}
写数据:CE端从低到高的一个上升沿开始允许开始写数据,拉低CE端则禁止读写数据,开始的8个SCLK周期,写命令字节,数据后的8个SCLK周期写入数据。
//向DS1302中写数据
void Write_DS1302(uchar cmd,uchar dat)
{
TRST = 0;//拉低使能端
TSCLK = 0;//拉低时钟总线
TRST = 1;//拉高使能端,产生上升沿开始写数据
DS1302WriteByte(cmd);
DS1302WriteByte(DAT_chg_BCD(dat));
TRST = 0;
}
BCD码的转换
//十进制转BCD
uchar DAT_chg_BCD(uchar dat)
{
uchar dat1, dat2;
dat1 = dat / 10;
dat2 = dat % 10;
dat2 = dat2 + dat1 * 16;
return dat2;
}
//BCD转十进制
uchar BCD_chg_DAT(uchar dat)
{
uchar dat1, dat2;
dat1 = dat / 16;
dat2 = dat % 16;
dat2 = dat2 + dat1 * 10;
return dat2;
}
设置/获取时钟
//设置DS1302初值
void Set_DS1302()
{
uchar i;
Write_DS1302(0x8e,0x00);
for(i = 0; i < 7; i++)
Write_DS1302(WriteReg[i],Time[i]);
Write_DS1302(0x8e,0x80);
}
//获取DS1302的值
void Get_DS1302()
{
uchar i;
for(i = 0; i < 7; i++)
Time[i] = Read_DS1302(ReadReg[i]);
}
onewire.h
#ifndef _ONEWIRE_H_
#define _ONEWIRE_H_
#include <STC15F2K60S2.H>
#include <intrins.h>
sbit TRST = P1^3;
sbit TSCLK = P1^7;
sbit TIO = P2^3;
#define uchar unsigned char
extern unsigned char Time[7];
//ds1302.c
unsigned char DAT_chg_BCD(unsigned char dat);
unsigned char BCD_chg_DAT(unsigned char dat);
void DS1302WriteByte(unsigned char dat);
unsigned char DS1302ReadByte();
void Write_DS1302(unsigned char cmd,unsigned char dat);
unsigned char Read_DS1302(unsigned char cmd);
void Set_DS1302();
void Get_DS1302();
#endif
初始化时间读/写寄存器
uchar Time[7] = {55,59,23,1,2,2,22};
//2022年星期二2月2号23时59分55秒
uchar ReadReg[7] = {0X81, 0X83, 0X85, 0X87, 0X89, 0X8B, 0X8D};
uchar WriteReg[7] = {0X80, 0X82, 0X84, 0X86, 0X88, 0X8A, 0X8C};