DS1302时钟芯片+esp8266

        这个芯片往上能找到很多资料,这里主要记录我手里的模块,

看了下芯片资料,说是当vcc 供电小于备用时用备用电源

这里直接没有接vcc 

遇到的问题

1.esp8266复位短路导致串口断开:

当只接scl sda rst  三个引脚的时候 esp8266复位会 导致短路,也有可能是之前我宏定义 复位引脚的时候命名问题,如果你也遇到这个问题,把gnd 接上就行 

2.自己手写的模拟spi 无法正常工作:

改来改去,没办法,还是用了别人写好的库

分析代码 

主体代码

// CONNECTIONS:
// DS1302 CLK/SCLK --> 5
// DS1302 DAT/IO --> 4
// DS1302 RST/CE --> 2
// DS1302 VCC --> 3.3V - 5V
// DS1302 GND --> GND
#include <Arduino.h>
#include <RtcDS1302.h>

// 定义 ThreeWire 对象,用于与 DS1302 RTC 通信
ThreeWire myWire(12, 13, 16); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);

// 打印日期时间的函数
void printDateTime(const RtcDateTime& dt);

void setup() 
{
    // 初始化串口通信
    Serial.begin(57600);

    // 输出编译日期和时间
    Serial.print("compiled: ");
    Serial.print(__DATE__);
    Serial.println(__TIME__);

    // 开始 RTC 通信
    Rtc.Begin();

    // 获取当前编译日期和时间
    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
    printDateTime(compiled);
    Serial.println();

    // 检查 RTC 是否有效
    if (!Rtc.IsDateTimeValid()) 
    {
        // 常见原因:
        // 1) 第一次运行时设备尚未启动
        // 2) 设备电池电量低或缺失
        Serial.println("RTC lost confidence in the DateTime!");
        Rtc.SetDateTime(compiled);
    }

    // 检查 RTC 是否被写保护
    if (Rtc.GetIsWriteProtected())
    {
        Serial.println("RTC was write protected, enabling writing now");
        Rtc.SetIsWriteProtected(false);
    }

    // 检查 RTC 是否正在运行
    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();

    // 检查日期时间是否有效
    if (!now.IsValid())
    {
        // 常见原因:
        // 1) 设备电池电量低或缺失且电源线断开
        Serial.println("RTC lost confidence in the DateTime!");
    }

    // 延时 10 秒
    delay(10000); // 十秒
}

// 宏定义,计算数组长度
#define countof(a) (sizeof(a) / sizeof(a[0]))

// 打印日期时间的函数
void printDateTime(const RtcDateTime& dt)
{
    char datestring[26]; // 存储日期时间字符串

    // 格式化日期时间字符串
    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);
}

看看它库文件是如何定义的 (打开RtcDS1302.h )

#pragma once

#include <Arduino.h>
#include "RtcUtility.h"
#include "RtcDateTime.h"
#include "ThreeWire.h"

// DS1302 寄存器地址
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 读写地址交错
const uint8_t DS1302RamSize = 31;                    // RAM 大小

// DS1302 滴流充电控制寄存器位
enum DS1302TcrResistor 
{
    DS1302TcrResistor_Disabled = 0,                   // 电阻禁用
    DS1302TcrResistor_2KOhm = 0b00000001,             // 2K 欧姆电阻
    DS1302TcrResistor_4KOhm = 0b00000010,             // 4K 欧姆电阻
    DS1302TcrResistor_8KOhm = 0b00000011,             // 8K 欧姆电阻
    DS1302TcrResistor_MASK  = 0b00000011,             // 电阻掩码
};

enum DS1302TcrDiodes 
{
    DS1302TcrDiodes_None = 0,                         // 无二极管
    DS1302TcrDiodes_One      = 0b00000100,            // 一个二极管
    DS1302TcrDiodes_Two      = 0b00001000,            // 两个二极管
    DS1302TcrDiodes_Disabled = 0b00001100,            // 二极管禁用
    DS1302TcrDiodes_MASK     = 0b00001100,            // 二极管掩码
};

enum DS1302TcrStatus 
{
    DS1302TcrStatus_Enabled  = 0b10100000,            // 启用状态
    DS1302TcrStatus_Disabled = 0b01010000,            // 禁用状态
    DS1302TcrStatus_MASK     = 0b11110000,            // 状态掩码
};

const uint8_t DS1302Tcr_Disabled = DS1302TcrStatus_Disabled | DS1302TcrDiodes_Disabled | DS1302TcrResistor_Disabled;  // 默认禁用设置

// DS1302 时钟停止寄存器及位
const uint8_t DS1302_REG_CH = 0x80;                  // 时钟停止位在秒寄存器中的位置
const uint8_t DS1302_CH     = 7;                     // 时钟停止位

// 写保护寄存器及位
const uint8_t DS1302_REG_WP = 0x8E;                  
const uint8_t DS1302_WP = 7;                         // 写保护位

// RTC 类模板
template<class T_WIRE_METHOD> class RtcDS1302
{
public:
    // 构造函数
    RtcDS1302(T_WIRE_METHOD& wire) :
        _wire(wire)
    {
    }

    // 初始化 RTC
    void Begin()
    {
        _wire.begin();
    }

    // 获取是否写保护
    bool GetIsWriteProtected()
    {
        uint8_t wp = getReg(DS1302_REG_WP);
        return !!(wp & _BV(DS1302_WP));
    }

    // 设置是否写保护
    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();
    }

    // 获取 RTC 是否运行
    bool GetIsRunning()
    {
        uint8_t ch = getReg(DS1302_REG_CH);
        return !(ch & _BV(DS1302_CH));
    }

    // 设置 RTC 是否运行
    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) 
        {
            // 无效电阻设置,设置为禁用
            setting = DS1302Tcr_Disabled;
        }
        else if ((setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_Disabled ||
            (setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_None) 
        {
            // 无效二极管设置,设置为禁用
            setting = DS1302Tcr_Disabled;
        }
        else if ((setting & DS1302TcrStatus_MASK) != DS1302TcrStatus_Enabled) 
        {
            // 无效状态设置,设置为禁用
            setting = DS1302Tcr_Disabled;
        }

        setReg(DS1302_REG_TCR, setting);
    }

    // 设置日期时间
    void SetDateTime(const RtcDateTime& dt)
    {
        // 设置日期时间
        _wire.beginTransmission(DS1302_REG_TIMEDATE_BURST);

        _wire.write(Uint8ToBcd(dt.Second()));
        _wire.write(Uint8ToBcd(dt.Minute()));
        _wire.write(Uint8ToBcd(dt.Hour())); // 24 小时模式
        _wire.write(Uint8ToBcd(dt.Day()));
        _wire.write(Uint8ToBcd(dt.Month()));

        // RTC 硬件星期是 1-7,1 表示星期一
        // 转换我们的星期到 RTC 星期
        uint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());

        _wire.write(Uint8ToBcd(rtcDow));
        _wire.write(Uint8ToBcd(dt.Year() - 2000));
        _wire.write(0); // 不写保护,如果写保护则忽略所有这些操作

        _wire.endTransmission();
    }

    // 获取日期时间
    RtcDateTime GetDateTime()
    {
        _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();  // 忽略星期,因为我们自己计算

总结:看不太懂

找找数据手册看看

数据手册icon-default.png?t=O83Ahttps://www.findic.com/doc/browser/bLXENOVde?doc_id=32251673#locale=zh-CN

DS1302中文数据手册 - 豆丁网icon-default.png?t=O83Ahttp:// https://www.docin.com/p-2157760379.html 

电路图 

引脚功能

 时序相关

命令字节:
命令字节启动每个数据传输。MSB(第 7 位)必须是一个逻辑1. 
如果为 0,则禁用对 DS1302 的写入。
如果 逻辑0,则 Bit 6 指定 clock/calendar 数据,
如果 逻辑 1 则指定 RAM 数据。
位 1 至 5 指定要输入或输出的指定寄存器,
LSB(位 0)指定写操作
0的时候是读取
1的时候是写入

命令字节始终以 LSB (位 0) 开头的输入。(这句意思是从低位到高位)

 

时序图:

可以看到当RST在高电平时,芯片才能正常通信

通过时序图可以看出,刚开始的八位发送过去的是命令字节,

数据手册中给出了寄存器地址

根据上述资料 模拟spi 代码实现 

实现失败,留着以后再说................

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐