1.前言
最近博主在弄8266编程的时候,偶然发现两个全新时钟模块压仓货:
- DS1302
- DS3231
为了避免资源浪费以及重复编写代码,博主还是抱着尝试的心态去寻找能够同时兼容 DS1302、DS3231甚至其他的时钟模块的第三方库。终于,还是被我找到了 —— Rtc 时钟库。
2.RTC
2.1 简介
- Arduino Real Time Clock library(Arduino平台的实时时钟库)
- 支持DS1302、DS1307、DS3231、DS3234
- 英文文档参考 wiki
2.2 安装
- 打开Arduino IDE的库管理器,然后搜索“Rtc by Makuna”,选择版本安装
- 为了更加了解该库的使用,博主会带着大家剖析源码。首先让我们看看代码结构:
代码非常直接明了,分别支持了DS1302、DS1307、DS3231、DS3234。但是由于博主资源限制,本篇只会讨论DS1302以及DS3231,其他请读者自行学习。
3. DS1302 与 RTC库
3.1 DS1302设计时钟芯片
网上介绍DS1302的帖子非常多,博主在这里就不从零开始讲解,这里推荐一个博主觉得写得还可以的参考文档 STM32与DS1302设计时钟芯片,超详细。
认真看完上面参考文档之后,博主得到几个我比较关心的点:
- DS1302是一个实时时钟芯片,可以提供秒、分、小时、日期、月、年等信息,并且还有闰年自动调整的能力,可以通过配置AM/PM来决定采用24小时格式还是12小时格式;
- 仅需用到三个口线:(1)RES 复位(2)I/O 数据线(3)SCLK串行时钟;
- 拥有31字节数据存储RAM(RTC Memory);
- DS1302这种时钟芯片功耗一般都很低,它在工作电压2.0V的时候,工作电流小于300nA;
- DS1302的工作电压比较宽,大概是2.0V~5.5V都可以正常工作。采用双电源供电,当主电源比备用电源高0.2V时,由主电源供电,否则采用备用电源,一般是一个纽扣电池;
- 读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式;
3.2 DS1302电路图与引脚关系
接下来看看常用电路图以及引脚定义:
3.3 DS1302具体操作
操作DS1302的大致过程,就是将各种数据或者控制命令写入DS1302的寄存器来完成对应操作(比如设置时间、写保护操作)。然后使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简易电子钟。
3.3.1 DS1302寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表。
此外,DS1302 还有控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。
DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
3.3.2 RTCDS1302库
上面只是介绍理论,在理解理论的基础上,我们开始讲解RTC库的使用。以下是RTCDS1302库的源码(参考源码注释):
-
-
- #ifndef __RTCDS1302_H__
- #define __RTCDS1302_H__
-
- #include <Arduino.h>
- #include "RtcDateTime.h"
- #include "RtcUtility.h"
-
-
-
- //DS1302 Register Addresses 寄存器地址
- const uint8_t DS1302_REG_TIMEDATE = 0x80;//秒寄存器
- const uint8_t DS1302_REG_TIMEDATE_BURST = 0xBE;//时钟批量处理寄存器
- const uint8_t DS1302_REG_TCR = 0x90;//涓流充电控制寄存器
- const uint8_t DS1302_REG_RAM_BURST = 0xFE;//RAM批量处理寄存器
- const uint8_t DS1302_REG_RAMSTART = 0xc0;//ram空间第一个字节
- const uint8_t DS1302_REG_RAMEND = 0xfd;//ram空间最后一个字节
- // ram read and write addresses are interleaved
- const uint8_t DS1302RamSize = 31;//ram空间大小
-
-
- // DS1302 Trickle Charge Control Register Bits 以下跟涓流充电有关 可忽略
- enum DS1302TcrResistor {
- DS1302TcrResistor_Disabled = 0,
- DS1302TcrResistor_2KOhm = B00000001,
- DS1302TcrResistor_4KOhm = B00000010,
- DS1302TcrResistor_8KOhm = B00000011,
- DS1302TcrResistor_MASK = B00000011,
- };
-
- enum DS1302TcrDiodes {
- DS1302TcrDiodes_None = 0,
- DS1302TcrDiodes_One = B00000100,
- DS1302TcrDiodes_Two = B00001000,
- DS1302TcrDiodes_Disabled = B00001100,
- DS1302TcrDiodes_MASK = B00001100,
- };
-
- enum DS1302TcrStatus {
- DS1302TcrStatus_Enabled = B10100000,
- DS1302TcrStatus_Disabled = B01010000,
- DS1302TcrStatus_MASK = B11110000,
- };
-
- const uint8_t DS1302Tcr_Disabled = DS1302TcrStatus_Disabled | DS1302TcrDiodes_Disabled | DS1302TcrResistor_Disabled;
-
- // DS1302 Clock Halt Register & Bits
- const uint8_t DS1302_REG_CH = 0x80; // bit in the seconds register 秒寄存器
- const uint8_t DS1302_CH = 7;
-
- // Write Protect Register & Bits
- const uint8_t DS1302_REG_WP = 0x8E; //写保护寄存器
- const uint8_t DS1302_WP = 7;
-
- template<class T_WIRE_METHOD> class RtcDS1302
- {
- public:
- RtcDS1302(T_WIRE_METHOD& wire) :
- _wire(wire)
- {
- }
-
- void Begin()
- {
- //会把三个引脚设置为输入状态
- _wire.begin();
- }
-
- /**
- * 判断是否写保护
- * @return bool true表示写保护
- */
- bool GetIsWriteProtected()
- {
- //获取写保护寄存器的值
- uint8_t wp = getReg(DS1302_REG_WP);
- //获取最高位的值
- return !!(wp & _BV(DS1302_WP));
- }
-
- /**
- * 设置是否写保护
- * @param isWriteProtected
- * true 写保护
- * false 去掉写保护
- */
- void SetIsWriteProtected(bool isWriteProtected)
- {
- //获取写保护寄存器的值
- uint8_t wp = getReg(DS1302_REG_WP);
- if (isWriteProtected)
- {
- wp |= _BV(DS1302_WP