深入学习RTC时钟库 DS1302

article/2025/8/6 23:38:14

❤️博主介绍❤️
😬 作者:单片机菜鸟哥
👉火爆博客:ESP8266 Arduino教程

零基础从入门到熟悉Arduino平台下开发ESP8266,同时会涉及网络编程知识。专栏文章累计超过60篇,分为基础篇、网络篇、应用篇、高级篇,涵盖ESP8266大部分开发技巧。

👻最近更新:ESP32 MicroPython应用

讲解Python在esp32上的应用,包括网络请求、爬虫

快速导航
单片机菜鸟的博客快速索引(快速找到你要的)

如果觉得有用,麻烦点赞收藏,您的支持是博主创作的动力。

文章目录

    • 1.前言
    • 2.RTC
      • 2.1 简介
      • 2.2 安装
    • 3. DS1302 与 RTC库
      • 3.1 DS1302设计时钟芯片
      • 3.2 DS1302电路图与引脚关系
      • 3.3 DS1302具体操作
        • 3.3.1 DS1302寄存器
        • 3.3.2 RTCDS1302库
        • 3.3.3 RTCDS1302库函数
          • 3.3.3.1 Begin() —— 初始化
          • 3.3.3.2 GetIsWriteProtected() —— 判断是否写保护
          • 3.3.3.3 GetIsWriteProtected() —— 设置是否写保护
          • 3.3.3.4 GetIsRunning() —— 判断时钟是否正在运行
          • 3.3.3.5 SetIsRunning() —— 设置时钟是否运行
          • 3.3.3.6 SetDateTime() —— 设置日期时间
          • 3.3.3.7 GetDateTime() —— 获取日期时间
          • 3.3.3.8 SetMemory() —— 往RTC Memory写入数据
          • 3.3.3.9 GetMemory() —— 读取RTC Memory
        • 3.3.3 DS1302接线
        • 3.3.4 测试用例
          • 3.3.4.1 测试时间
          • 3.3.4.2 测试RTC Memory
    • 4.总结

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”,选择版本安装

image

  • 为了更加了解该库的使用,博主会带着大家剖析源码。首先让我们看看代码结构:

在这里插入图片描述

    代码非常直接明了,分别支持了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电路图与引脚关系

    接下来看看常用电路图以及引脚定义:

在这里插入图片描述

image

3.3 DS1302具体操作

    操作DS1302的大致过程,就是将各种数据或者控制命令写入DS1302的寄存器来完成对应操作(比如设置时间、写保护操作)。然后使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简易电子钟。

3.3.1 DS1302寄存器

    DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表。

image

    此外,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);}else{wp &= ~_BV(DS1302_WP);}setReg(DS1302_REG_WP, wp);}bool IsDateTimeValid(){return GetDateTime().IsValid();}/*** 判断时钟是否正在运行* @return bool*        true 时钟运行*        false 时钟停振,进入低功耗态*/bool GetIsRunning(){uint8_t ch = getReg(DS1302_REG_CH);return !(ch & _BV(DS1302_CH));}void SetIsRunning(bool isRunning){uint8_t ch = getReg(DS1302_REG_CH);if (isRunning){ch &= ~_BV(DS1302_CH);}else{ch |= _BV(DS1302_CH);}setReg(DS1302_REG_CH, ch);}uint8_t GetTrickleChargeSettings(){uint8_t setting = getReg(DS1302_REG_TCR);return setting;}void SetTrickleChargeSettings(uint8_t setting){if ((setting & DS1302TcrResistor_MASK) == DS1302TcrResistor_Disabled) {// invalid resistor setting, set to disabledsetting = DS1302Tcr_Disabled;goto apply;}if ((setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_Disabled ||(setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_None) {// invalid diode setting, set to disabledsetting = DS1302Tcr_Disabled;goto apply;}if ((setting & DS1302TcrStatus_MASK) != DS1302TcrStatus_Enabled) {// invalid status setting, set to disabledsetting = DS1302Tcr_Disabled;goto apply;}apply:setReg(DS1302_REG_TCR, setting);}/*** 设置日期时间* @param RtcDateTime 日期时间对象*/void SetDateTime(const RtcDateTime& dt){// set the date time  批量设置时间_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST);_wire.write(Uint8ToBcd(dt.Second()));//秒数_wire.write(Uint8ToBcd(dt.Minute()));//分钟_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only_wire.write(Uint8ToBcd(dt.Day()));//天数_wire.write(Uint8ToBcd(dt.Month()));//月份// RTC Hardware Day of Week is 1-7, 1 = Monday// convert our Day of Week to Rtc Day of Weekuint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());_wire.write(Uint8ToBcd(rtcDow));_wire.write(Uint8ToBcd(dt.Year() - 2000));//年份_wire.write(0); // no write protect, as all of this is ignored if it is protected_wire.endTransmission();//批量写入寄存器}/*** 获取日期时间* @return RtcDateTime 日期时间对象*/RtcDateTime GetDateTime(){// set the date time  批量获取时间_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST | THREEWIRE_READFLAG);uint8_t second = BcdToUint8(_wire.read() & 0x7F);//秒数uint8_t minute = BcdToUint8(_wire.read());//分钟uint8_t hour = BcdToBin24Hour(_wire.read());//小时uint8_t dayOfMonth = BcdToUint8(_wire.read());//天数uint8_t month = BcdToUint8(_wire.read());//月份_wire.read();  // throwing away day of week as we calculate ituint16_t year = BcdToUint8(_wire.read()) + 2000;//年份_wire.read();  // throwing away write protect flag_wire.endTransmission();//批量处理//返回日期时间对象return RtcDateTime(year, month, dayOfMonth, hour, minute, second);}/**** 往RTC Memory写入数据* @param  memoryAddress 地址偏移量* @param  value 数据*/void SetMemory(uint8_t memoryAddress, uint8_t value){// memory addresses interleaved read and write addresses// so we need to calculate the offsetuint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;if (address <= DS1302_REG_RAMEND){setReg(address, value);}}uint8_t GetMemory(uint8_t memoryAddress){uint8_t value = 0;// memory addresses interleaved read and write addresses// so we need to calculate the offsetuint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;if (address <= DS1302_REG_RAMEND){value = getReg(address);}return value;}uint8_t SetMemory(const uint8_t* pValue, uint8_t countBytes){uint8_t countWritten = 0;//批量处理_wire.beginTransmission(DS1302_REG_RAM_BURST);while (countBytes > 0 && countWritten < DS1302RamSize){_wire.write(*pValue++);countBytes--;countWritten++;}_wire.endTransmission();//返回写入数量return countWritten;}uint8_t GetMemory(uint8_t* pValue, uint8_t countBytes){uint8_t countRead = 0;_wire.beginTransmission(DS1302_REG_RAM_BURST | THREEWIRE_READFLAG);while (countBytes > 0 && countRead < DS1302RamSize){*pValue++ = _wire.read();countRead++;countBytes--;}_wire.endTransmission();return countRead;}private:T_WIRE_METHOD& _wire;uint8_t getReg(uint8_t regAddress){_wire.beginTransmission(regAddress | THREEWIRE_READFLAG);uint8_t regValue = _wire.read();_wire.endTransmission();return regValue;}void setReg(uint8_t regAddress, uint8_t regValue){_wire.beginTransmission(regAddress);_wire.write(regValue);_wire.endTransmission();}
};#endif // __RTCDS1302_H__

3.3.3 RTCDS1302库函数

3.3.3.1 Begin() —— 初始化

函数说明:

/*** 初始化,会把三个引脚设置为输入状态*/
void Begin();
3.3.3.2 GetIsWriteProtected() —— 判断是否写保护

函数说明:

/*** 判断是否写保护* @return bool true表示写保护*/
bool GetIsWriteProtected();

源码说明:

bool GetIsWriteProtected()
{//获取写保护寄存器的值uint8_t wp = getReg(DS1302_REG_WP);//获取最高位的值return !!(wp & _BV(DS1302_WP));
}
3.3.3.3 GetIsWriteProtected() —— 设置是否写保护

函数说明:

/*** 设置是否写保护* @param isWriteProtected*        true 写保护*        false 去掉写保护*/
void SetIsWriteProtected(bool isWriteProtected)

源码说明:

void SetIsWriteProtected(bool isWriteProtected)
{//获取写保护寄存器的值uint8_t wp = getReg(DS1302_REG_WP);if (isWriteProtected){wp |= _BV(DS1302_WP);}else{wp &= ~_BV(DS1302_WP);}setReg(DS1302_REG_WP, wp);
}
3.3.3.4 GetIsRunning() —— 判断时钟是否正在运行

函数说明:

/*** 判断时钟是否正在运行* @return bool*        true 时钟运行*        false 时钟停振,进入低功耗态*/
bool GetIsRunning()

源码说明:

bool GetIsRunning()
{//判断秒寄存器的最高位数值uint8_t ch = getReg(DS1302_REG_CH);return !(ch & _BV(DS1302_CH));
}
3.3.3.5 SetIsRunning() —— 设置时钟是否运行

函数说明:

/*** 设置时钟是否运行* @param isRunning*        true 时钟运行*        false 时钟停振,进入低功耗态*/
void SetIsRunning(bool isRunning)

源码说明:

void SetIsRunning(bool isRunning)
{uint8_t ch = getReg(DS1302_REG_CH);if (isRunning){ch &= ~_BV(DS1302_CH);}else{ch |= _BV(DS1302_CH);}//设置秒寄存器的最高位setReg(DS1302_REG_CH, ch);
}
3.3.3.6 SetDateTime() —— 设置日期时间

函数说明:

/*** 设置日期时间* @param RtcDateTime 日期时间对象*/
void SetDateTime(const RtcDateTime& dt)

源码说明:

/*** 设置日期时间* @param RtcDateTime 日期时间对象*/
void SetDateTime(const RtcDateTime& dt)
{// set the date time  批量设置时间_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST);_wire.write(Uint8ToBcd(dt.Second()));//秒数_wire.write(Uint8ToBcd(dt.Minute()));//分钟_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only_wire.write(Uint8ToBcd(dt.Day()));//天数_wire.write(Uint8ToBcd(dt.Month()));//月份// RTC Hardware Day of Week is 1-7, 1 = Monday// convert our Day of Week to Rtc Day of Weekuint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());_wire.write(Uint8ToBcd(rtcDow));_wire.write(Uint8ToBcd(dt.Year() - 2000));//年份_wire.write(0); // no write protect, as all of this is ignored if it is protected_wire.endTransmission();//批量写入寄存器
}

参数说明:

  • RtcDateTime RTC日期时间对象
class RtcDateTime
{
public:RtcDateTime(uint32_t secondsFrom2000 = 0);RtcDateTime(uint16_t year,uint8_t month,uint8_t dayOfMonth,uint8_t hour,uint8_t minute,uint8_t second) :_yearFrom2000((year >= c_OriginYear) ? year - c_OriginYear : year),_month(month),_dayOfMonth(dayOfMonth),_hour(hour),_minute(minute),_second(second){}// RtcDateTime compileDateTime(__DATE__, __TIME__);RtcDateTime(const char* date, const char* time);bool IsValid() const;uint16_t Year() const{return c_OriginYear + _yearFrom2000;}uint8_t Month() const{return _month;}uint8_t Day() const{return _dayOfMonth;}uint8_t Hour() const{return _hour;}uint8_t Minute() const{return _minute;}uint8_t Second() const{return _second;}// 0 = Sunday, 1 = Monday, ... 6 = Saturdayuint8_t DayOfWeek() const;// 32-bit times as seconds since 1/1/2000uint32_t TotalSeconds() const;uint64_t TotalSeconds64() const;// add secondsvoid operator += (uint32_t seconds){RtcDateTime after = RtcDateTime( TotalSeconds() + seconds );*this = after;}// remove secondsvoid operator -= (uint32_t seconds){RtcDateTime before = RtcDateTime( TotalSeconds() - seconds );*this = before;}// allows for comparisons to just work (==, <, >, <=, >=, !=)operator uint32_t() const{return TotalSeconds();}// Epoch32 supportuint32_t Epoch32Time() const{return TotalSeconds() + c_Epoch32OfOriginYear;}void InitWithEpoch32Time(uint32_t time){_initWithSecondsFrom2000<uint32_t>(time - c_Epoch32OfOriginYear);}// Epoch64 supportuint64_t Epoch64Time() const{return TotalSeconds64() + c_Epoch32OfOriginYear;}void InitWithEpoch64Time(uint64_t time){_initWithSecondsFrom2000<uint64_t>(time - c_Epoch32OfOriginYear);}void InitWithIso8601(const char* date);// convert our Day of Week to Rtc Day of Week // RTC Hardware Day of Week is 1-7, 1 = Mondaystatic uint8_t ConvertDowToRtc(uint8_t dow){if (dow == 0){dow = 7;}return dow;}// convert Rtc Day of Week to our Day of Weekstatic uint8_t ConvertRtcToDow(uint8_t rtcDow){return (rtcDow % 7);}protected:uint8_t _yearFrom2000;uint8_t _month;uint8_t _dayOfMonth;uint8_t _hour;uint8_t _minute;uint8_t _second;template <typename T> void _initWithSecondsFrom2000(T secondsFrom2000){_second = secondsFrom2000 % 60;T timeFrom2000 = secondsFrom2000 / 60;_minute = timeFrom2000 % 60;timeFrom2000 /= 60;_hour = timeFrom2000 % 24;T days = timeFrom2000 / 24;T leapDays;for (_yearFrom2000 = 0;; ++_yearFrom2000){leapDays = (_yearFrom2000 % 4 == 0) ? 1 : 0;if (days < 365U + leapDays)break;days -= 365 + leapDays;}for (_month = 1;; ++_month){uint8_t daysPerMonth = pgm_read_byte(c_daysInMonth + _month - 1);if (leapDays && _month == 2)daysPerMonth++;if (days < daysPerMonth)break;days -= daysPerMonth;}_dayOfMonth = days + 1;}};
3.3.3.7 GetDateTime() —— 获取日期时间

函数说明:

/*** 获取日期时间* @return RtcDateTime 日期时间对象*/
RtcDateTime GetDateTime()

源码说明:

RtcDateTime GetDateTime()
{// set the date time  批量获取时间_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST | THREEWIRE_READFLAG);uint8_t second = BcdToUint8(_wire.read() & 0x7F);//秒数uint8_t minute = BcdToUint8(_wire.read());//分钟uint8_t hour = BcdToBin24Hour(_wire.read());//小时uint8_t dayOfMonth = BcdToUint8(_wire.read());//天数uint8_t month = BcdToUint8(_wire.read());//月份_wire.read();  // throwing away day of week as we calculate ituint16_t year = BcdToUint8(_wire.read()) + 2000;//年份_wire.read();  // throwing away write protect flag_wire.endTransmission();//批量处理//返回日期时间对象return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
3.3.3.8 SetMemory() —— 往RTC Memory写入数据

函数说明:

/**** 往RTC Memory写入数据* @param  memoryAddress 地址偏移量* @param  value 数据*/
void SetMemory(uint8_t memoryAddress, uint8_t value)/*** 往RTC Memory批量写入数据* @param pValue 批量数据* @param countBytes 数据字节数*/
uint8_t SetMemory(const uint8_t* pValue, uint8_t countBytes)

源码说明:

    void SetMemory(uint8_t memoryAddress, uint8_t value){// memory addresses interleaved read and write addresses// so we need to calculate the offsetuint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;if (address <= DS1302_REG_RAMEND){setReg(address, value);}}uint8_t SetMemory(const uint8_t* pValue, uint8_t countBytes){uint8_t countWritten = 0;//批量处理_wire.beginTransmission(DS1302_REG_RAM_BURST);while (countBytes > 0 && countWritten < DS1302RamSize){_wire.write(*pValue++);countBytes--;countWritten++;}_wire.endTransmission();//返回写入数量return countWritten;}
3.3.3.9 GetMemory() —— 读取RTC Memory

函数说明:

/**** 读取RTC Memory* @param  memoryAddress 地址偏移量* @return  数据*/
uint8_t GetMemory(uint8_t memoryAddress)/**** 批量读取RTC Memory* @param pValue 存储空间* @param countBytes 数据字节数*/
uint8_t GetMemory(uint8_t* pValue, uint8_t countBytes)

源码说明:

    uint8_t GetMemory(uint8_t memoryAddress){uint8_t value = 0;// memory addresses interleaved read and write addresses// so we need to calculate the offsetuint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;if (address <= DS1302_REG_RAMEND){value = getReg(address);}return value;}uint8_t GetMemory(uint8_t* pValue, uint8_t countBytes){uint8_t countRead = 0;_wire.beginTransmission(DS1302_REG_RAM_BURST | THREEWIRE_READFLAG);while (countBytes > 0 && countRead < DS1302RamSize){*pValue++ = _wire.read();countRead++;countBytes--;}_wire.endTransmission();return countRead;}

3.3.3 DS1302接线

DS1302采用三总线方式,SCLK(CLK), IO (DAT), CE (RST)。

3.3.4 测试用例

3.3.4.1 测试时间

实验内容

  • 设置时间并在串口上打印时间

实验器材

  • Mega2560 + DS1302

引脚连接

模块引脚Mega2560引脚
VCCVCC
GNDGND
DAT6
CLK5
RST7

实验代码


// CONNECTIONS:
// DS1302 CLK/SCLK --> 5
// DS1302 DAT/IO --> 6
// DS1302 RST/CE --> 7
// DS1302 VCC --> 3.3v - 5v
// DS1302 GND --> GND#include <ThreeWire.h>  
#include <RtcDS1302.h>ThreeWire myWire(/*IO*/6,/*SCLK*/5,/*CE*/7); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);void setup () 
{Serial.begin(57600);Serial.print("compiled: ");Serial.print(__DATE__);Serial.println(__TIME__);Rtc.Begin();RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);printDateTime(compiled);Serial.println();if (Rtc.GetIsWriteProtected()){Serial.println("RTC was write protected, enabling writing now");Rtc.SetIsWriteProtected(false);}if (!Rtc.GetIsRunning()){Serial.println("RTC was not actively running, starting now");Rtc.SetIsRunning(true);}RtcDateTime now = Rtc.GetDateTime();if (now < compiled) {Serial.println("RTC is older than compile time!  (Updating DateTime)");Rtc.SetDateTime(compiled);}else if (now > compiled) {Serial.println("RTC is newer than compile time. (this is expected)");}else if (now == compiled) {Serial.println("RTC is the same as compile time! (not expected but all is fine)");}
}void loop () 
{RtcDateTime now = Rtc.GetDateTime();printDateTime(now);Serial.println();delay(10000); // ten seconds
}#define countof(a) (sizeof(a) / sizeof(a[0]))void printDateTime(const RtcDateTime& dt)
{char datestring[20];snprintf_P(datestring, countof(datestring),PSTR("%02u/%02u/%04u %02u:%02u:%02u"),dt.Month(),dt.Day(),dt.Year(),dt.Hour(),dt.Minute(),dt.Second() );Serial.print(datestring);
}

实验结果:
image

3.3.4.2 测试RTC Memory

实验内容

  • 往RTC Memory存入“danpianjicainiao”
  • 读取存储内容并打印到串口显示

实验器材

  • Mega2560 + DS1302

引脚连接

模块引脚Mega2560引脚
VCCVCC
GNDGND
DAT6
CLK5
RST7

实验代码


// CONNECTIONS:
// DS1302 CLK/SCLK --> 5
// DS1302 DAT/IO --> 6
// DS1302 RST/CE --> 7
// DS1302 VCC --> 3.3v - 5v
// DS1302 GND --> GND#include <ThreeWire.h>  
#include <RtcDS1302.h>ThreeWire myWire(/*IO*/6,/*SCLK*/5,/*CE*/7); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);#define countof(a) (sizeof(a) / sizeof(a[0]))const char data[] = "danpianjicainiao";void setup () 
{Serial.begin(57600);Serial.print("compiled: ");Serial.print(__DATE__);Serial.println(__TIME__);Rtc.Begin();RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);printDateTime(compiled);Serial.println();if (Rtc.GetIsWriteProtected()){Serial.println("RTC was write protected, enabling writing now");Rtc.SetIsWriteProtected(false);}if (!Rtc.GetIsRunning()){Serial.println("RTC was not actively running, starting now");Rtc.SetIsRunning(true);}RtcDateTime now = Rtc.GetDateTime();if (now < compiled) {Serial.println("RTC is older than compile time!  (Updating DateTime)");Rtc.SetDateTime(compiled);}/* comment out on a second run to see that the info is stored long term */// Store something in memory on the RTCuint8_t count = sizeof(data);uint8_t written = Rtc.SetMemory((const uint8_t*)data, count); // this includes a null terminator for the stringif (written != count) {Serial.print("something didn't match, count = ");Serial.print(count, DEC);Serial.print(", written = ");Serial.print(written, DEC);Serial.println();}
/* end of comment out section */
}void loop () 
{RtcDateTime now = Rtc.GetDateTime();printDateTime(now);Serial.println(" +");delay(5000);// read datauint8_t buff[20];const uint8_t count = sizeof(buff);// get our datauint8_t gotten = Rtc.GetMemory(buff, count);if (gotten != count) {Serial.print("something didn't match, count = ");Serial.print(count, DEC);Serial.print(", gotten = ");Serial.print(gotten, DEC);Serial.println();}Serial.print("data read (");Serial.print(gotten);Serial.print(") = \"");// print the string, but terminate if we get a nullfor (uint8_t ch = 0; ch < gotten && buff[ch]; ch++){Serial.print((char)buff[ch]);}Serial.println("\"");delay(5000);
}void printDateTime(const RtcDateTime& dt)
{char datestring[20];snprintf_P(datestring, countof(datestring),PSTR("%02u/%02u/%04u %02u:%02u:%02u"),dt.Month(),dt.Day(),dt.Year(),dt.Hour(),dt.Minute(),dt.Second() );Serial.print(datestring);
}

实验结果:
在这里插入图片描述

4.总结

本博文讲解如何使用RTC时钟库来操作DS1302,同时附带源码解析,请关注下一篇DS3231.


http://chatgpt.dhexx.cn/article/p7AS6QVF.shtml

相关文章

深入学习 RTC时钟库 DS3231

❤️博主介绍❤️ &#x1f62c; 作者&#xff1a;单片机菜鸟哥 &#x1f449;火爆博客&#xff1a;ESP8266 Arduino教程 零基础从入门到熟悉Arduino平台下开发ESP8266&#xff0c;同时会涉及网络编程知识。专栏文章累计超过60篇&#xff0c;分为基础篇、网络篇、应用篇、高级篇…

rtc时钟

一、设计效果 配置RTC时钟&#xff0c;初始化为2000年1月1日00:00:00&#xff1b;通过RTC时钟秒中断串口每秒打印一次当前时刻&#xff0c;并切换一次流水灯状态&#xff1b;配置闹铃为10:00:05&#xff0c;在闹铃中断中每秒切换一次蜂鸣器状态闹铃&#xff0c;直到按KEY1关闭…

RTC时钟实现实时日历

文章目录 1、RTC时钟简介1.2、初识RTC1.2、相关寄存器 2、创建项目23、完善代码4、总结 1、RTC时钟简介 1.2、初识RTC 1、简介&#xff1a; RTC—real time clock&#xff0c;实时时钟&#xff0c;主要包含日历、闹钟和自动唤醒这三部分的功能&#xff0c;其中的日历功能我们使…

STM32之RTC时钟

前言 了解实时时钟RTC的原理。STM32芯片自带RTC&#xff0c;因此不须像其他MCU需外接RTC模块。请编程实现STM32的日历读取、设置和输出。要求&#xff1a; 1&#xff09;读取RTC初始时间&#xff0c;验证是否为 1970年1月1日零分零秒&#xff1b; 2&#xff09;将RTC时间调整为…

【STM32】HAL库 STM32CubeMX教程十三---RTC时钟

前言&#xff1a; 本系列教程将 对应外设原理&#xff0c;HAL库与STM32CubeMX结合在一起讲解&#xff0c;使您可以更快速的学会各个模块的使用 所用工具&#xff1a; 1、芯片&#xff1a; STM32F407ZET6/ STM32F103ZET6 2、STM32CubeMx软件 3、IDE&#xff1a; MDK-Keil软…

【STM32】详解RTC实时时钟的概念和配置示例代码

一、什么是RTC RTC(Real-time Clock)&#xff1a;实时时钟&#xff0c;本质上是一个支持BCD编码的定时器/计数器。主电源断电后能够由电池供电&#xff0c;使其时钟跳转依然正常。 二、STM32F4芯片内的RTC功能 ①日历时钟&#xff08;时分秒、年月日、星期&#xff09; ②两个闹…

android小错误:Failure retrieving text 0x7f050001 in package

1.在启动android应用程序的过程中&#xff0c;logcat打印如下的错误&#xff1a; 报错的原因&#xff1a;资源的id没有找到。资源在R.java文件中&#xff0c;找到0x7f050001 对应的定义 R.java public static final int AppTheme0x7f050001; AppTheme这个文件在AndroidMan…

Windows7系统蓝屏-解决办法, 错误代码:0x0000007F

1.电脑突然蓝屏提示stop:0x0000007F&#xff0c;如下图所示&#xff1a; 2.故障排除 重启电脑&#xff0c;一直按F8&#xff0c;进入“安全模式”&#xff0c;如能正常进入系统&#xff0c;查看系统错误日志。针对系统记录的错误日志&#xff0c;解决问题。如下图&#xff0c;…

java.lang.IllegalArgumentException No view found for id 0x7

java.lang.IllegalArgumentException No view found for id 0x7 布局上找不到这个View&#xff0c;看下ERROR的地方&#xff0c;可以看到是因为Container找不到因此报错了。 从布局入手&#xff0c;参考了很多文章主要分为以下两种原因 1 Fragment 嵌套了 Fragment 例如&…

Fragment报java.lang.IllegalArgumentException:No view found for id 0x7f070250的错误

我用的是Fragment嵌套Fragment做的&#xff0c;放fragment切换快的时候程序就会崩溃&#xff0c;解决这个办法就是在View生成前先将FragemnentManger创建好&#xff0c;就不会报错了

Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f解析

先看日志报错这个错误纠结我两天了&#xff0c;真的要崩溃了~_~ 关于android.content.res.Resources$NotFoundException: Resource ID的问题&#xff0c;那行代码是onCreate加载.xml布局&#xff0c;是加载的R.layout.xxxx&#xff0c;不是R.id.xxxx&#xff0c;布局文件存在&a…

关于No view found for id 0x7f080135 (com.xxx.xxx:id/viewpager) for fragment PopupWindow

最近在开发项目中&#xff0c;遇到了一个问题。PopupWindow中无法嵌套viewpagerFragment&#xff0c;现在进行总结一下。 问题描述&#xff1a;在Fragment中弹出一个PopupWindow,PopupWindow中用viewpager加载多个Fragment时出现上面问题。 网上搜的都是那些什么没有设置id之…

流水灯设计

流水灯设计 目的与要求 通过采用单片机控制8个LED发光二极管顺序点亮的流水灯系统设计与制作&#xff0c;让读者了解C语言的数据类型、常量与变量、运算符和表达式等基本概念及使用方法。 设计要求&#xff1a;首先点亮连接到P1.7引脚的发光二极管&#xff0c;延时一定时间后…

IT管理人才必备的十大能力

公众号回复&#xff1a;干货&#xff0c;领取价值58元/套IT管理体系文档 公众号回复&#xff1a;ITIL教材&#xff0c;领取最新ITIL4中文教材 正文 作为IT技术人员&#xff0c;相信没有一个人愿意永远在底层编写程序或做简单的系统维护。经过一段时间的技术和经验的积累&#x…

他,连续 3 年担任新星计划导师,这次的内容有点特别

一、新星计划 新星计划是一个发掘潜力新人、培养优质博主为目标的创作活动&#xff0c;通过为期两周的时间&#xff0c;明白为什么要写博客&#xff0c;写作的意义是什么&#xff1f;制定学习计划&#xff0c;完善Java知识体系。 二、学习计划 创作打卡阶段第1周&#xff08…

Python 彻底甩掉 Java,位居 48 种编程语言之首!

Python 彻底甩掉 Java&#xff0c;位居 48 种编程语言之首&#xff01; 昨日&#xff0c;IEEE Spectrum 杂志发布了一年一度的编程语言排行榜&#xff0c;这个排行榜已经连续发布了五年。对于每位开发者而言&#xff0c;想要衡量编程语言流行度则需要依赖相对流行的网站统计数据…

java并发问题概述

转自 https://www.jb51.net/article/131411.htm java并发问题概述 转载 更新时间&#xff1a;2017年12月25日 09:28:54 作者&#xff1a;人圭先生 我要评论 这篇文章主要介绍了java并发问题概述&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。 1什么是…

【Java基础系列教程】第一章 编程入门

一、计算机概述 1.1 计算机简介 计算机&#xff08;computer&#xff09;俗称电脑&#xff0c;是现代一种用于高速计算的电子计算机器&#xff0c;可以进行数值计算&#xff0c;又可以进行逻辑计算&#xff0c;还具有存储记忆功能。是能够按照程序运行&#xff0c;自动、高速处…

关于程序员这14条经典定律,我全中~

定律1:最难定位的问题要么是最疑难的问题,要么是最低级的问题,这两种问题都有一个共同特征,就是让你意想不到。 举一个例子,一次代码编译不过,报函数没有定义,开始怀疑是类没有“;”结束符,然后怀疑有没有匹配的“{”,折腾了好久,最后才发现是开头的“#ifndef”定义…

系统性能优化的十大策略(强烈推荐,建议收藏)

点击关注公众号&#xff0c;实用技术文章及时了解 上篇 提升系统性能&#xff0c;榨干计算机资源是程序员的极致追求&#xff0c;今天跟大家聊聊性能优化。分为上中下三篇&#xff0c;由浅及深的写了关于性能优化的方方面面&#xff0c;并不仅仅局限于代码层面&#xff0c;希望…