DS1302的使用说明

DS1302基本介绍

DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31 字节静态RAM ,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:(1)RES 复位(2)I/O 数据线(3)SCLK串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mW

电气说明

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

引脚说明

DS1302封装
VCC2:主用电源引脚
X1、X2:32.768kHz外部晶振引脚(应有一个6 pF的负载电容CL )
GND:地
RST:复位引脚(又称CE)
I/O:串行数据引脚,数据输出或者输入都从这个引脚
SCLK:串行时钟引脚
VCC1:备用电源

时序解读

在这里插入图片描述

  1. RST: 复位时序。即在RST引脚产生一个正脉冲。在整个读写期间,RST=1,一次字节读写完毕之后,要注意把RST置0,准备下次读写周期;
  2. SINGLE BYTE READ: 单字节读。先对寄存器写命令,从最低位开始写;写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现。所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!读出来的数据是最低位开始。
  3. SINGLE BYTE WRITE: 单字节写,两个字节的数据配合16个上升沿将数据写入即可。
  4. BURST模式: 先写到缓冲区内,最终 DS1302 会把这个缓冲区内的数据一次性送到它的时钟寄存器内。

寄存器及其功能

地址/命令字节

在这里插入图片描述

  1. 第7位必须为1;
  2. 第6位:置1,操作RAM寄存器;置0,操作clock寄存器;
  3. 第0位:置1,读数据;置0,写数据。

数据字节

在这里插入图片描述

秒寄存器的CH位:
置1,时钟停振,进入低功耗态;
置0,时钟工作。
小时寄存器的D7位:
置1,12小时制(D5置1表示上午,置0表示下午);
置0,24小时制(此时D5、D4组成小时的十位)。
WP:写保护位。
置为1时,写保护;
置为0时,未写保护。

单次读/写操作

1. 发送一个byte的数据

/* 发送一个字节到 DS1302 通信总线上 */
void DS1302::WriteByte(uint8_t byte)
{
  for (uint8_t n = 0; n < 8; n++) //开始传送八位地址命令
  {
    digitalWrite(clkPin, LOW); //clk置0,开始放置数据
    digitalWrite(ioPin, byte & 0x01); //数据从低位开始传送
    byte >>= 1;
    digitalWrite(clkPin, HIGH); //clk置1,数据在上升沿时被DS1302读取
    delayMicroseconds(2);
  }
}

2.写入数据

/* 用单次写操作向某一寄存器写入一个字节,add-寄存器地址,dat-待写入字节 */
void DS1302::SingleWrite(uint8_t add, uint8_t dat)
{
  digitalWrite(rstPin, HIGH); //使能片选信号
  delayMicroseconds(5);
  WriteByte(add); //发送写寄存器指令
  WriteByte(dat); //写入字节数据
  digitalWrite(rstPin, LOW);
}

3. 接收一个byte的数据

/* 由 DS1302 通信总线上读取一个字节 */
uint8_t DS1302::ReadByte()
{
  uint8_t n, dat = 0, io = 0;
  pinMode(ioPin, INPUT);
  delayMicroseconds(3);
  for (n = 0; n < 8; n++) //读取8位数据
  {
    digitalWrite(clkPin, LOW); //CLK置0后,单片机开始接收数据
    delayMicroseconds(5);
    io = digitalRead(ioPin); //从最低位开始接收
    dat >>= 1;
    if (io)
      dat |= 0x80;
    digitalWrite(clkPin, HIGH);
    delayMicroseconds(1);
  }
  digitalWrite(clkPin, LOW);
  pinMode(ioPin, OUTPUT);
  return dat;
}

4. 读取数据

/* 用单次读操作从某一寄存器读取一个字节,add-寄存器地址,返回值-读到的字节 */
uint8_t DS1302::SingleRead(uint8_t add)
{
  digitalWrite(rstPin, HIGH); //使能片选信号
  delayMicroseconds(5);
  WriteByte(add);           //发送读寄存器指令
  uint8_t dat = ReadByte(); //读取字节数据
  digitalWrite(rstPin, LOW);
  return dat;
}

突发(BURS)模式读/写操作

简单说明

问题描述:在极端的情况下就会出现这样一种情况:假如我们当前的时间是 00:00:59,我们先读秒,读到的秒是 59,然后再去读分钟,而就在读完秒到还未开始读分钟的这段时间内,刚好时间进位了,变成了 00:01:00 这个时间,我们读到的分钟就是 01,显示在液晶上就会出现一个 00:01:59,这个时间很明显是错误的。出现这个问题的概率极小,但却是实实在在可能存在的。

解决方案:DS1302 的突发模式。写操作用 0xBE,读操作用 0xBF, DS1302 收到指令之后,会自动识别出来是 burst 模式,马上把所有的 8 个字节同时锁存到另外的 8 个字节的寄存器缓冲区内,这样时钟继续走,而我们读数据是从另外一个缓冲区内读取的。同理,用 burst 模式写数据,也是先写到这个缓冲区内,最终 DS1302 会把这个缓冲区内的数据一次性送到它的时钟寄存器内。

写入数据

#define BURST_WRITE 0xBE  //突发模式写地址
/* 用突发模式连续写入 8 个寄存器数据,dat-待写入数据指针 */
void DS1302::BurstWrite(uint8_t *dat)
{
  digitalWrite(rstPin, HIGH); //使能片选信号
  delayMicroseconds(5);
  WriteByte(BURST_WRITE); //发送突发写寄存器指令
  for (uint8_t i = 0; i < 8; i++)
  { //连续写入 8 字节数据
    WriteByte(dat[i]);
  }
  digitalWrite(rstPin, LOW);
}
  • 函数调用示例:
//---DS1302时钟初始化2020年4月2日星期四12点00分00秒。---//秒分时日月周年
uint8_t TIME[7] = {0x12, 0x12, 0x12, 0x02, 0x04, 0x04, 0x20};
BurstWrite(TIME);

读取数据

#define BURST_READ 0xBF   //突发模式读地址
/* 用突发模式连续读取 8 个寄存器的数据,dat-读取数据的接收指针 */
void DS1302::BurstRead(uint8_t *dat)
{
  digitalWrite(rstPin, HIGH); //使能片选信号
  delayMicroseconds(5);
  WriteByte(BURST_READ); //发送突发读寄存器指令
  for (uint8_t i = 0; i < 8; i++)
  { //连续读取 8 个字节
    dat[i] = ReadByte();
  }
  digitalWrite(rstPin, LOW);
}

涓细电流充电

充电原理图

在这里插入图片描述
由图可知,TCS、DS、RS为串联关系,必须同时接通才能充电。其中,一个二极管降压0.7V。
充电电流计算:以一个二极管,2k电阻为例。
I = ( V C C 2 − V C C 1 − 1 ∗ 0.7 V ) / 2 k Ω ( m A ) I=(V_{CC2}-V_{CC1}-1*0.7V)/2k\Omega (mA) I=(VCC2VCC110.7V)/2kΩmA

充电控制字节

写命令地址:91H,数据位仅以下组合才可充电。

TCS开启TCS1010
DS1个二极管01
2个二极管10
DS2K电阻01
4K电阻10
8K电阻11

代码示例

/*涓流充电:(CHARGE_TCS|CHARGE_DS[0]|CHARGE_RS[0])*/
#define CHARGE_WRITE 0x90                       //涓流充电寄存器
#define CHARGE_TCS 0xA0                         //10100000 充电模式
const int8_t CHARGE_DS[2] = {0x04, 0x08};       //00000100 一个二极管 00001000 二个二极管
const int8_t CHARGE_RS[3] = {0x01, 0x02, 0x03}; //00000001 电阻2K 00000010 电阻4K 00000011 电阻8K

//充电设置
void DS1302::Charge(bool enable, uint8_t ds, uint8_t rs)
{
  digitalWrite(rstPin, HIGH);
  delayMicroseconds(5); //使能片选信号

  WriteByte(CHARGE_WRITE); //发送写寄存器指令
  if (enable)
  { //开启充电
    WriteByte(CHARGE_TCS | CHARGE_DS[ds] | CHARGE_RS[rs]);
  }
  else
  {
    WriteByte(0x00);
  }

  digitalWrite(rstPin, LOW); //传送数据结束
  delayMicroseconds(2);
}

写保护开关

#define PROTECT_ADDR 0x8E //写保护地址
//写保护开关
void DS1302::Protect(const bool enable)
{
  if (enable)
  { //保护模式,禁止写入
    SingleWrite(PROTECT_ADDR, 0x80);
  }
  else
  {
    SingleWrite(PROTECT_ADDR, 0x00);
  }
}

BCD码和十进制之间的转换

十进制转BCD

uint8_t decToBcd(const uint8_t dec)
{
  const uint8_t tens = dec / 10;
  const uint8_t ones = dec % 10;
  return (tens << 4) | ones;
}

BCD转十进制

uint8_t bcdToDec(const uint8_t bcd)
{
  return (10 * ((bcd & 0xF0) >> 4) + (bcd & 0x0F));
}

参考文献

【1】15.7 DS1302的BURST模式
【2】STM32与DS1302设计时钟芯片,超详细
【3】DS1302时钟程序解读

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值