一.DS1302的主要性能指标

    (1)DS1302实时时钟具有能计算2100年之前的秒、分、时、日、日期、星期、月、年的能力,还有闰年调整的能力。
    (2)内部含有31个字节静态RAM,可提供用户访问。

    (3)采用串行数据传送方式,使得管脚数量最少,简单SPI 3线接口。
    (4)工作电压范围宽:2.0~5.5V。
    (5)工作电流:2.0V时,小于300nA。

    (6)时钟或RAM数据的读/写有两种传送方式:单字节传送和多字节传送方式。
     (7)采用8脚DIP封装或SOIC封装。
    (8)与TTL兼容,Vcc=5V。

    (9)可选工业级温度范围:-40°C~+85°C。
    (10)具有涓流充电能力。
    (11)采用主电源和备份电源双电源供应。

    (12)备份电源可由电池或大容量电容实现。

二、SPI总线概念
    SPI接口的全称是“Serial Peripheral Interface”,意为串行外围接口
    SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

    SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,地位在后,为全双工通信,数据传输速度总体来说比I2C总线要快,速度可达到几Mbps。

    SPI接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从器件,其接口包括以下四种信号:

   (1)MOSI – 主器件数据输出,从器件数据输入
    (2)MISO – 主器件数据输入,从器件数据输出

    (3)SCLK – 时钟信号,由主器件产生
    (4)/CS  – 从器件使能信号,由主器件控制

    最后,SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。 

 

三、DS1302引脚功能

   X1、X2:32.768KHz晶振接入引脚。
     GND:地。
     RST:复位引脚,低电平有效,操作时高电平。
     I/O:数据输入/输出引脚,具有三态功能。
     SCLK:串行时钟输入引脚。
    Vcc1:工作电源引脚。
    Vcc2:备用电源引脚。 接入电池断电时提供1302电源

四.DS1302的寄存器及片内RAM
    DS1302有一个控制寄存器、12个日历、时钟寄存器和31个RAM。可读写

   1.控制寄存器
           控制寄存器用于存放DS1302的控制命令字,DS1302的RST引脚回到高电平后写入的第一个字就为控制命令。它用于对DS1302读写过程进行控制,它的格式如下: 

  D7

D6

D5

D4

D3

D2

D1

D0

  1

RAM/CK

A4

A3

A2

A1

A0

RD/W

 其中:
        D7:固定为1

        D6:RAM/CK位,=1片内RAM,=0日历、时钟寄存器选择位。 
        D5~D1:地址位,用于选择进行读写的日历、时钟寄存器或片内RAM。对日历、时钟寄存器或片内RAM的选择见表。

        D0: 读写选择,=0写,=1读

 

存器名称

D7

D6

D5

D4

D3

D2

D1

D0

1

RAM/CK

A4

A3

A2

A1

A0

R/W

秒寄存器

1

0

0

0

0

0

0

0或1

分寄存器

1

0

0

0

0

0

1

0或1

小时寄存器

1

0

0

0

0

1

0

0或1

日寄存器

1

0

0

0

0

1

1

0或1

月寄存器

1

0

0

0

1

0

0

0或1

星期寄存器

1

0

0

0

1

0

1

0或1

年寄存器

1

0

0

0

1

1

0

0或1

寄存器名称

D7

D6

D5

D4

D3

D2

D1

D0

1

RAM/CK

A4

A3

A2

A1

A0

R/W

写保护寄存器

1

0

0

0

1

1

1

0或1

慢充电寄存器

1

0

0

1

0

0

0

0或1

时钟突发模式

1

0

1

1

1

1

1

0或1

RAM0

1

1

0

0

0

0

0

0或1

  •  

1

1

  •  
  •  
  •  
  •  
  •  

0或1

RAM30

1

1

1

1

1

1

0

0或1

RAM突发模式

1

1

1

1

1

1

1

0或1

  2.日历、时钟寄存器
        DS1302共有12个寄存器,其中有7个与日历、时钟相关,存放的数据为BCD码形式。日历、时钟寄存器的格式如表。

寄存器名称

取值范围

D7

D6

D5

D4

D3

D2

D1

D0

秒寄存器

00~59

CH

秒的十位

秒的个位

分寄存器

00~59

0

分的十位

分的个位

小时寄存器

01~12或00~23

12/24

0

A/P

HR

小时的个位

日寄存器

01~31

0

0

日的十位

日的个位

寄存器名称

取值

范围

D7

D6

D5

D4

D3

D2

D1

D0

月寄存器

01~12

0

0

0

1或0

月的个位

星期寄存器

01~07

0

0

0

0

星期几

年寄存器

01~99

年的十位

年的个位

写保护寄存器

 

WP

0

0

0

0

0

0

0

慢充电寄存器

 

TCS

TCS

TCS

TCS

DS

DS

RS

RS

时钟突发寄存器

 

 

 

 

 

 

 

 

 

        说明:
        (1)数据都以BCD码形式。    
        (2)小时寄存器的D7位为12小时制/24小时制的选择位,当为1时选12小时制,当为0时选24小时制。当12小时制时,D5位为1是上午,D5位为0是下午,D4为小时的十位。当24小时制时,D5、D4位为小时的十位。(3)秒寄存器中的CH位为时钟暂停位,当为1时钟暂停,为0时钟开始启动。
        ( 4)写保护寄存器中的WP为写保护位,当WP=1,写保护,当WP=0未写保护,当对日历、时钟寄存器或片内RAM进行写时WP应清零,当对日历、时钟寄存器或片内RAM进行读时WP一般置1。
        (5)慢充电寄存器的TCS位为控制慢充电的选择,当它为1010才能使慢充电工作。DS为二极管选择位。DS为01选择一个二极管,DS为10选择二个二极管,DS为11或00充电器被禁止,与TCS无关。RS用于选择连接在VCC2与VCC1之间的电阻,RS为00,充电器被禁止,与TCS无关,电阻选择情况见表.

RS位

电阻器

阻值

00

01

R1

2K

10

R2

4K

11

R3

8K

 注:什么是BCD码
       BCD码是通过4位二进制码来表示1位十进制中的0~9这10个数码。
         二进制码转换为BCD码的方式为:4位二进制码大于1001时,加6。
         如:BCD码00001100的二进制码为:00001100+6=00010010

0

0000

5

0101

1

0001

6

0110

2

0010

7

0111

3

0011

8

1000

4

0100

9

1001

五、片内RAM
        DS1302片内有31个RAM单元,对片内RAM的操作有两种方式:单字节方式和多字节方式。当控制命令字为C0H~FDH时为单字节读写方式,命令字中的D5~D1用于选择对应的RAM单元,其中奇数为读操作,偶数为写操作

        当控制命令字为FEH、FFH时为多字节操作(表中的RAM突发模式),多字节操作可一次把所有的RAM单元内容进行读写。FEH为写操作,FFH为读操作。


六、数据输入输出(I/O)

        在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。

单字节读写

 
        DS1302是通过SPI串行总线跟单片机通信的,当进行一次读写操作时最少得读写两个字节,第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOK寄存器操作。第二个字节就是要读或写的数据了。

   

 单字节读写:只有在SCLK为低电平时,才能将CE置为高电平。所以在进行操作之前先将SCLK置低电平,然后将CE置为高电平,接着开始在IO上面放入要传送的电平信号,然后跳变SCLK。数据在SCLK上升沿时,DS1302读写数据,在SCLK下降沿时,DS1302放置数据到IO上

 

主函数部分

/**************************************************************************************
*		              DS1302时钟实验												  *
实现现象:下载程序后,数码管显示时钟数据
注意事项:																				  
***************************************************************************************/
 
#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"	
 
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
 
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
 
 
char num=0;
u8 DisplayData[8];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
 
/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	while(i--);	
}
 
 
/*******************************************************************************
* 函 数 名         : datapros()
* 函数功能		   : 时间读取处理转换函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
 
void datapros() 	 
{
   	Ds1302ReadTime();
	DisplayData[0] = smgduan[TIME[2]/16];				//时
	DisplayData[1] = smgduan[TIME[2]&0x0f];				 
	DisplayData[2] = 0x40;
	DisplayData[3] = smgduan[TIME[1]/16];				//分
	DisplayData[4] = smgduan[TIME[1]&0x0f];	
	DisplayData[5] = 0x40;
	DisplayData[6] = smgduan[TIME[0]/16];				//秒
	DisplayData[7] = smgduan[TIME[0]&0x0f];
}
 
 
/*******************************************************************************
* 函数名         :DigDisplay()
* 函数功能		 :数码管显示函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void DigDisplay()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位
			case(3):
				LSA=1;LSB=1;LSC=0; break;//显示第3位
			case(4):
				LSA=0;LSB=0;LSC=1; break;//显示第4位
			case(5):
				LSA=1;LSB=0;LSC=1; break;//显示第5位
			case(6):
				LSA=0;LSB=1;LSC=1; break;//显示第6位
			case(7):
				LSA=1;LSB=1;LSC=1; break;//显示第7位	
		}
		P0=DisplayData[7-i];//发送数据
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}		
}
 
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	Ds1302Init();
	while(1)
	{
		datapros();	 //数据处理函数
		DigDisplay();//数码管显示函数		
	}		
}
 

数据处理函数部分

#include"ds1302.h"
 
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
 
//---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x12, 0x07, 0x05, 0x06, 0x16};
 
/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能		   : 向DS1302命令(地址+数据)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/
 
void Ds1302Write(uchar addr, uchar dat)
{
	uchar n;
	RST = 0;
	_nop_();
 
	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1; //然后将RST(CE)置高电平。
	_nop_();
 
	for (n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();
	}
	for (n=0; n<8; n++)//写入8位数据
	{
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	
		 
	RST = 0;//传送数据结束
	_nop_();
}
 
/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能		   : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/
 
uchar Ds1302Read(uchar addr)
{
	uchar n,dat,dat1;
	RST = 0;
	_nop_();
 
	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;//然后将RST(CE)置高电平。
	_nop_();
 
	for(n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
 
	RST = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat;	
}
 
/*******************************************************************************
* 函 数 名         : Ds1302Init
* 函数功能		   : 初始化DS1302.
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
 
void Ds1302Init()
{
	uchar n;
	Ds1302Write(0x8E,0X00);		 //禁止写保护,就是关闭写保护功能
	for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
	{
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);	
	}
	Ds1302Write(0x8E,0x80);		 //打开写保护功能
}
 
/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能		   : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
 
void Ds1302ReadTime()
{
	uchar n;
	for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
	{
		TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
	}
		
}
 
 

头函数部分

#ifndef __DS1302_H_
#define __DS1302_H_
 
//---包含头文件---//
#include<reg52.h>
#include<intrins.h>
 
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
 
#ifndef uint 
#define uint unsigned int
#endif
 
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
 
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
 
//---加入全局变量--//
extern uchar TIME[7];	//加入全局变量
 
#endif