DS1320的基本概述
DS1302是美国DALLAS公司推出的高性能、低功耗的实时时钟,附加31字节的静态RAM,采用SPI三线接口与MCU进行同步通信,并可采用突发方式一次传送多个字节的时钟参数和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小于31天时可以自动调整,并具有润年补偿功能。
简单来说,DS1302可以理解为一个电子手表,里面带有一个31字节的内存。当然,基本的使用方法和我们平时使用电子手表差不多,你可以设定时间,也可以读取时间,只不过这些工作是通过SPI接口由MCU去完成而已。
DS1320的工作电压比较宽,在2.0V~5.5V都可以正常工作。芯片采用双电源供电,当主电源比备用电源高0.2V以上时,由主电源供电,否则由备用电源供电。备用电源一般是一个纽扣电池。DS1302的功耗一般很低,在2.0V工作电压的时候,工作电流小于300nA。
DS1302的指令格式

DS1302的时钟日历寄存器
在DS1302中有两块存储器:日历时钟寄存器和静态RAM存储器。
前者用于记录实时时间,后者用于记录其他数据。
对于基本的实时时钟应用,用户重点关注的是日历时钟寄存器。设定时间参数就是往这些寄存器写入内容,读取实时时间也是从这些寄存器读出数据。
DS1302有关日历和时钟的寄存器有12个,我们最常用的有7个。

要理解日历时钟寄存器的具体定义,你需要先了解一个编码知识点:
什么是BCD码?
就是用十六进制来表示十进制。
什么意思?怎么理解?
例如,十六进制数0x13的真实值为整数19,但BCD码表示的是整数13。
由于在DS1302的指令格式定义中,最后一位是读写控制位,所以,对于同一个寄存器单元,DS1302读寄存器和写寄存器的指令是不一样的。
为了程序设计方便,我们可以认为它们是读寄存器和写寄存器两个不同的地址,并定义三个数组,对读寄存器地址、写寄存器地址和日历时钟寄存器参数进行管理。

DS1302的通信接口
DS1302的基本操作实际上非常简单,只有两个操作:其一是设定时间参数,其二是读取实时时间。不管是那个操作,MCU都要通过SPI接口进行数据交互,而SPI接口有其规定的时序,这个必须参考数据手册。
官方手册下载:DS1302数据原版手册
控制字的输出总是从最低位开始,在控制字指令输入后的下一个SCLK时钟信号的上升沿,数据被写入DS1302 ,数据的写入是从最低位到最高位的。
时间数据的读入从最低位开始;在控制字指令输入后的下一个SCLK时钟信号的下降沿,数据从DS1302读出,数据的读出也是从最低位到最高位的。
DS1302的单字节写操作时序

【1】在时钟信号SCLK为低电平的时候,拉高使能端RST的电平。
【2】数据位在时钟SCLK的上升沿完成写入操作。
【3】单字节的写入需要2个参数:第一个为控制字,指明控制方式和目标寄存器的地址;第二个位写入的具体数据。
//DS1302单字节写操作的底层驱动代码参考--51版
//第一个参数 addr:待写入的目标寄存器地址
//第二个参数 dat: 待写入的具体数据
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
unsigned char n;
RST = 0;
Delay_DS1302(1);
SCLK = 0;
Delay_DS1302(1);
RST = 1; //在SCLK为低电平的时候拉高RST
Delay_DS1302(1);
for (n=0; n<8; n++) //发送要写入数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
Delay_DS1302(1); //在SCLK的上升沿写入数据位
SCLK = 0;
Delay_DS1302(1);
}
for (n=0; n<8; n++) //将指定内容写入该地址的内存
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;
Delay_DS1302(1); //在SCLK的上升沿写入数据位
SCLK = 0;
Delay_DS1302(1);
}
RST = 0;
Delay_DS1302(1);
}
DS1302的单字节读操作时序

【1】在时钟信号SCLK为低电平的时候,拉高使能端RST的电平。
【2】数据位在时钟SCLK的上升沿完成写入操作;在SCLK的下降沿完成读出操作。
【3】单字节的读出有1个参数:第一个为控制字,指明控制方式和目标寄存器的地址。
【4】单字节的读出有1个返回值:为读到的具体数据。
unsigned char DS1302_ReadByte(unsigned char addr)
{
unsigned char n,dat,tmp;
RST = 0;
Delay_DS1302(1);
SCLK = 0;
Delay_DS1302(1);
RST = 1;
Delay_DS1302(1);
for(n=0; n<8; n++) //发送要读出数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
Delay_DS1302(1);
SCLK = 0;
Delay_DS1302(1);
}
for(n=0; n<8; n++) //读出该地址内存的数据
{
tmp = DSIO;
dat = (dat>>1) | (tmp<<7);
SCLK = 1;
Delay_DS1302(1);
SCLK = 0;
Delay_DS1302(1);
}
RST = 0;
Delay_DS1302(1);
SCLK = 1;
Delay_DS1302(1);
DSIO = 0;
Delay_DS1302(1);
DSIO = 1;
Delay_DS1302(1);
return dat;
}