DS1302时钟芯片介绍

DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历31 字节静态RAM ,通过简单的串行接口与单片机进行通信。

芯片得实物图张下面这个样子:
在这里插入图片描述
一般会又晶振电路,备用电源等组成集成电路构成实时时钟,实物如下:
在这里插入图片描述

其中,实时时钟/日历电路,提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。

静态RAM得存在使得可以对DS1302进行一些设置,比如时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。

DS1302 与单片机通信:DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:(1)RES 复位(2)I/O 数据线(3)SCLK串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。

总结DS1302特点如下:

  • 实时时钟具有能计算2100 年之前的秒、分、时、日、星期、月、年的能力,与闰年调整的能力
  • 31 个8 位暂存数据存储RAM
  • 串行 I/O 口方式使得管脚数量最少
  • 宽范围工作电压2.0V~ 5.5V
  • 工作电流 2.0V 时,小于300nA
  • 读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式
  • 8 脚DIP 封装或可选的8 脚SOIC 封装
  • 简单 3 线接口
  • 与 TTL 兼容Vcc=5V
  • 可选工业级温度范围-40 ~ +85
  • 双电源管用于主电源和备份电源供应

DS1302 硬件

DS1302可以8 脚DIP 封装或可选的8 脚SOIC 封装如下:
DIP封装:
在这里插入图片描述
SOIC封装:
在这里插入图片描述

引脚定义

由上面得封装可以看到DS1302有8个引脚,其中:
电源有两个

  • VCC2 主电源
  • VCC1 备用电池

外部晶振引脚两个

  • X1、X2 之间需要32.768KHz得晶振

通信引脚3个

  • CE 芯片使能
  • IO 数据输入/输出
  • SCLK 串行时钟

电源地一个

  • GND 电源地

应用电路

根据引脚定义,其典型与单片机得应用电路可以如下:
在这里插入图片描述

AD原理图

DS1302得AD原理图可以画成如下形式:
在这里插入图片描述
VCC1没有接备用电池,所以掉电后会恢复初始时间。

5、6、7脚分别与控制器相联,最好可以加上上拉电阻4.7K
1引脚可以加个滤波电容

如果要加备用电源脚,注意需要是3.3V,DS1302要求备用电源电压稍微低于主用电源

在protrues里设计了一个完美的如下图:
在这里插入图片描述

DS1302 软件

命令字节

DS1302 的一条命令指令为一个字节共 8 位。
其中第 7 位(即最高位)固定为 1,这一位如果是0 的话,那写进去也是无效的。
第 6 位是选择 RAM 还是 CLOCK 的。如果选择 CLOCK 功能,第 6位是 0,如果要用 RAM,那第 6 位就是 1
第 5 到第 1 位,决定了寄存器的 5 位地址
第 0 位是读写位,如果要写,这一位就是 0,如果要读,这一位就是 1
整个字节指令如下图所示:
在这里插入图片描述
如果,对时钟操作、秒地址操作、读:
10000001(0x81)
对时钟操作、秒地址操作、写:
10000000(0x80)

寄存器

DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器如下图所示。
在这里插入图片描述
此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。

通信时序与数据读写

DS1302有三根线,分别是 CE、I/O 和 SCLK,其中 CE 是使能线,SCLK 是时钟线,I/O 是数据线。
通信是SPI的变异种类。
在时钟的上升沿,I/O口的数据将会被写入,在时钟的下降沿,时钟芯片的数据将会被读出。
单字节写入操作
在这里插入图片描述
在这里插入图片描述
单字节写(Write)有16个脉冲,而单字节读(Read)只有15个脉冲,因为当最后一个命令字的上升沿之后的下降沿数据马上就读出来了,就是红框那里

驱动程序

上面给出了单字节的读写方法,下面是则是单字节读写的对应驱动程序

DS1302写一个字节

/**
  * @brief  DS1302写一个字节
  * @param  Command 命令字/地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void DS1302_WriteByte(unsigned char Command,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;
}

DS1302读一个字节

/**
  * @brief  DS1302读一个字节
  * @param  Command 命令字/地址
  * @retval 读出的数据
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
    unsigned char i,Data=0x00;
    Command|=0x01;    //将指令转换为读指令
    DS1302_CE=1;
    for(i=0;i<8;i++)
    {
        DS1302_IO=Command&(0x01<<i);
        DS1302_SCLK=0;
        DS1302_SCLK=1;
    }
    for(i=0;i<8;i++)
    {
        DS1302_SCLK=1;
        DS1302_SCLK=0;
        if(DS1302_IO){Data|=(0x01<<i);}
    }
    DS1302_CE=0;
    DS1302_IO=0;    //读取后将IO设置为0,否则读出的数据会出错
    return Data;
}

初始化DS1302时间

可以在程序的初始阶段设置DS1302的时间,就是往指定的寄存器写相关时间设置

void Ds1302Init()
{
    uchar n;
    Ds1302Write(0x8E,0X00);         //禁止写保护,就是关闭写保护功能
    for (n=0; n<7; n++)          //写入7个字节的时钟信号:分秒时日月周年
    {
        Ds1302Write(WRITE_RTC_ADDR[n],rtc_time[n]);    
    }
    Ds1302Write(0x8E,0x80);         //打开写保护功能
}

其中0x8E地址的寄存器就是控制是否可以往DS1302写数据的指令0x00就可以写了,0x80,可以关闭写,即不能设置数据了。
上面的WRITE_RTC_ADDR分别是

uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

rtc_time的数组分别是

uchar rtc_time[7] = {0x55, 0x59, 0x6, 0x17, 0x04, 0x07, 0x22};

分别是秒分时日月周年的BCD码数据
秒设置的是0x55 及 秒是55,
上面的时间就是
22年4月17日 6点59分55秒 周日

读取时间

上面给出了读取单字节的方法,下面则是调用上面的方法,然后在lcd上显示

uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};

上面是秒….的寄存器地址

void Ds1302ReadTime()
{
    uchar n;
    for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
    {
        rtc_time[n] = Ds1302Read(READ_RTC_ADDR[n]);
    }

    DisplayOneChar(0, 0, '0' + rtc_time[2]/16);
    DisplayOneChar(1, 0, '0' + rtc_time[2]%16);
    DisplayOneChar(3, 0, '0' + rtc_time[1]/16);
    DisplayOneChar(4, 0, '0' + rtc_time[1]%16);

    DisplayOneChar(6, 0, '0' + rtc_time[0]/16);
    DisplayOneChar(7, 0, '0' + rtc_time[0]%16);
}

rtc_time[0]/16就是秒的十位位
rtc_time[0]%16就是秒的个位
除以16和余16就是因为返回的数值是BCD码。

Protues仿真

下面通过Protues仿真验证下上面的软硬件,整体电路图如下:
在这里插入图片描述
软件就是上面介绍的,运行后如下图:
lcd显示的单片机读取的DS1302的数据
在这里插入图片描述
在这里插入图片描述
仿真过去了28s,初始化为55s,所以当前是23s