目录
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; ★ 可选工业级温度范围-400 85; ★ 主电源和备份电源供应采用双电源管;
引脚说明
VCC二、主电源引脚 X1、X2:32.768kHz外部晶振引脚(6 pF的负载电容CL ) GND:地 RST:复位引脚(也称为CE) I/O:串行数据引脚、数据输出或输入都来自这个引脚 SCLK:串行时钟引脚 VCC1:备用电源
时序解读
- 复位时序RST引脚产生正脉冲。RST=1.读完字节后,要注意RST准备下一个读写周期;
- 单字节阅读。先写寄存器的命令,从最低点写;写数据是在SCLK实现阅读数据的上升沿SCLK实现了下降边缘。因此,在单字节阅读顺序中,写命令的第八个上升边缘结束后第八个下降边将在数据线上读取寄存器的第一个数据!读取的数据从最低水平开始。
- 单字节写,两个字节的数据可以用16个上升沿写入数据。
- 写在缓冲区,最后 DS1302 缓冲区的数据将一次性发送到时钟寄存器。
寄存器及其功能
地址/命令字节
- 第七名必须是1;
- 第六位:位置1,操作RAM存储器;放0,操作clock寄存器;
- 第0位:置1,读数据;置0,写数据。
数据字节
-
秒寄存器的CH位:
- 1.时钟停止振动,进入低功耗状态;
- 时钟工作。 小时寄存器D7位:
- 置1,12小时制(D5置1表示上午,置0表示下午);
- 0,24小时制(此时)D5、D四组成小时十位)。 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 的突发模式。 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=(VCC2−VCC1−1∗0.7V)/2kΩ(mA)
充电控制字节
写命令地址:91H,数据位仅以下组合才可充电。
| TCS | 开启TCS | 1010 |
| DS | 1个二极管 | 01 |
| 2个二极管 | 10 | |
| DS | 2K电阻 | 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时钟程序解读