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(); // 忽略星期,因为我们自己计算
总结:看不太懂
找找数据手册看看
数据手册https://www.findic.com/doc/browser/bLXENOVde?doc_id=32251673#locale=zh-CN
DS1302中文数据手册 - 豆丁网http:// 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 代码实现
实现失败,留着以后再说................