初始化提交

This commit is contained in:
王立帮
2024-07-20 22:09:06 +08:00
commit c247dd07a6
6876 changed files with 2743096 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1,22 @@
# Rtc
Arduino Real Time Clock library.
An RTC library with deep device support.
[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4)
For quick questions jump on Gitter and ask away.
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/Rtc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
For bugs, make sure there isn't an active issue and then create one.
## Documentation
[See Wiki](https://github.com/Makuna/Rtc/wiki)
## Installing This Library (prefered, you just want to use it)
Open the Library Manager and search for "Rtc by Makuna" and install
## Installing This Library From GitHub (advanced, you want to contribute)
Create a directory in your Arduino\Library folder named "Rtc"
Clone (Git) this project into that folder.
It should now show up in the import list when you restart Arduino IDE.

View File

@@ -0,0 +1,8 @@
# Support
For questions and help, jump on Gitter and ask away.
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/Rtc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
For documentation [See the Wiki](https://github.com/Makuna/Rtc/wiki)
For bugs, make sure there isn't an active issue and then create one. Understand that issues are for bugs found in the library and not issues you are having with the library.

View File

@@ -0,0 +1,135 @@
// CONNECTIONS:
// DS1302 CLK/SCLK --> 5
// DS1302 DAT/IO --> 4
// DS1302 RST/CE --> 2
// DS1302 VCC --> 3.3v - 5v
// DS1302 GND --> GND
#include <ThreeWire.h>
#include <RtcDS1302.h>
ThreeWire myWire(4,5,2); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
#define countof(a) (sizeof(a) / sizeof(a[0]))
const char data[] = "what time is it";
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.IsDateTimeValid())
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
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 RTC
uint8_t count = sizeof(data);
uint8_t written = Rtc.SetMemory((const uint8_t*)data, count); // this includes a null terminator for the string
if (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(" +");
if (!now.IsValid())
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
delay(5000);
// read data
uint8_t buff[20];
const uint8_t count = sizeof(buff);
// get our data
uint8_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 null
for (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);
}

View File

@@ -0,0 +1,101 @@
// CONNECTIONS:
// DS1302 CLK/SCLK --> 5
// DS1302 DAT/IO --> 4
// DS1302 RST/CE --> 2
// DS1302 VCC --> 3.3v - 5v
// DS1302 GND --> GND
#include <ThreeWire.h>
#include <RtcDS1302.h>
ThreeWire myWire(4,5,2); // 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.IsDateTimeValid())
{
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
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();
if (!now.IsValid())
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
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);
}

View File

@@ -0,0 +1,172 @@
// CONNECTIONS:
// DS1307 SDA --> SDA
// DS1307 SCL --> SCL
// DS1307 VCC --> 5v
// DS1307 GND --> GND
#define countof(a) (sizeof(a) / sizeof(a[0]))
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS1307.h>
SoftwareWire myWire(SDA, SCL);
RtcDS1307<SoftwareWire> Rtc(myWire);
for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS1307.h>
RtcDS1307<TwoWire> Rtc(Wire);
/* for normal hardware wire use above */
const char data[] = "what time is it";
void setup ()
{
Serial.begin(57600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
}
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);
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.SetSquareWavePin(DS1307SquareWaveOut_Low);
/* comment out on a second run to see that the info is stored long term */
// Store something in memory on the RTC
Rtc.SetMemory(0, 13);
uint8_t written = Rtc.SetMemory(13, (const uint8_t*)data, sizeof(data) - 1); // remove the null terminator strings add
Rtc.SetMemory(1, written);
/* end of comment out section */
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
delay(5000);
// read data
// get the offset we stored our data from address zero
uint8_t address = Rtc.GetMemory(0);
if (address != 13)
{
Serial.println("address didn't match");
}
else
{
// get the size of the data from address 1
uint8_t count = Rtc.GetMemory(1);
uint8_t buff[20];
// get our data from the address with the given size
uint8_t gotten = Rtc.GetMemory(address, buff, count);
if (gotten != count ||
count != sizeof(data) - 1) // remove the extra null terminator strings add
{
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(") = \"");
for (uint8_t ch = 0; ch < gotten; 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);
}

View File

@@ -0,0 +1,137 @@
// CONNECTIONS:
// DS1307 SDA --> SDA
// DS1307 SCL --> SCL
// DS1307 VCC --> 5v
// DS1307 GND --> GND
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS1307.h>
SoftwareWire myWire(SDA, SCL);
RtcDS1307<SoftwareWire> Rtc(myWire);
for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS1307.h>
RtcDS1307<TwoWire> Rtc(Wire);
/* for normal hardware wire use above */
void setup ()
{
Serial.begin(57600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
// following line sets the RTC to the date & time this sketch was compiled
// it will also reset the valid flag internally unless the Rtc device is
// having an issue
Rtc.SetDateTime(compiled);
}
}
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)");
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.SetSquareWavePin(DS1307SquareWaveOut_Low);
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
}
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);
}

View File

@@ -0,0 +1,207 @@
// CONNECTIONS:
// DS3231 SDA --> SDA
// DS3231 SCL --> SCL
// DS3231 VCC --> 3.3v or 5v
// DS3231 GND --> GND
// SQW ---> (Pin19) Don't forget to pullup (4.7k to 10k to VCC)
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
SoftwareWire myWire(SDA, SCL);
RtcDS3231<SoftwareWire> Rtc(myWire);
for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);
/* for normal hardware wire use above */
// Interrupt Pin Lookup Table
// (copied from Arduino Docs)
//
// CAUTION: The interrupts are Arduino numbers NOT Atmel numbers
// and may not match (example, Mega2560 int.4 is actually Atmel Int2)
// this is only an issue if you plan to use the lower level interupt features
//
// Board int.0 int.1 int.2 int.3 int.4 int.5
// ---------------------------------------------------------------
// Uno, Ethernet 2 3
// Mega2560 2 3 21 20 [19] 18
// Leonardo 3 2 0 1 7
#define RtcSquareWavePin 19 // Mega2560
#define RtcSquareWaveInterrupt 4 // Mega2560
// marked volatile so interrupt can safely modify them and
// other code can safely read and modify them
volatile uint16_t interuptCount = 0;
volatile bool interuptFlag = false;
void ISR_ATTR InteruptServiceRoutine()
{
// since this interupted any other running code,
// don't do anything that takes long and especially avoid
// any communications calls within this routine
interuptCount++;
interuptFlag = true;
}
void setup ()
{
Serial.begin(57600);
// set the interupt pin to input mode
pinMode(RtcSquareWavePin, INPUT);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
}
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);
}
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeAlarmBoth);
// Alarm 1 set to trigger every day when
// the hours, minutes, and seconds match
RtcDateTime alarmTime = now + 88; // into the future
DS3231AlarmOne alarm1(
alarmTime.Day(),
alarmTime.Hour(),
alarmTime.Minute(),
alarmTime.Second(),
DS3231AlarmOneControl_HoursMinutesSecondsMatch);
Rtc.SetAlarmOne(alarm1);
// Alarm 2 set to trigger at the top of the minute
DS3231AlarmTwo alarm2(
0,
0,
0,
DS3231AlarmTwoControl_OncePerMinute);
Rtc.SetAlarmTwo(alarm2);
// throw away any old alarm state before we ran
Rtc.LatchAlarmsTriggeredFlags();
// setup external interupt
attachInterrupt(RtcSquareWaveInterrupt, InteruptServiceRoutine, FALLING);
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
Serial.println("RTC lost confidence in the DateTime!");
}
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
// we only want to show time every 10 seconds
// but we want to show responce to the interupt firing
for (int timeCount = 0; timeCount < 20; timeCount++)
{
if (Alarmed())
{
Serial.print(">>Interupt Count: ");
Serial.print(interuptCount);
Serial.println("<<");
}
delay(500);
}
}
bool Alarmed()
{
bool wasAlarmed = false;
if (interuptFlag) // check our flag that gets sets in the interupt
{
wasAlarmed = true;
interuptFlag = false; // reset the flag
// this gives us which alarms triggered and
// then allows for others to trigger again
DS3231AlarmFlag flag = Rtc.LatchAlarmsTriggeredFlags();
if (flag & DS3231AlarmFlag_Alarm1)
{
Serial.println("alarm one triggered");
}
if (flag & DS3231AlarmFlag_Alarm2)
{
Serial.println("alarm two triggered");
}
}
return wasAlarmed;
}
#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);
}

View File

@@ -0,0 +1,197 @@
// CONNECTIONS:
// DS1307 SDA --> SDA
// DS1307 SCL --> SCL
// DS1307 VCC --> 5v
// DS1307 GND --> GND
#define countof(a) (sizeof(a) / sizeof(a[0]))
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
#include <EepromAT24C32.h>
SoftwareWire myWire(SDA, SCL);
RtcDS1307<SoftwareWire> Rtc(myWire);
/* for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
#include <EepromAT24C32.h>
RtcDS3231<TwoWire> Rtc(Wire);
EepromAt24c32<TwoWire> RtcEeprom(Wire);
// if you have any of the address pins on the RTC soldered together
// then you need to provide the state of those pins, normally they
// are connected to vcc with a reading of 1, if soldered they are
// grounded with a reading of 0. The bits are in the order A2 A1 A0
// thus the following would have the A2 soldered together
// EepromAt24c32<TwoWire> RtcEeprom(Wire, 0b011);
/* for normal hardware wire use above */
// nothing longer than 32 bytes
// rtc eeprom memory is 32 byte pages
// writing is limited to each page, so it will wrap at page
// boundaries.
// But reading is only limited by the buffer in Wire class which
// by default is 32
const char data[] = "What time is it in Greenwich?";
const uint16_t stringAddr = 64; // stored on page boundary
void setup ()
{
Serial.begin(57600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcEeprom.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
}
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);
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
/* comment out on a second run to see that the info is stored long term */
// Store something in memory on the Eeprom
// store starting address of string
RtcEeprom.SetMemory(0, stringAddr);
// store the string, nothing longer than 32 bytes due to paging
uint8_t written = RtcEeprom.SetMemory(stringAddr, (const uint8_t*)data, sizeof(data) - 1); // remove the null terminator strings add
// store the length of the string
RtcEeprom.SetMemory(1, written); // store the
/* end of comment out section */
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
delay(5000);
// read data
// get the offset we stored our data from address zero
uint8_t address = RtcEeprom.GetMemory(0);
if (address != stringAddr)
{
Serial.print("address didn't match ");
Serial.println(address);
}
{
// get the size of the data from address 1
uint8_t count = RtcEeprom.GetMemory(1);
uint8_t buff[64];
// get our data from the address with the given size
uint8_t gotten = RtcEeprom.GetMemory(address, buff, count);
if (gotten != count ||
count != sizeof(data) - 1) // remove the extra null terminator strings add
{
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(") = \"");
for (uint8_t ch = 0; ch < gotten; 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);
}

View File

@@ -0,0 +1,145 @@
// CONNECTIONS:
// DS3231 SDA --> SDA
// DS3231 SCL --> SCL
// DS3231 VCC --> 3.3v or 5v
// DS3231 GND --> GND
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
SoftwareWire myWire(SDA, SCL);
RtcDS3231<SoftwareWire> Rtc(myWire);
for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);
/* for normal hardware wire use above */
void setup ()
{
Serial.begin(57600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
// following line sets the RTC to the date & time this sketch was compiled
// it will also reset the valid flag internally unless the Rtc device is
// having an issue
Rtc.SetDateTime(compiled);
}
}
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)");
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
if (Rtc.LastError() != 0)
{
// we have a communications error
// see https://www.arduino.cc/en/Reference/WireEndTransmission for
// what the number means
Serial.print("RTC communications error = ");
Serial.println(Rtc.LastError());
}
else
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
RtcTemperature temp = Rtc.GetTemperature();
temp.Print(Serial);
// you may also get the temperature as a float and print it
// Serial.print(temp.AsFloatDegC());
Serial.println("C");
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);
}

View File

@@ -0,0 +1,100 @@
// CONNECTIONS:
// DS3231 SDA --> SDA
// DS3231 SCL --> SCL
// DS3231 VCC --> 3.3v or 5v
// DS3231 GND --> GND
/* for software wire use below
#include <SoftwareWire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
SoftwareWire myWire(SDA, SCL);
RtcDS3231<SoftwareWire> Rtc(myWire);
for software wire use above */
/* for normal hardware wire use below */
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);
/* for normal hardware wire use above */
void setup ()
{
Serial.begin(57600);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
//--------RTC SETUP ------------
// if you are using ESP-01 then uncomment the line below to reset the pins to
// the available pins for SDA, SCL
// Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
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);
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
}
void loop ()
{
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
for(;;)
{
Rtc.SetIsRunning(false);
Serial.println(">>> Rtc ready for storage <<<");
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);
}

View File

@@ -0,0 +1,179 @@
// Reference for connecting SPI see https://www.arduino.cc/en/Reference/SPI
// CONNECTIONS:
// DS3234 MISO --> MISO
// DS3234 MOSI --> MOSI
// DS3234 CLK --> CLK (SCK)
// DS3234 CS (SS) --> 5 (pin used to select the DS3234 on the SPI)
// DS3234 VCC --> 3.3v or 5v
// DS3234 GND --> GND
// SQW ---> (Pin19) Don't forget to pullup (4.7k to 10k to VCC)
const uint8_t DS3234_CS_PIN = 5;
#include <SPI.h>
#include <RtcDS3234.h>
RtcDS3234<SPIClass> Rtc(SPI, DS3234_CS_PIN);
// Interrupt Pin Lookup Table
// (copied from Arduino Docs)
//
// CAUTION: The interrupts are Arduino numbers NOT Atmel numbers
// and may not match (example, Mega2560 int.4 is actually Atmel Int2)
// this is only an issue if you plan to use the lower level interupt features
//
// Board int.0 int.1 int.2 int.3 int.4 int.5
// ---------------------------------------------------------------
// Uno, Ethernet 2 3
// Mega2560 2 3 21 20 [19] 18
// Leonardo 3 2 0 1 7
// esp8266 (pin and interrupt should be the same thing)
// esp32 (pin and interrupt should be the same thing)
#define RtcSquareWavePin 19 // Mega2560
#define RtcSquareWaveInterrupt 4 // Mega2560
// marked volatile so interrupt can safely modify them and
// other code can safely read and modify them
volatile uint16_t interuptCount = 0;
volatile bool interuptFlag = false;
void ISR_ATTR InteruptServiceRoutine()
{
// since this interupted any other running code,
// don't do anything that takes long and especially avoid
// any communications calls within this routine
interuptCount++;
interuptFlag = true;
}
void setup ()
{
Serial.begin(115200);
while (!Serial);
// set the interupt pin to input mode
pinMode(RtcSquareWavePin, INPUT_PULLUP); // external pullup maybe required still
SPI.begin();
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
if (!Rtc.IsDateTimeValid())
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
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);
}
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3234SquareWavePin_ModeAlarmBoth);
// Alarm 1 set to trigger every day when
// the hours, minutes, and seconds match
RtcDateTime alarmTime = now + 88; // into the future
DS3234AlarmOne alarm1(
alarmTime.Day(),
alarmTime.Hour(),
alarmTime.Minute(),
alarmTime.Second(),
DS3234AlarmOneControl_HoursMinutesSecondsMatch);
Rtc.SetAlarmOne(alarm1);
// Alarm 2 set to trigger at the top of the minute
DS3234AlarmTwo alarm2(
0,
0,
0,
DS3234AlarmTwoControl_OncePerMinute);
Rtc.SetAlarmTwo(alarm2);
// throw away any old alarm state before we ran
Rtc.LatchAlarmsTriggeredFlags();
// setup external interupt
attachInterrupt(RtcSquareWaveInterrupt, InteruptServiceRoutine, FALLING);
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
Serial.println("RTC lost confidence in the DateTime!");
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
// we only want to show time every 10 seconds
// but we want to show responce to the interupt firing
for (int timeCount = 0; timeCount < 20; timeCount++)
{
if (Alarmed())
{
Serial.print(">>Interupt Count: ");
Serial.print(interuptCount);
Serial.println("<<");
}
delay(500);
}
}
bool Alarmed()
{
bool wasAlarmed = false;
if (interuptFlag) // check our flag that gets sets in the interupt
{
wasAlarmed = true;
interuptFlag = false; // reset the flag
// this gives us which alarms triggered and
// then allows for others to trigger again
DS3234AlarmFlag flag = Rtc.LatchAlarmsTriggeredFlags();
if (flag & DS3234AlarmFlag_Alarm1)
{
Serial.println("alarm one triggered");
}
if (flag & DS3234AlarmFlag_Alarm2)
{
Serial.println("alarm two triggered");
}
}
return wasAlarmed;
}
#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);
}

View File

@@ -0,0 +1,139 @@
// Reference for connecting SPI see https://www.arduino.cc/en/Reference/SPI
// CONNECTIONS:
// DS3234 MISO --> MISO
// DS3234 MOSI --> MOSI
// DS3234 CLK --> CLK (SCK)
// DS3234 CS (SS) --> 5 (pin used to select the DS3234 on the SPI)
// DS3234 VCC --> 3.3v or 5v
// DS3234 GND --> GND
const uint8_t DS3234_CS_PIN = 5;
#include <SPI.h>
#include <RtcDS3234.h>
RtcDS3234<SPIClass> Rtc(SPI, DS3234_CS_PIN);
const char data[] = "what time is it";
void setup ()
{
Serial.begin(115200);
while (!Serial);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
SPI.begin();
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
Serial.println("RTC lost confidence in the DateTime!");
Rtc.SetDateTime(compiled);
}
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);
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.SetSquareWavePin(DS3234SquareWavePin_ModeNone);
/* comment out on a second run to see that the info is stored long term */
// Store something in memory on the RTC
Rtc.SetMemory(0, 13); // address of a data item
uint8_t written = Rtc.SetMemory(13, (const uint8_t*)data, sizeof(data) - 1); // remove the null terminator strings add
Rtc.SetMemory(1, written); // size of data time
/* end of comment out section */
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
delay(5000);
// read data
// get the offset we stored our data from address zero
uint8_t address = Rtc.GetMemory(0);
if (address != 13)
{
Serial.println("address didn't match");
}
else
{
// get the size of the data from address 1
uint8_t count = Rtc.GetMemory(1);
uint8_t buff[20];
// get our data from the address with the given size
uint8_t gotten = Rtc.GetMemory(address, buff, count);
if (gotten != count ||
count != sizeof(data) - 1) // remove the extra null terminator strings add
{
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(") = \"");
for (uint8_t ch = 0; ch < gotten; ch++)
{
Serial.print((char)buff[ch]);
}
Serial.println("\"");
}
delay(5000);
}
#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);
}

View File

@@ -0,0 +1,115 @@
// Reference for connecting SPI see https://www.arduino.cc/en/Reference/SPI
// CONNECTIONS:
// DS3234 MISO --> MISO
// DS3234 MOSI --> MOSI
// DS3234 CLK --> CLK (SCK)
// DS3234 CS (SS) --> 5 (pin used to select the DS3234 on the SPI)
// DS3234 VCC --> 3.3v or 5v
// DS3234 GND --> GND
const uint8_t DS3234_CS_PIN = 5;
#include <SPI.h>
#include <RtcDS3234.h>
RtcDS3234<SPIClass> Rtc(SPI, DS3234_CS_PIN);
void setup ()
{
Serial.begin(115200);
while (!Serial);
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);
SPI.begin();
Rtc.Begin();
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
printDateTime(compiled);
Serial.println();
if (!Rtc.IsDateTimeValid())
{
// Common Causes:
// 1) first time you ran and the device wasn't running yet
// 2) the battery on the device is low or even missing
Serial.println("RTC lost confidence in the DateTime!");
// following line sets the RTC to the date & time this sketch was compiled
// it will also reset the valid flag internally unless the Rtc device is
// having an issue
Rtc.SetDateTime(compiled);
}
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)");
}
// never assume the Rtc was last configured by you, so
// just clear them to your needed state
Rtc.Enable32kHzPin(false);
Rtc.SetSquareWavePin(DS3234SquareWavePin_ModeNone);
}
void loop ()
{
if (!Rtc.IsDateTimeValid())
{
// Common Causes:
// 1) the battery on the device is low or even missing and the power line was disconnected
Serial.println("RTC lost confidence in the DateTime!");
}
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
RtcTemperature temp = Rtc.GetTemperature();
temp.Print(Serial);
// you may also get the temperature as a float and print it
// Serial.print(temp.AsFloatDegC());
Serial.println("C");
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);
}

View File

@@ -0,0 +1,204 @@
// These tests do not rely on RTC hardware at all
//#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
void PrintPassFail(bool passed)
{
if (passed)
{
Serial.print("passed");
}
else
{
Serial.print("failed");
}
}
void ComparePrintlnPassFail(RtcTemperature& rtcTemp, float compare)
{
Serial.print(rtcTemp.AsFloatDegC());
Serial.print("C ");
PrintPassFail(rtcTemp.AsFloatDegC() == compare);
Serial.println();
}
void ConstructorTests()
{
// RTC constructors
Serial.println("Constructors:");
{
RtcTemperature temp075Below(0b11111111, 0b01000000); // -0.75
ComparePrintlnPassFail(temp075Below, -0.75f);
RtcTemperature temp050Below(0b11111111, 0b10000000); // -0.5
ComparePrintlnPassFail(temp050Below, -0.50f);
RtcTemperature temp025Below(0b11111111, 0b11000000); // -0.25
ComparePrintlnPassFail(temp025Below, -0.25f);
RtcTemperature tempZero(0b00000000, 0b00000000); // 0.0
ComparePrintlnPassFail(tempZero, -0.0f);
RtcTemperature temp025Above(0b00000000, 0b01000000); // 0.25
ComparePrintlnPassFail(temp025Above, 0.25f);
RtcTemperature temp050Above(0b00000000, 0b10000000); // 0.5
ComparePrintlnPassFail(temp050Above, 0.5f);
RtcTemperature temp075Above(0b00000000, 0b11000000); // 0.75
ComparePrintlnPassFail(temp075Above, 0.75f);
RtcTemperature temp25Above(0b00011001, 0b00000000); // 25.0
ComparePrintlnPassFail(temp25Above, 25.0f);
RtcTemperature temp25Below(0b11100111, 0b00000000); // -25.0
ComparePrintlnPassFail(temp25Below, -25.0f);
}
Serial.println();
// SameType
{
Serial.print("same type ");
RtcTemperature temp25Below(0b11100111, 0b00000000); // -25.0
RtcTemperature test = temp25Below;
ComparePrintlnPassFail(test, -25.0f);
}
// CentiDegrees
{
Serial.print("centi degrees ");
RtcTemperature temp025Below(-25); // -0.25
ComparePrintlnPassFail(temp025Below, -0.25f);
Serial.print("centi degrees ");
RtcTemperature temp025Above(25); // 0.25
ComparePrintlnPassFail(temp025Above, 0.25f);
Serial.print("centi degrees ");
RtcTemperature temp25Below(-2500); // -25.0
ComparePrintlnPassFail(temp25Below, -25.0f);
Serial.print("centi degrees ");
RtcTemperature temp25Above(2500); // 25.0
ComparePrintlnPassFail(temp25Above, 25.0f);
}
Serial.println();
}
void PrintlnExpected(RtcTemperature& temp, uint16_t digits)
{
Serial.print(" = ");
Serial.print(temp.AsFloatDegC(), digits);
Serial.println();
}
void PrintTests()
{
Serial.println("Prints:");
RtcTemperature temp25Above(2500);
temp25Above.Print(Serial);
PrintlnExpected(temp25Above, 2);
RtcTemperature temp25Below(-2500);
temp25Below.Print(Serial);
PrintlnExpected(temp25Below, 2);
RtcTemperature temp025Above(25);
temp025Above.Print(Serial);
PrintlnExpected(temp025Above, 2);
temp025Above.Print(Serial, 1);
PrintlnExpected(temp025Above, 1);
RtcTemperature temp025Below(-25);
temp025Below.Print(Serial);
PrintlnExpected(temp025Below, 2);
temp025Below.Print(Serial, 1);
PrintlnExpected(temp025Below, 1);
RtcTemperature temp050Above(50);
temp050Above.Print(Serial);
PrintlnExpected(temp050Above, 2);
temp050Above.Print(Serial, 0);
PrintlnExpected(temp050Above, 0);
RtcTemperature temp050Below(-50);
temp050Below.Print(Serial);
PrintlnExpected(temp050Below, 2);
temp050Below.Print(Serial, 0);
PrintlnExpected(temp050Below, 0);
temp050Below.Print(Serial, 2, ',');
Serial.println(" == -0,50");
Serial.println();
}
void MathmaticalOperatorTests()
{
Serial.println("Mathmaticals:");
RtcTemperature temp050Below(-50);
RtcTemperature temp050Above(50);
RtcTemperature temp050Diff(100);
RtcTemperature temp050Same(-50);
RtcTemperature tempResult;
Serial.print("equality ");
PrintPassFail(temp050Below == temp050Same);
Serial.println();
Serial.print("inequality ");
PrintPassFail(temp050Below != temp050Above);
Serial.println();
Serial.print("less than ");
PrintPassFail(temp050Below < temp050Above);
Serial.println();
Serial.print("greater than ");
PrintPassFail(temp050Above > temp050Below);
Serial.println();
Serial.print("less than ");
PrintPassFail(temp050Below <= temp050Above);
Serial.print(" or equal ");
PrintPassFail(temp050Below <= temp050Same);
Serial.println();
Serial.print("greater than ");
PrintPassFail(temp050Above >= temp050Below);
Serial.print(" or equal ");
PrintPassFail(temp050Below >= temp050Same);
Serial.println();
tempResult = temp050Above - temp050Below;
Serial.print("subtraction ");
PrintPassFail(tempResult == temp050Diff);
Serial.println();
tempResult = temp050Above + temp050Above;
Serial.print("addition ");
PrintPassFail(tempResult == temp050Diff);
Serial.println();
Serial.println();
}
void setup ()
{
Serial.begin(115200);
while (!Serial);
Serial.println();
ConstructorTests();
PrintTests();
MathmaticalOperatorTests();
}
void loop ()
{
delay(500);
}

View File

@@ -0,0 +1,148 @@
#######################################
# Syntax Coloring Map RTC
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ThreeWire KEYWORD1
RtcDS1302 KEYWORD1
RtcDS1307 KEYWORD1
DS3234AlarmOne KEYWORD1
DS3234AlarmTwo KEYWORD1
RtcDS3234 KEYWORD1
DS3231AlarmOne KEYWORD1
DS3231AlarmTwo KEYWORD1
RtcDS3231 KEYWORD1
EepromAt24c32 KEYWORD1
RtcTemperature KEYWORD1
RtcDateTime KEYWORD1
DayOfWeek KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
Begin KEYWORD2
LastError KEYWORD2
IsDateTimeValid KEYWORD2
GetIsRunning KEYWORD2
SetIsRunning KEYWORD2
GetIsWriteProtected KEYWORD2
SetIsWriteProtected KEYWORD2
SetDateTime KEYWORD2
GetDateTime KEYWORD2
GetTemperature KEYWORD2
Enable32kHzPin KEYWORD2
SetSquareWavePin KEYWORD2
SetSquareWavePinClockFrequency KEYWORD2
SetAlarmOne KEYWORD2
SetAlarmTwo KEYWORD2
GetAlarmOne KEYWORD2
GetAlarmTwo KEYWORD2
LatchAlarmsTriggeredFlags KEYWORD2
ForceTemperatureCompensationUpdate KEYWORD2
SetTemperatureCompensationRate KEYWORD2
GetTemperatureCompensationRate KEYWORD2
GetAgingOffset KEYWORD2
SetAgingOffset KEYWORD2
GetMemory KEYWORD2
SetMemory KEYWORD2
GetTrickleChargeSettings KEYWORD2
SetTrickleChargeSettings KEYWORD2
AsFloatDegC KEYWORD2
AsFloatDegF KEYWORD2
AsCentiDegC KEYWORD2
Print KEYWORD2
Year KEYWORD2
Month KEYWORD2
Day KEYWORD2
Hour KEYWORD2
Minute KEYWORD2
Second KEYWORD2
DayOfWeek KEYWORD2
TotalSeconds KEYWORD2
TotalSeconds64 KEYWORD2
TotalDays KEYWORD2
DayOf KEYWORD2
ControlFlags KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
DS3231SquareWaveClock_1Hz LITERAL1
DS3231SquareWaveClock_1kHz LITERAL1
DS3231SquareWaveClock_4kHz LITERAL1
DS3231SquareWaveClock_8kHz LITERAL1
DS3231SquareWavePin_ModeNone LITERAL1
DS3231SquareWavePin_ModeClock LITERAL1
DS3231SquareWavePin_ModeAlarmOne LITERAL1
DS3231SquareWavePin_ModeAlarmTwo LITERAL1
DS3231SquareWavePin_ModeAlarmBoth LITERAL1
DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch LITERAL1
DS3231AlarmOneControl_OncePerSecond LITERAL1
DS3231AlarmOneControl_SecondsMatch LITERAL1
DS3231AlarmOneControl_MinutesSecondsMatch LITERAL1
DS3231AlarmOneControl_HoursMinutesSecondsMatch LITERAL1
DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch LITERAL1
DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch LITERAL1
DS3231AlarmTwoControl_OncePerMinute LITERAL1
DS3231AlarmTwoControl_MinutesMatch LITERAL1
DS3231AlarmTwoControl_HoursMinutesMatch LITERAL1
DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch LITERAL1
DS3231AlarmFlag_Alarm1 LITERAL1
DS3231AlarmFlag_Alarm2 LITERAL1
DS3231AlarmFlag_AlarmBoth LITERAL1
DS1302RamSize LITERAL1
DS1302Tcr_Disabled LITERAL1
DS1302TcrResistor_2KOhm LITERAL1
DS1302TcrResistor_4KOhm LITERAL1
DS1302TcrResistor_8KOhm LITERAL1
DS1302TcrDiodes_One LITERAL1
DS1302TcrDiodes_Two LITERAL1
DS1302TcrStatus_Enabled LITERAL1
DS1302TcrStatus_Disabled LITERAL1
DS1307SquareWaveOut_1Hz LITERAL1
DS1307SquareWaveOut_4kHz LITERAL1
DS1307SquareWaveOut_8kHz LITERAL1
DS1307SquareWaveOut_32kHz LITERAL1
DS1307SquareWaveOut_High LITERAL1
DS1307SquareWaveOut_Low LITERAL1
DS3234SquareWaveClock_1Hz LITERAL1
DS3234SquareWaveClock_1kHz LITERAL1
DS3234SquareWaveClock_4kHz LITERAL1
DS3234SquareWaveClock_8kHz LITERAL1
DS3234SquareWavePin_ModeNone LITERAL1
DS3234SquareWavePin_ModeBatteryBackup LITERAL1
DS3234SquareWavePin_ModeClock LITERAL1
DS3234SquareWavePin_ModeAlarmOne LITERAL1
DS3234SquareWavePin_ModeAlarmTwo LITERAL1
DS3234SquareWavePin_ModeAlarmBoth LITERAL1
DS3234AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch LITERAL1
DS3234AlarmOneControl_OncePerSecond LITERAL1
DS3234AlarmOneControl_SecondsMatch LITERAL1
DS3234AlarmOneControl_MinutesSecondsMatch LITERAL1
DS3234AlarmOneControl_HoursMinutesSecondsMatch LITERAL1
DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch LITERAL1
DS3234AlarmTwoControl_HoursMinutesDayOfMonthMatch LITERAL1
DS3234AlarmTwoControl_OncePerMinute LITERAL1
DS3234AlarmTwoControl_MinutesMatch LITERAL1
DS3234AlarmTwoControl_HoursMinutesMatch LITERAL1
DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch LITERAL1
DS3234AlarmFlag_Alarm1 LITERAL1
DS3234AlarmFlag_Alarm2 LITERAL1
DS3234AlarmFlag_AlarmBoth LITERAL1
DS3234TempCompensationRate_64Seconds LITERAL1
DS3234TempCompensationRate_128Seconds LITERAL1
DS3234TempCompensationRate_256Seconds LITERAL1
DS3234TempCompensationRate_512Seconds LITERAL1
DayOfWeek_Sunday LITERAL1
DayOfWeek_Monday LITERAL1
DayOfWeek_Tuesday LITERAL1
DayOfWeek_Wednesday LITERAL1
DayOfWeek_Thursday LITERAL1
DayOfWeek_Friday LITERAL1
DayOfWeek_Saturday LITERAL1

View File

@@ -0,0 +1,13 @@
{
"name": "RTC",
"keywords": "RTC, DS1302, DS1307, DS3231, DS3234, AT24C32, clock",
"description": "A library that makes interfacing DS1302, DS1307, DS3231, and DS3234 Real Time Clock modules easy.",
"repository": {
"type": "git",
"url": "https://github.com/Makuna/Rtc.git"
},
"version": "2.3.5",
"frameworks": "arduino",
"platforms": "*"
}

View File

@@ -0,0 +1,9 @@
name=Rtc by Makuna
version=2.3.5
author=Michael C. Miller (makuna@live.com)
maintainer=Michael C. Miller (makuna@live.com)
sentence=A library that makes interfacing DS1302, DS1307, DS3231, and DS3234 Real Time Clock modules easy.
paragraph=Includes deep support of module features, including temperature, alarms and memory storage if present. Tested on esp8266.
category=Device Control
url=https://github.com/Makuna/Rtc/wiki
architectures=*

View File

@@ -0,0 +1,112 @@
#pragma once
//I2C Slave Address
const uint8_t AT24C32_ADDRESS = 0x50; // 0b0 1010 A2 A1 A0
template<class T_WIRE_METHOD> class EepromAt24c32
{
public:
EepromAt24c32(T_WIRE_METHOD& wire, uint8_t addressBits = 0b111) :
_address(AT24C32_ADDRESS | (addressBits & 0b00000111)),
_wire(wire),
_lastError(0)
{
}
void Begin()
{
_wire.begin();
}
uint8_t LastError()
{
return _lastError;
}
void SetMemory(uint16_t memoryAddress, uint8_t value)
{
SetMemory(memoryAddress, &value, 1);
}
uint8_t GetMemory(uint16_t memoryAddress)
{
uint8_t value;
GetMemory(memoryAddress, &value, 1);
return value;
}
// note: this method will write within a single page of eeprom.
// Pages are 32 bytes (5 bits), so writing past a page boundary will
// just wrap within the page of the starting memory address.
//
// xxxppppp pppaaaaa => p = page #, a = address within the page
//
// NOTE: hardware WIRE libraries often have a limit of a 32 byte send buffer. The
// effect of this is that only 30 bytes can be sent, 2 bytes for the address to write to,
// and then 30 bytes of the actual data.
uint8_t SetMemory(uint16_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
{
uint8_t countWritten = 0;
beginTransmission(memoryAddress);
while (countBytes > 0)
{
_wire.write(*pValue++);
delay(10); // per spec, memory writes
countBytes--;
countWritten++;
}
_lastError = _wire.endTransmission();
return countWritten;
}
// reading data does not wrap within pages, but due to only using
// 12 (32K) or 13 (64K) bits are used, they will wrap within the memory limits
// of the installed EEPROM
//
// NOTE: hardware WIRE libraries may have a limit of a 32 byte recieve buffer. The
// effect of this is that only 32 bytes can be read at one time.
uint8_t GetMemory(uint16_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
{
// set address to read from
beginTransmission(memoryAddress);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return 0;
}
// read the data
uint8_t countRead = 0;
countRead = _wire.requestFrom(_address, countBytes);
countBytes = countRead;
while (countBytes-- > 0)
{
*pValue++ = _wire.read();
}
return countRead;
}
private:
const uint8_t _address;
T_WIRE_METHOD& _wire;
uint8_t _lastError;
void beginTransmission(uint16_t memoryAddress)
{
_wire.beginTransmission(_address);
_wire.write(memoryAddress >> 8);
_wire.write(memoryAddress & 0xFf);
}
};

View File

@@ -0,0 +1,272 @@
#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;
const uint8_t DS1302_REG_RAMSTART = 0xc0;
const uint8_t DS1302_REG_RAMEND = 0xfd;
// ram read and write addresses are interleaved
const uint8_t DS1302RamSize = 31;
// 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();
}
void Begin(int sda, int scl)
{
_wire.begin(sda, scl);
}
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();
}
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 disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
if ((setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_Disabled ||
(setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_None) {
// invalid diode setting, set to disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
if ((setting & DS1302TcrStatus_MASK) != DS1302TcrStatus_Enabled) {
// invalid status setting, set to disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
apply:
setReg(DS1302_REG_TCR, setting);
}
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 Week
uint8_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 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(); // throwing away day of week as we calculate it
uint16_t year = BcdToUint8(_wire.read()) + 2000;
_wire.read(); // throwing away write protect flag
_wire.endTransmission();
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
void SetMemory(uint8_t memoryAddress, uint8_t value)
{
// memory addresses interleaved read and write addresses
// so we need to calculate the offset
uint8_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 offset
uint8_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__

View File

@@ -0,0 +1,259 @@
#ifndef __RTCDS1307_H__
#define __RTCDS1307_H__
#include <Arduino.h>
#include "RtcDateTime.h"
#include "RtcUtility.h"
//I2C Slave Address
const uint8_t DS1307_ADDRESS = 0x68;
//DS1307 Register Addresses
const uint8_t DS1307_REG_TIMEDATE = 0x00;
const uint8_t DS1307_REG_STATUS = 0x00;
const uint8_t DS1307_REG_CONTROL = 0x07;
const uint8_t DS1307_REG_RAMSTART = 0x08;
const uint8_t DS1307_REG_RAMEND = 0x3f;
const uint8_t DS1307_REG_RAMSIZE = DS1307_REG_RAMEND - DS1307_REG_RAMSTART;
//DS1307 Register Data Size if not just 1
const uint8_t DS1307_REG_TIMEDATE_SIZE = 7;
// DS1307 Control Register Bits
const uint8_t DS1307_RS0 = 0;
const uint8_t DS1307_RS1 = 1;
const uint8_t DS1307_SQWE = 4;
const uint8_t DS1307_OUT = 7;
// DS1307 Status Register Bits
const uint8_t DS1307_CH = 7;
enum DS1307SquareWaveOut
{
DS1307SquareWaveOut_1Hz = 0b00010000,
DS1307SquareWaveOut_4kHz = 0b00010001,
DS1307SquareWaveOut_8kHz = 0b00010010,
DS1307SquareWaveOut_32kHz = 0b00010011,
DS1307SquareWaveOut_High = 0b10000000,
DS1307SquareWaveOut_Low = 0b00000000,
};
template<class T_WIRE_METHOD> class RtcDS1307
{
public:
RtcDS1307(T_WIRE_METHOD& wire) :
_wire(wire),
_lastError(0)
{
}
void Begin()
{
_wire.begin();
}
void Begin(int sda, int scl)
{
_wire.begin(sda, scl);
}
uint8_t LastError()
{
return _lastError;
}
bool IsDateTimeValid()
{
return GetIsRunning();
}
bool GetIsRunning()
{
uint8_t sreg = getReg(DS1307_REG_STATUS);
return (!(sreg & _BV(DS1307_CH)) && (_lastError == 0));
}
void SetIsRunning(bool isRunning)
{
uint8_t sreg = getReg(DS1307_REG_STATUS);
if (isRunning)
{
sreg &= ~_BV(DS1307_CH);
}
else
{
sreg |= _BV(DS1307_CH);
}
setReg(DS1307_REG_STATUS, sreg);
}
void SetDateTime(const RtcDateTime& dt)
{
// retain running state
uint8_t sreg = getReg(DS1307_REG_STATUS) & _BV(DS1307_CH);
// set the date time
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(DS1307_REG_TIMEDATE);
_wire.write(Uint8ToBcd(dt.Second()) | sreg);
_wire.write(Uint8ToBcd(dt.Minute()));
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
// RTC Hardware Day of Week is 1-7, 1 = Monday
// convert our Day of Week to Rtc Day of Week
uint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());
_wire.write(Uint8ToBcd(rtcDow));
_wire.write(Uint8ToBcd(dt.Day()));
_wire.write(Uint8ToBcd(dt.Month()));
_wire.write(Uint8ToBcd(dt.Year() - 2000));
_lastError = _wire.endTransmission();
}
RtcDateTime GetDateTime()
{
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(DS1307_REG_TIMEDATE);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
RtcDateTime(0);
}
uint8_t bytesRead = _wire.requestFrom(DS1307_ADDRESS, DS1307_REG_TIMEDATE_SIZE);
if (DS1307_REG_TIMEDATE_SIZE != bytesRead)
{
_lastError = 4;
RtcDateTime(0);
}
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
uint8_t minute = BcdToUint8(_wire.read());
uint8_t hour = BcdToBin24Hour(_wire.read());
_wire.read(); // throwing away day of week as we calculate it
uint8_t dayOfMonth = BcdToUint8(_wire.read());
uint8_t month = BcdToUint8(_wire.read());
uint16_t year = BcdToUint8(_wire.read()) + 2000;
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
void SetMemory(uint8_t memoryAddress, uint8_t value)
{
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
if (address <= DS1307_REG_RAMEND)
{
setReg(address, value);
}
}
uint8_t GetMemory(uint8_t memoryAddress)
{
uint8_t value = 0;
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
if (address <= DS1307_REG_RAMEND)
{
value = getReg(address);
}
return value;
}
uint8_t SetMemory(uint8_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
{
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
uint8_t countWritten = 0;
if (address <= DS1307_REG_RAMEND)
{
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(address);
while (countBytes > 0 && address <= DS1307_REG_RAMEND)
{
_wire.write(*pValue++);
address++;
countBytes--;
countWritten++;
}
_lastError = _wire.endTransmission();
}
return countWritten;
}
uint8_t GetMemory(uint8_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
{
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
uint8_t countRead = 0;
if (address <= DS1307_REG_RAMEND)
{
if (countBytes > DS1307_REG_RAMSIZE)
{
countBytes = DS1307_REG_RAMSIZE;
}
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(address);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return 0;
}
countRead = _wire.requestFrom(DS1307_ADDRESS, countBytes);
countBytes = countRead;
while (countBytes-- > 0)
{
*pValue++ = _wire.read();
}
}
return countRead;
}
void SetSquareWavePin(DS1307SquareWaveOut pinMode)
{
setReg(DS1307_REG_CONTROL, pinMode);
}
private:
T_WIRE_METHOD& _wire;
uint8_t _lastError;
uint8_t getReg(uint8_t regAddress)
{
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(regAddress);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return 0;
}
// control register
uint8_t bytesRead = _wire.requestFrom(DS1307_ADDRESS, (uint8_t)1);
if (1 != bytesRead)
{
_lastError = 4;
return 0;
}
uint8_t regValue = _wire.read();
return regValue;
}
void setReg(uint8_t regAddress, uint8_t regValue)
{
_wire.beginTransmission(DS1307_ADDRESS);
_wire.write(regAddress);
_wire.write(regValue);
_lastError = _wire.endTransmission();
}
};
#endif // __RTCDS1307_H__

View File

@@ -0,0 +1,631 @@
#ifndef __RTCDS3231_H__
#define __RTCDS3231_H__
#include <Arduino.h>
#include "RtcDateTime.h"
#include "RtcTemperature.h"
#include "RtcUtility.h"
//I2C Slave Address
const uint8_t DS3231_ADDRESS = 0x68;
//DS3231 Register Addresses
const uint8_t DS3231_REG_TIMEDATE = 0x00;
const uint8_t DS3231_REG_ALARMONE = 0x07;
const uint8_t DS3231_REG_ALARMTWO = 0x0B;
const uint8_t DS3231_REG_CONTROL = 0x0E;
const uint8_t DS3231_REG_STATUS = 0x0F;
const uint8_t DS3231_REG_AGING = 0x10;
const uint8_t DS3231_REG_TEMP = 0x11;
//DS3231 Register Data Size if not just 1
const uint8_t DS3231_REG_TIMEDATE_SIZE = 7;
const uint8_t DS3231_REG_ALARMONE_SIZE = 4;
const uint8_t DS3231_REG_ALARMTWO_SIZE = 3;
const uint8_t DS3231_REG_TEMP_SIZE = 2;
// DS3231 Control Register Bits
const uint8_t DS3231_A1IE = 0;
const uint8_t DS3231_A2IE = 1;
const uint8_t DS3231_INTCN = 2;
const uint8_t DS3231_RS1 = 3;
const uint8_t DS3231_RS2 = 4;
const uint8_t DS3231_CONV = 5;
const uint8_t DS3231_BBSQW = 6;
const uint8_t DS3231_EOSC = 7;
const uint8_t DS3231_AIEMASK = (_BV(DS3231_A1IE) | _BV(DS3231_A2IE));
const uint8_t DS3231_RSMASK = (_BV(DS3231_RS1) | _BV(DS3231_RS2));
// DS3231 Status Register Bits
const uint8_t DS3231_A1F = 0;
const uint8_t DS3231_A2F = 1;
const uint8_t DS3231_BSY = 2;
const uint8_t DS3231_EN32KHZ = 3;
const uint8_t DS3231_OSF = 7;
const uint8_t DS3231_AIFMASK = (_BV(DS3231_A1F) | _BV(DS3231_A2F));
// seconds accuracy
enum DS3231AlarmOneControl
{
// bit order: A1M4 DY/DT A1M3 A1M2 A1M1
DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch = 0x00,
DS3231AlarmOneControl_OncePerSecond = 0x17,
DS3231AlarmOneControl_SecondsMatch = 0x16,
DS3231AlarmOneControl_MinutesSecondsMatch = 0x14,
DS3231AlarmOneControl_HoursMinutesSecondsMatch = 0x10,
DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch = 0x08,
};
class DS3231AlarmOne
{
public:
DS3231AlarmOne( uint8_t dayOf,
uint8_t hour,
uint8_t minute,
uint8_t second,
DS3231AlarmOneControl controlFlags) :
_flags(controlFlags),
_dayOf(dayOf),
_hour(hour),
_minute(minute),
_second(second)
{
}
uint8_t DayOf() const
{
return _dayOf;
}
uint8_t Hour() const
{
return _hour;
}
uint8_t Minute() const
{
return _minute;
}
uint8_t Second() const
{
return _second;
}
DS3231AlarmOneControl ControlFlags() const
{
return _flags;
}
bool operator == (const DS3231AlarmOne& other) const
{
return (_dayOf == other._dayOf &&
_hour == other._hour &&
_minute == other._minute &&
_second == other._second &&
_flags == other._flags);
}
bool operator != (const DS3231AlarmOne& other) const
{
return !(*this == other);
}
protected:
DS3231AlarmOneControl _flags;
uint8_t _dayOf;
uint8_t _hour;
uint8_t _minute;
uint8_t _second;
};
// minutes accuracy
enum DS3231AlarmTwoControl
{
// bit order: A2M4 DY/DT A2M3 A2M2
DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch = 0x00,
DS3231AlarmTwoControl_OncePerMinute = 0x0b,
DS3231AlarmTwoControl_MinutesMatch = 0x0a,
DS3231AlarmTwoControl_HoursMinutesMatch = 0x08,
DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch = 0x04,
};
class DS3231AlarmTwo
{
public:
DS3231AlarmTwo( uint8_t dayOf,
uint8_t hour,
uint8_t minute,
DS3231AlarmTwoControl controlFlags) :
_flags(controlFlags),
_dayOf(dayOf),
_hour(hour),
_minute(minute)
{
}
uint8_t DayOf() const
{
return _dayOf;
}
uint8_t Hour() const
{
return _hour;
}
uint8_t Minute() const
{
return _minute;
}
DS3231AlarmTwoControl ControlFlags() const
{
return _flags;
}
bool operator == (const DS3231AlarmTwo& other) const
{
return (_dayOf == other._dayOf &&
_hour == other._hour &&
_minute == other._minute &&
_flags == other._flags);
}
bool operator != (const DS3231AlarmTwo& other) const
{
return !(*this == other);
}
protected:
DS3231AlarmTwoControl _flags;
uint8_t _dayOf;
uint8_t _hour;
uint8_t _minute;
};
enum DS3231SquareWaveClock
{
DS3231SquareWaveClock_1Hz = 0b00000000,
DS3231SquareWaveClock_1kHz = 0b00001000,
DS3231SquareWaveClock_4kHz = 0b00010000,
DS3231SquareWaveClock_8kHz = 0b00011000,
};
enum DS3231SquareWavePinMode
{
DS3231SquareWavePin_ModeNone,
DS3231SquareWavePin_ModeAlarmOne,
DS3231SquareWavePin_ModeAlarmTwo,
// note: the same as DS3231SquareWavePin_ModeAlarmOne | DS3231SquareWavePin_ModeAlarmTwo
DS3231SquareWavePin_ModeAlarmBoth,
DS3231SquareWavePin_ModeClock
};
enum DS3231AlarmFlag
{
DS3231AlarmFlag_Alarm1 = 0x01,
DS3231AlarmFlag_Alarm2 = 0x02,
DS3231AlarmFlag_AlarmBoth = 0x03,
};
template<class T_WIRE_METHOD> class RtcDS3231
{
public:
RtcDS3231(T_WIRE_METHOD& wire) :
_wire(wire),
_lastError(0)
{
}
void Begin()
{
_wire.begin();
}
void Begin(int sda, int scl)
{
_wire.begin(sda, scl);
}
uint8_t LastError()
{
return _lastError;
}
bool IsDateTimeValid()
{
uint8_t status = getReg(DS3231_REG_STATUS);
return (!(status & _BV(DS3231_OSF)) && (_lastError == 0));
}
bool GetIsRunning()
{
uint8_t creg = getReg(DS3231_REG_CONTROL);
return (!(creg & _BV(DS3231_EOSC)) && (_lastError == 0));
}
void SetIsRunning(bool isRunning)
{
uint8_t creg = getReg(DS3231_REG_CONTROL);
if (isRunning)
{
creg &= ~_BV(DS3231_EOSC);
}
else
{
creg |= _BV(DS3231_EOSC);
}
setReg(DS3231_REG_CONTROL, creg);
}
void SetDateTime(const RtcDateTime& dt)
{
// clear the invalid flag
uint8_t status = getReg(DS3231_REG_STATUS);
status &= ~_BV(DS3231_OSF); // clear the flag
setReg(DS3231_REG_STATUS, status);
// set the date time
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_TIMEDATE);
_wire.write(Uint8ToBcd(dt.Second()));
_wire.write(Uint8ToBcd(dt.Minute()));
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
uint8_t year = dt.Year() - 2000;
uint8_t centuryFlag = 0;
if (year >= 100)
{
year -= 100;
centuryFlag = _BV(7);
}
// RTC Hardware Day of Week is 1-7, 1 = Monday
// convert our Day of Week to Rtc Day of Week
uint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());
_wire.write(Uint8ToBcd(rtcDow));
_wire.write(Uint8ToBcd(dt.Day()));
_wire.write(Uint8ToBcd(dt.Month()) | centuryFlag);
_wire.write(Uint8ToBcd(year));
_lastError = _wire.endTransmission();
}
RtcDateTime GetDateTime()
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_TIMEDATE);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return RtcDateTime(0);
}
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TIMEDATE_SIZE);
if (DS3231_REG_TIMEDATE_SIZE != bytesRead)
{
_lastError = 4;
return RtcDateTime(0);
}
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
uint8_t minute = BcdToUint8(_wire.read());
uint8_t hour = BcdToBin24Hour(_wire.read());
_wire.read(); // throwing away day of week as we calculate it
uint8_t dayOfMonth = BcdToUint8(_wire.read());
uint8_t monthRaw = _wire.read();
uint16_t year = BcdToUint8(_wire.read()) + 2000;
if (monthRaw & _BV(7)) // century wrap flag
{
year += 100;
}
uint8_t month = BcdToUint8(monthRaw & 0x7f);
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
RtcTemperature GetTemperature()
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_TEMP);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return RtcTemperature(0);
}
// Temperature is represented as a 10-bit code with a resolution
// of 1/4th °C and is accessable as a signed 16-bit integer at
// locations 11h and 12h.
//
// | r11h | DP | r12h |
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
// s i i i i i i i . f f 0 0 0 0 0 0
//
// As it takes (8) right-shifts to register the decimal point (DP) to
// the right of the 0th bit, the overall word scaling equals 256.
//
// For example, at +/- 25.25°C, concatenated registers <r11h:r12h> =
// 256 * (+/- 25+(1/4)) = +/- 6464, or 1940h / E6C0h.
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TEMP_SIZE);
if (DS3231_REG_TEMP_SIZE != bytesRead)
{
_lastError = 4;
return RtcTemperature(0);
}
int8_t r11h = _wire.read(); // MS byte, signed temperature
return RtcTemperature( r11h, _wire.read() ); // LS byte is r12h
}
void Enable32kHzPin(bool enable)
{
uint8_t sreg = getReg(DS3231_REG_STATUS);
if (enable == true)
{
sreg |= _BV(DS3231_EN32KHZ);
}
else
{
sreg &= ~_BV(DS3231_EN32KHZ);
}
setReg(DS3231_REG_STATUS, sreg);
}
void SetSquareWavePin(DS3231SquareWavePinMode pinMode, bool enableWhileInBatteryBackup = true)
{
uint8_t creg = getReg(DS3231_REG_CONTROL);
// clear all relevant bits to a known "off" state
creg &= ~(DS3231_AIEMASK | _BV(DS3231_BBSQW));
creg |= _BV(DS3231_INTCN); // set INTCN to disables clock SQW
if (pinMode != DS3231SquareWavePin_ModeNone)
{
if (pinMode == DS3231SquareWavePin_ModeClock)
{
creg &= ~_BV(DS3231_INTCN); // clear INTCN to enable clock SQW
}
else
{
if (pinMode & DS3231SquareWavePin_ModeAlarmOne)
{
creg |= _BV(DS3231_A1IE);
}
if (pinMode & DS3231SquareWavePin_ModeAlarmTwo)
{
creg |= _BV(DS3231_A2IE);
}
}
if (enableWhileInBatteryBackup)
{
creg |= _BV(DS3231_BBSQW); // set enable int/sqw while in battery backup flag
}
}
setReg(DS3231_REG_CONTROL, creg);
}
void SetSquareWavePinClockFrequency(DS3231SquareWaveClock freq)
{
uint8_t creg = getReg(DS3231_REG_CONTROL);
creg &= ~DS3231_RSMASK; // Set to 0
creg |= (freq & DS3231_RSMASK); // Set freq bits
setReg(DS3231_REG_CONTROL, creg);
}
void SetAlarmOne(const DS3231AlarmOne& alarm)
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_ALARMONE);
_wire.write(Uint8ToBcd(alarm.Second()) | ((alarm.ControlFlags() & 0x01) << 7));
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x02) << 6));
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x04) << 5)); // 24 hour mode only
uint8_t rtcDow = alarm.DayOf();
if (alarm.ControlFlags() == DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
{
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
}
_wire.write(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x18) << 3));
_lastError = _wire.endTransmission();
}
void SetAlarmTwo(const DS3231AlarmTwo& alarm)
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_ALARMTWO);
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x01) << 7));
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x02) << 6)); // 24 hour mode only
// convert our Day of Week to Rtc Day of Week if needed
uint8_t rtcDow = alarm.DayOf();
if (alarm.ControlFlags() == DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch)
{
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
}
_wire.write(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x0c) << 4));
_lastError = _wire.endTransmission();
}
DS3231AlarmOne GetAlarmOne()
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_ALARMONE);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return DS3231AlarmOne(0, 0, 0, 0, DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch);
}
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMONE_SIZE);
if (DS3231_REG_ALARMONE_SIZE != bytesRead)
{
_lastError = 4;
return DS3231AlarmOne(0, 0, 0, 0, DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch);
}
uint8_t raw = _wire.read();
uint8_t flags = (raw & 0x80) >> 7;
uint8_t second = BcdToUint8(raw & 0x7F);
raw = _wire.read();
flags |= (raw & 0x80) >> 6;
uint8_t minute = BcdToUint8(raw & 0x7F);
raw = _wire.read();
flags |= (raw & 0x80) >> 5;
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
raw = _wire.read();
flags |= (raw & 0xc0) >> 3;
uint8_t dayOf = BcdToUint8(raw & 0x3f);
if (flags == DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
{
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
}
return DS3231AlarmOne(dayOf, hour, minute, second, (DS3231AlarmOneControl)flags);
}
DS3231AlarmTwo GetAlarmTwo()
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(DS3231_REG_ALARMTWO);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return DS3231AlarmTwo(0, 0, 0, DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch);
}
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMTWO_SIZE);
if (DS3231_REG_ALARMTWO_SIZE != bytesRead)
{
_lastError = 4;
return DS3231AlarmTwo(0, 0, 0, DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch);
}
uint8_t raw = _wire.read();
uint8_t flags = (raw & 0x80) >> 7;
uint8_t minute = BcdToUint8(raw & 0x7F);
raw = _wire.read();
flags |= (raw & 0x80) >> 6;
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
raw = _wire.read();
flags |= (raw & 0xc0) >> 4;
uint8_t dayOf = BcdToUint8(raw & 0x3f);
if (flags == DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch)
{
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
}
return DS3231AlarmTwo(dayOf, hour, minute, (DS3231AlarmTwoControl)flags);
}
// Latch must be called after an alarm otherwise it will not
// trigger again
DS3231AlarmFlag LatchAlarmsTriggeredFlags()
{
uint8_t sreg = getReg(DS3231_REG_STATUS);
uint8_t alarmFlags = (sreg & DS3231_AIFMASK);
sreg &= ~DS3231_AIFMASK; // clear the flags
setReg(DS3231_REG_STATUS, sreg);
return (DS3231AlarmFlag)alarmFlags;
}
void ForceTemperatureCompensationUpdate(bool block)
{
uint8_t creg = getReg(DS3231_REG_CONTROL);
creg |= _BV(DS3231_CONV); // Write CONV bit
setReg(DS3231_REG_CONTROL, creg);
while (block && (creg & _BV(DS3231_CONV)) != 0)
{
// Block until CONV is 0
creg = getReg(DS3231_REG_CONTROL);
}
}
int8_t GetAgingOffset()
{
return getReg(DS3231_REG_AGING);
}
void SetAgingOffset(int8_t value)
{
setReg(DS3231_REG_AGING, value);
}
private:
T_WIRE_METHOD& _wire;
uint8_t _lastError;
uint8_t getReg(uint8_t regAddress)
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(regAddress);
_lastError = _wire.endTransmission();
if (_lastError != 0)
{
return 0;
}
// control register
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, (uint8_t)1);
if (1 != bytesRead)
{
_lastError = 4;
return 0;
}
uint8_t regValue = _wire.read();
return regValue;
}
void setReg(uint8_t regAddress, uint8_t regValue)
{
_wire.beginTransmission(DS3231_ADDRESS);
_wire.write(regAddress);
_wire.write(regValue);
_lastError = _wire.endTransmission();
}
};
#endif // __RTCDS3231_H__

View File

@@ -0,0 +1,699 @@
#ifndef __RTCDS3234_H__
#define __RTCDS3234_H__
#include <Arduino.h>
#include <SPI.h>
#include "RtcDateTime.h"
#include "RtcTemperature.h"
#include "RtcUtility.h"
//DS3234 Register Addresses
const uint8_t DS3234_REG_WRITE_FLAG = 0x80;
const uint8_t DS3234_REG_TIMEDATE = 0x00;
const uint8_t DS3234_REG_ALARMONE = 0x07;
const uint8_t DS3234_REG_ALARMTWO = 0x0B;
const uint8_t DS3234_REG_CONTROL = 0x0E;
const uint8_t DS3234_REG_STATUS = 0x0F;
const uint8_t DS3234_REG_AGING = 0x10;
const uint8_t DS3234_REG_TEMP = 0x11;
const uint8_t DS3234_REG_RAM_ADDRESS = 0x18;
const uint8_t DS3234_REG_RAM_DATA = 0x19;
const uint8_t DS3234_RAMSTART = 0x00;
const uint8_t DS3234_RAMEND = 0xFF;
const uint8_t DS3234_RAMSIZE = DS3234_RAMEND - DS3234_RAMSTART;
// DS3234 Control Register Bits
const uint8_t DS3234_A1IE = 0;
const uint8_t DS3234_A2IE = 1;
const uint8_t DS3234_INTCN = 2;
const uint8_t DS3234_RS1 = 3;
const uint8_t DS3234_RS2 = 4;
const uint8_t DS3234_CONV = 5;
const uint8_t DS3234_BBSQW = 6;
const uint8_t DS3234_EOSC = 7;
const uint8_t DS3234_AIEMASK = (_BV(DS3234_A1IE) | _BV(DS3234_A2IE));
const uint8_t DS3234_RSMASK = (_BV(DS3234_RS1) | _BV(DS3234_RS2));
// DS3234 Status Register Bits
const uint8_t DS3234_A1F = 0;
const uint8_t DS3234_A2F = 1;
const uint8_t DS3234_BSY = 2;
const uint8_t DS3234_EN32KHZ = 3;
const uint8_t DS3234_CRATE0 = 4;
const uint8_t DS3234_CRATE1 = 5;
const uint8_t DS3234_BB32KHZ = 6;
const uint8_t DS3234_OSF = 7;
const uint8_t DS3234_AIFMASK = (_BV(DS3234_A1F) | _BV(DS3234_A2F));
const uint8_t DS3234_CRATEMASK = (_BV(DS3234_CRATE0) | _BV(DS3234_CRATE1));
// seconds accuracy
enum DS3234AlarmOneControl
{
// bit order: A1M4 DY/DT A1M3 A1M2 A1M1
DS3234AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch = 0x00,
DS3234AlarmOneControl_OncePerSecond = 0x17,
DS3234AlarmOneControl_SecondsMatch = 0x16,
DS3234AlarmOneControl_MinutesSecondsMatch = 0x14,
DS3234AlarmOneControl_HoursMinutesSecondsMatch = 0x10,
DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch = 0x08,
};
class DS3234AlarmOne
{
public:
DS3234AlarmOne( uint8_t dayOf,
uint8_t hour,
uint8_t minute,
uint8_t second,
DS3234AlarmOneControl controlFlags) :
_flags(controlFlags),
_dayOf(dayOf),
_hour(hour),
_minute(minute),
_second(second)
{
}
uint8_t DayOf() const
{
return _dayOf;
}
uint8_t Hour() const
{
return _hour;
}
uint8_t Minute() const
{
return _minute;
}
uint8_t Second() const
{
return _second;
}
DS3234AlarmOneControl ControlFlags() const
{
return _flags;
}
bool operator == (const DS3234AlarmOne& other) const
{
return (_dayOf == other._dayOf &&
_hour == other._hour &&
_minute == other._minute &&
_second == other._second &&
_flags == other._flags);
}
bool operator != (const DS3234AlarmOne& other) const
{
return !(*this == other);
}
protected:
DS3234AlarmOneControl _flags;
uint8_t _dayOf;
uint8_t _hour;
uint8_t _minute;
uint8_t _second;
};
// minutes accuracy
enum DS3234AlarmTwoControl
{
// bit order: A2M4 DY/DT A2M3 A2M2
DS3234AlarmTwoControl_HoursMinutesDayOfMonthMatch = 0x00,
DS3234AlarmTwoControl_OncePerMinute = 0x0b,
DS3234AlarmTwoControl_MinutesMatch = 0x0a,
DS3234AlarmTwoControl_HoursMinutesMatch = 0x08,
DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch = 0x04,
};
class DS3234AlarmTwo
{
public:
DS3234AlarmTwo( uint8_t dayOf,
uint8_t hour,
uint8_t minute,
DS3234AlarmTwoControl controlFlags) :
_flags(controlFlags),
_dayOf(dayOf),
_hour(hour),
_minute(minute)
{
}
uint8_t DayOf() const
{
return _dayOf;
}
uint8_t Hour() const
{
return _hour;
}
uint8_t Minute() const
{
return _minute;
}
DS3234AlarmTwoControl ControlFlags() const
{
return _flags;
}
bool operator == (const DS3234AlarmTwo& other) const
{
return (_dayOf == other._dayOf &&
_hour == other._hour &&
_minute == other._minute &&
_flags == other._flags);
}
bool operator != (const DS3234AlarmTwo& other) const
{
return !(*this == other);
}
protected:
DS3234AlarmTwoControl _flags;
uint8_t _dayOf;
uint8_t _hour;
uint8_t _minute;
};
enum DS3234SquareWaveClock
{
DS3234SquareWaveClock_1Hz = 0b00000000,
DS3234SquareWaveClock_1kHz = 0b00001000,
DS3234SquareWaveClock_4kHz = 0b00010000,
DS3234SquareWaveClock_8kHz = 0b00011000,
};
enum DS3234SquareWavePinMode
{
DS3234SquareWavePin_ModeNone,
DS3234SquareWavePin_ModeBatteryBackup,
DS3234SquareWavePin_ModeClock,
DS3234SquareWavePin_ModeAlarmOne,
DS3234SquareWavePin_ModeAlarmTwo,
DS3234SquareWavePin_ModeAlarmBoth
};
enum DS3234TempCompensationRate
{
DS3234TempCompensationRate_64Seconds,
DS3234TempCompensationRate_128Seconds,
DS3234TempCompensationRate_256Seconds,
DS3234TempCompensationRate_512Seconds,
};
enum DS3234AlarmFlag
{
DS3234AlarmFlag_Alarm1 = 0x01,
DS3234AlarmFlag_Alarm2 = 0x02,
DS3234AlarmFlag_AlarmBoth = 0x03,
};
const SPISettings c_Ds3234SpiSettings(1000000, MSBFIRST, SPI_MODE1); // CPHA must be used, so mode 1 or mode 3 are valid
template<class T_SPI_METHOD> class RtcDS3234
{
public:
RtcDS3234(T_SPI_METHOD& spi, uint8_t csPin) :
_spi(spi),
_csPin(csPin)
{
}
void Begin()
{
UnselectChip();
pinMode(_csPin, OUTPUT);
}
bool IsDateTimeValid()
{
uint8_t status = getReg(DS3234_REG_STATUS);
return !(status & _BV(DS3234_OSF));
}
bool GetIsRunning()
{
uint8_t creg = getReg(DS3234_REG_CONTROL);
return !(creg & _BV(DS3234_EOSC));
}
void SetIsRunning(bool isRunning)
{
uint8_t creg = getReg(DS3234_REG_CONTROL);
if (isRunning)
{
creg &= ~_BV(DS3234_EOSC);
}
else
{
creg |= _BV(DS3234_EOSC);
}
setReg(DS3234_REG_CONTROL, creg);
}
void SetDateTime(const RtcDateTime& dt)
{
// clear the invalid flag
uint8_t status = getReg(DS3234_REG_STATUS);
status &= ~_BV(DS3234_OSF); // clear the flag
setReg(DS3234_REG_STATUS, status);
// set the date time
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_TIMEDATE | DS3234_REG_WRITE_FLAG);
_spi.transfer(Uint8ToBcd(dt.Second()));
_spi.transfer(Uint8ToBcd(dt.Minute()));
_spi.transfer(Uint8ToBcd(dt.Hour())); // 24 hour mode only
uint8_t year = dt.Year() - 2000;
uint8_t centuryFlag = 0;
if (year >= 100)
{
year -= 100;
centuryFlag = _BV(7);
}
// RTC Hardware Day of Week is 1-7, 1 = Monday
// convert our Day of Week to Rtc Day of Week
uint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());
_spi.transfer(Uint8ToBcd(rtcDow));
_spi.transfer(Uint8ToBcd(dt.Day()));
_spi.transfer(Uint8ToBcd(dt.Month()) | centuryFlag);
_spi.transfer(Uint8ToBcd(year));
UnselectChip();
_spi.endTransaction();
}
RtcDateTime GetDateTime()
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_TIMEDATE);
uint8_t second = BcdToUint8(_spi.transfer(0));
uint8_t minute = BcdToUint8(_spi.transfer(0));
uint8_t hour = BcdToBin24Hour(_spi.transfer(0));
_spi.transfer(0); // throwing away day of week as we calculate it
uint8_t dayOfMonth = BcdToUint8(_spi.transfer(0));
uint8_t monthRaw = _spi.transfer(0);
uint16_t year = BcdToUint8(_spi.transfer(0)) + 2000;
UnselectChip();
_spi.endTransaction();
if (monthRaw & _BV(7)) // century wrap flag
{
year += 100;
}
uint8_t month = BcdToUint8(monthRaw & 0x7f);
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
RtcTemperature GetTemperature()
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_TEMP);
// Temperature is represented as a 10-bit code with a resolution
// of 1/4th °C and is accessable as a signed 16-bit integer at
// locations 11h and 12h.
//
// | r11h | DP | r12h |
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
// s i i i i i i i . f f 0 0 0 0 0 0
//
// As it takes (8) right-shifts to register the decimal point (DP) to
// the right of the 0th bit, the overall word scaling equals 256.
//
// For example, at +/- 25.25°C, concatenated registers <r11h:r12h> =
// 256 * (+/- 25+(1/4)) = +/- 6464, or 1940h / E6C0h.
int8_t ms = _spi.transfer(0); // MS byte, signed temperature
uint8_t ls = _spi.transfer(0); // LS byte is r12h
UnselectChip();
_spi.endTransaction();
return RtcTemperature(ms, ls); // LS byte is r12h
}
void Enable32kHzPin(bool enable)
{
uint8_t sreg = getReg(DS3234_REG_STATUS);
if (enable == true)
{
sreg |= _BV(DS3234_EN32KHZ);
}
else
{
sreg &= ~_BV(DS3234_EN32KHZ);
}
setReg(DS3234_REG_STATUS, sreg);
}
void SetSquareWavePin(DS3234SquareWavePinMode pinMode)
{
uint8_t creg = getReg(DS3234_REG_CONTROL);
// clear all relevant bits to a known "off" state
creg &= ~(DS3234_AIEMASK | _BV(DS3234_BBSQW));
creg |= _BV(DS3234_INTCN); // set INTCN to disables SQW
switch (pinMode)
{
case DS3234SquareWavePin_ModeNone:
break;
case DS3234SquareWavePin_ModeBatteryBackup:
creg |= _BV(DS3234_BBSQW); // set battery backup flag
creg &= ~_BV(DS3234_INTCN); // clear INTCN to enable SQW
break;
case DS3234SquareWavePin_ModeClock:
creg &= ~_BV(DS3234_INTCN); // clear INTCN to enable SQW
break;
case DS3234SquareWavePin_ModeAlarmOne:
creg |= _BV(DS3234_A1IE);
break;
case DS3234SquareWavePin_ModeAlarmTwo:
creg |= _BV(DS3234_A2IE);
break;
case DS3234SquareWavePin_ModeAlarmBoth:
creg |= _BV(DS3234_A1IE) | _BV(DS3234_A2IE);
break;
}
setReg(DS3234_REG_CONTROL, creg);
}
void SetSquareWavePinClockFrequency(DS3234SquareWaveClock freq)
{
uint8_t creg = getReg(DS3234_REG_CONTROL);
creg &= ~DS3234_RSMASK; // Set to 0
creg |= (freq & DS3234_RSMASK); // Set freq bits
setReg(DS3234_REG_CONTROL, creg);
}
void SetAlarmOne(const DS3234AlarmOne& alarm)
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_ALARMONE | DS3234_REG_WRITE_FLAG);
_spi.transfer(Uint8ToBcd(alarm.Second()) | ((alarm.ControlFlags() & 0x01) << 7));
_spi.transfer(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x02) << 6));
_spi.transfer(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x04) << 5)); // 24 hour mode only
uint8_t rtcDow = alarm.DayOf();
if (alarm.ControlFlags() == DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
{
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
}
_spi.transfer(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x18) << 3));
UnselectChip();
_spi.endTransaction();
}
void SetAlarmTwo(const DS3234AlarmTwo& alarm)
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_ALARMTWO | DS3234_REG_WRITE_FLAG);
_spi.transfer(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x01) << 7));
_spi.transfer(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x02) << 6)); // 24 hour mode only
// convert our Day of Week to Rtc Day of Week if needed
uint8_t rtcDow = alarm.DayOf();
if (alarm.ControlFlags() == DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch)
{
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
}
_spi.transfer(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x0c) << 4));
UnselectChip();
_spi.endTransaction();
}
DS3234AlarmOne GetAlarmOne()
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_ALARMONE);
uint8_t raw = _spi.transfer(0);
uint8_t flags = (raw & 0x80) >> 7;
uint8_t second = BcdToUint8(raw & 0x7F);
raw = _spi.transfer(0);
flags |= (raw & 0x80) >> 6;
uint8_t minute = BcdToUint8(raw & 0x7F);
raw = _spi.transfer(0);
flags |= (raw & 0x80) >> 5;
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
raw = _spi.transfer(0);
flags |= (raw & 0xc0) >> 3;
uint8_t dayOf = BcdToUint8(raw & 0x3f);
UnselectChip();
_spi.endTransaction();
if (flags == DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
{
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
}
return DS3234AlarmOne(dayOf, hour, minute, second, (DS3234AlarmOneControl)flags);
}
DS3234AlarmTwo GetAlarmTwo()
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_ALARMTWO);
uint8_t raw = _spi.transfer(0);
uint8_t flags = (raw & 0x80) >> 7;
uint8_t minute = BcdToUint8(raw & 0x7F);
raw = _spi.transfer(0);
flags |= (raw & 0x80) >> 6;
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
raw = _spi.transfer(0);
flags |= (raw & 0xc0) >> 4;
uint8_t dayOf = BcdToUint8(raw & 0x3f);
UnselectChip();
_spi.endTransaction();
if (flags == DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch)
{
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
}
return DS3234AlarmTwo(dayOf, hour, minute, (DS3234AlarmTwoControl)flags);
}
// Latch must be called after an alarm otherwise it will not
// trigger again
DS3234AlarmFlag LatchAlarmsTriggeredFlags()
{
uint8_t sreg = getReg(DS3234_REG_STATUS);
uint8_t alarmFlags = (sreg & DS3234_AIFMASK);
sreg &= ~DS3234_AIFMASK; // clear the flags
setReg(DS3234_REG_STATUS, sreg);
return (DS3234AlarmFlag)alarmFlags;
}
void SetTemperatureCompensationRate(DS3234TempCompensationRate rate)
{
uint8_t sreg = getReg(DS3234_REG_STATUS);
sreg &= ~DS3234_CRATEMASK;
sreg |= (rate << DS3234_CRATE0);
setReg(DS3234_REG_STATUS, sreg);
}
DS3234TempCompensationRate GetTemperatureCompensationRate()
{
uint8_t sreg = getReg(DS3234_REG_STATUS);
return (sreg & DS3234_CRATEMASK) >> DS3234_CRATE0;
}
void ForceTemperatureCompensationUpdate(bool block)
{
uint8_t creg = getReg(DS3234_REG_CONTROL);
creg |= _BV(DS3234_CONV); // Write CONV bit
setReg(DS3234_REG_CONTROL, creg);
while (block && (creg & _BV(DS3234_CONV)) != 0)
{
// Block until CONV is 0
creg = getReg(DS3234_REG_CONTROL);
}
}
int8_t GetAgingOffset()
{
return getReg(DS3234_REG_AGING);
}
void SetAgingOffset(int8_t value)
{
setReg(DS3234_REG_AGING, value);
}
void SetMemory(uint8_t memoryAddress, uint8_t value)
{
SetMemory(memoryAddress, &value, 1);
}
uint8_t GetMemory(uint8_t memoryAddress)
{
uint8_t value;
GetMemory(memoryAddress, &value, 1);
return value;
}
uint8_t SetMemory(uint8_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
{
uint8_t countWritten = 0;
setReg(DS3234_REG_RAM_ADDRESS, memoryAddress);
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_RAM_DATA | DS3234_REG_WRITE_FLAG);
while (countBytes > 0)
{
_spi.transfer(*pValue++);
countBytes--;
countWritten++;
}
UnselectChip();
_spi.endTransaction();
return countWritten;
}
uint8_t GetMemory(uint8_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
{
// set address to read from
setReg(DS3234_REG_RAM_ADDRESS, memoryAddress);
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(DS3234_REG_RAM_DATA);
// read the data
uint8_t countRead = 0;
while (countBytes-- > 0)
{
*pValue++ = _spi.transfer(0);
countRead++;
}
UnselectChip();
_spi.endTransaction();
return countRead;
}
private:
T_SPI_METHOD& _spi;
uint8_t _csPin;
void SelectChip()
{
digitalWrite(_csPin, LOW);
}
void UnselectChip()
{
digitalWrite(_csPin, HIGH);
}
uint8_t getReg(uint8_t regAddress)
{
uint8_t regValue;
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(regAddress);
regValue = _spi.transfer(0);
UnselectChip();
_spi.endTransaction();
return regValue;
}
void setReg(uint8_t regAddress, uint8_t regValue)
{
_spi.beginTransaction(c_Ds3234SpiSettings);
SelectChip();
_spi.transfer(regAddress | DS3234_REG_WRITE_FLAG);
_spi.transfer(regValue);
UnselectChip();
_spi.endTransaction();
}
};
#endif // __RTCDS3234_H__

View File

@@ -0,0 +1,211 @@
#include <Arduino.h>
#include "RtcDateTime.h"
const uint8_t c_daysInMonth[] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
RtcDateTime::RtcDateTime(uint32_t secondsFrom2000)
{
_initWithSecondsFrom2000<uint32_t>(secondsFrom2000);
}
bool RtcDateTime::IsValid() const
{
// this just tests the most basic validity of the value ranges
// and valid leap years
// It does not check any time zone or daylight savings time
if ((_month > 0 && _month < 13) &&
(_dayOfMonth > 0 && _dayOfMonth < 32) &&
(_hour < 24) &&
(_minute < 60) &&
(_second < 60))
{
// days in a month tests
//
if (_month == 2)
{
if (_dayOfMonth > 29)
{
return false;
}
else if (_dayOfMonth > 28)
{
// leap day
// check year to make sure its a leap year
uint16_t year = Year();
if ((year % 4) != 0)
{
return false;
}
if ((year % 100) == 0 &&
(year % 400) != 0)
{
return false;
}
}
}
else if (_dayOfMonth == 31)
{
if ((((_month - 1) % 7) % 2) == 1)
{
return false;
}
}
return true;
}
return false;
}
uint8_t StringToUint8(const char* pString)
{
uint8_t value = 0;
// skip leading 0 and spaces
while ('0' == *pString || *pString == ' ')
{
pString++;
}
// calculate number until we hit non-numeral char
while ('0' <= *pString && *pString <= '9')
{
value *= 10;
value += *pString - '0';
pString++;
}
return value;
}
RtcDateTime::RtcDateTime(const char* date, const char* time)
{
// sample input: date = "Dec 06 2009", time = "12:34:56"
_yearFrom2000 = StringToUint8(date + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[0])
{
case 'J':
if ( date[1] == 'a' )
_month = 1;
else if ( date[2] == 'n' )
_month = 6;
else
_month = 7;
break;
case 'F':
_month = 2;
break;
case 'A':
_month = date[1] == 'p' ? 4 : 8;
break;
case 'M':
_month = date[2] == 'r' ? 3 : 5;
break;
case 'S':
_month = 9;
break;
case 'O':
_month = 10;
break;
case 'N':
_month = 11;
break;
case 'D':
_month = 12;
break;
}
_dayOfMonth = StringToUint8(date + 4);
_hour = StringToUint8(time);
_minute = StringToUint8(time + 3);
_second = StringToUint8(time + 6);
}
template <typename T> T DaysSinceFirstOfYear2000(uint16_t year, uint8_t month, uint8_t dayOfMonth)
{
T days = dayOfMonth;
for (uint8_t indexMonth = 1; indexMonth < month; ++indexMonth)
{
days += pgm_read_byte(c_daysInMonth + indexMonth - 1);
}
if (month > 2 && year % 4 == 0)
{
days++;
}
return days + 365 * year + (year + 3) / 4 - 1;
}
template <typename T> T SecondsIn(T days, uint8_t hours, uint8_t minutes, uint8_t seconds)
{
return ((days * 24L + hours) * 60 + minutes) * 60 + seconds;
}
uint8_t RtcDateTime::DayOfWeek() const
{
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
return (days + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
}
// 32-bit time; as seconds since 1/1/2000
uint32_t RtcDateTime::TotalSeconds() const
{
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
return SecondsIn<uint32_t>(days, _hour, _minute, _second);
}
// 64-bit time; as seconds since 1/1/2000
uint64_t RtcDateTime::TotalSeconds64() const
{
uint32_t days = DaysSinceFirstOfYear2000<uint32_t>(_yearFrom2000, _month, _dayOfMonth);
return SecondsIn<uint64_t>(days, _hour, _minute, _second);
}
// total days since 1/1/2000
uint16_t RtcDateTime::TotalDays() const
{
return DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
}
void RtcDateTime::InitWithIso8601(const char* date)
{
// sample input: date = "Sat, 06 Dec 2009 12:34:56 GMT"
_yearFrom2000 = StringToUint8(date + 13);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[8])
{
case 'J':
if (date[1 + 8] == 'a')
_month = 1;
else if (date[2 + 8] == 'n')
_month = 6;
else
_month = 7;
break;
case 'F':
_month = 2;
break;
case 'A':
_month = date[1 + 8] == 'p' ? 4 : 8;
break;
case 'M':
_month = date[2 + 8] == 'r' ? 3 : 5;
break;
case 'S':
_month = 9;
break;
case 'O':
_month = 10;
break;
case 'N':
_month = 11;
break;
case 'D':
_month = 12;
break;
}
_dayOfMonth = StringToUint8(date + 5);
_hour = StringToUint8(date + 17);
_minute = StringToUint8(date + 20);
_second = StringToUint8(date + 23);
}

View File

@@ -0,0 +1,185 @@
#ifndef __RTCDATETIME_H__
#define __RTCDATETIME_H__
// ESP32 complains if not included
#if defined(ARDUINO_ARCH_ESP32)
#include <inttypes.h>
#endif
enum DayOfWeek
{
DayOfWeek_Sunday = 0,
DayOfWeek_Monday,
DayOfWeek_Tuesday,
DayOfWeek_Wednesday,
DayOfWeek_Thursday,
DayOfWeek_Friday,
DayOfWeek_Saturday,
};
const uint16_t c_OriginYear = 2000;
const uint32_t c_Epoch32OfOriginYear = 946684800;
extern const uint8_t c_daysInMonth[] PROGMEM;
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 = Saturday
uint8_t DayOfWeek() const;
// 32-bit time; as seconds since 1/1/2000
uint32_t TotalSeconds() const;
// 64-bit time; as seconds since 1/1/2000
uint64_t TotalSeconds64() const;
// total days since 1/1/2000
uint16_t TotalDays() const;
// add seconds
void operator += (uint32_t seconds)
{
RtcDateTime after = RtcDateTime( TotalSeconds() + seconds );
*this = after;
}
// remove seconds
void operator -= (uint32_t seconds)
{
RtcDateTime before = RtcDateTime( TotalSeconds() - seconds );
*this = before;
}
// allows for comparisons to just work (==, <, >, <=, >=, !=)
operator uint32_t() const
{
return TotalSeconds();
}
// Epoch32 support
uint32_t Epoch32Time() const
{
return TotalSeconds() + c_Epoch32OfOriginYear;
}
void InitWithEpoch32Time(uint32_t time)
{
_initWithSecondsFrom2000<uint32_t>(time - c_Epoch32OfOriginYear);
}
// Epoch64 support
uint64_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 = Monday
static uint8_t ConvertDowToRtc(uint8_t dow)
{
if (dow == 0)
{
dow = 7;
}
return dow;
}
// convert Rtc Day of Week to our Day of Week
static 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;
}
};
#endif // __RTCDATETIME_H__

View File

@@ -0,0 +1,153 @@
#ifndef __RTCTEMPERATURE_H__
#define __RTCTEMPERATURE_H__
class RtcTemperature
{
public:
// Constructor
// a) Merge RTC registers into signed scaled temperature (x256),
// then bind to RTC resolution.
// | r11h | DP | r12h |
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
// s i i i i i i i . f f 0 0 0 0 0 0
//
// b) Rescale to (x4) by right-shifting (6) bits
// | | DP | |
// Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 . 1 0 -1 -2
// s s s s s s s i i i i i i i f f 0 0
RtcTemperature(int8_t highByteDegreesC, uint8_t lowByteDegreesC)
{
int16_t scaledDegC = ((highByteDegreesC << 8) | (lowByteDegreesC & 0xC0)) >> 6;
_centiDegC = scaledDegC * 100 / 4;
}
RtcTemperature(int16_t centiDegC = 0) :
_centiDegC(centiDegC)
{
}
// Float temperature Celsius
float AsFloatDegC()
{
return (float)_centiDegC / 100.0f;
}
// Float temperature Fahrenheit
float AsFloatDegF()
{
return AsFloatDegC() * 1.8f + 32.0f;
}
// centi degrees (1/100th of a degree),
int16_t AsCentiDegC()
{
return _centiDegC;
}
void Print(Stream& target, uint8_t decimals = 2, char decimal = '.')
{
int16_t decimalDivisor = 1;
int16_t integerPart;
int16_t decimalPart;
{
int16_t rounded = abs(_centiDegC);
// round up as needed
if (decimals == 0)
{
rounded += 50;
}
else if (decimals == 1)
{
rounded += 5;
decimalDivisor = 10;
}
integerPart = rounded / 100;
decimalPart = (rounded % 100) / decimalDivisor;
}
// test for zero before printing negative sign to not print-0.00
if (_centiDegC < 0 && (integerPart != 0 || decimalPart != 0))
{
target.print('-');
}
// print integer part
target.print(integerPart);
// print decimal part
if (decimals != 0)
{
target.print(decimal);
if (decimalPart != 0)
{
target.print(decimalPart);
}
else
{
// append zeros as requested
while (decimals > 0)
{
target.print('0');
decimals--;
}
}
}
}
bool operator==(const RtcTemperature& other) const
{
return (_centiDegC == other._centiDegC);
};
bool operator>(const RtcTemperature& other) const
{
return (_centiDegC > other._centiDegC);
};
bool operator<(const RtcTemperature& other) const
{
return (_centiDegC < other._centiDegC);
};
bool operator>=(const RtcTemperature& other) const
{
return (_centiDegC >= other._centiDegC);
};
bool operator<=(const RtcTemperature& other) const
{
return (_centiDegC <= other._centiDegC);
};
bool operator!=(const RtcTemperature& other) const
{
return (_centiDegC != other._centiDegC);
};
RtcTemperature operator-(const RtcTemperature& right)
{
RtcTemperature result;
result._centiDegC = (_centiDegC - right._centiDegC);
return result;
}
RtcTemperature operator+(const RtcTemperature& right)
{
RtcTemperature result;
result._centiDegC = (_centiDegC + right._centiDegC);
return result;
}
protected:
int16_t _centiDegC; // 1/100th of a degree temperature (100 x degC)
};
#endif // __RTCTEMPERATURE_H__

View File

@@ -0,0 +1,34 @@
#include <Arduino.h>
#include "RtcUtility.h"
uint8_t BcdToUint8(uint8_t val)
{
return val - 6 * (val >> 4);
}
uint8_t Uint8ToBcd(uint8_t val)
{
return val + 6 * (val / 10);
}
uint8_t BcdToBin24Hour(uint8_t bcdHour)
{
uint8_t hour;
if (bcdHour & 0x40)
{
// 12 hour mode, convert to 24
bool isPm = ((bcdHour & 0x20) != 0);
hour = BcdToUint8(bcdHour & 0x1f);
if (isPm)
{
hour += 12;
}
}
else
{
hour = BcdToUint8(bcdHour);
}
return hour;
}

View File

@@ -0,0 +1,35 @@
#ifndef __RTCUTILITY_H__
#define __RTCUTILITY_H__
// ESP32 complains if not included
#if defined(ARDUINO_ARCH_ESP32)
#include <inttypes.h>
#endif
// Arduino has no standard for attributing methods used for ISRs
// even though some platforms require it, so to simplify the problem
// for end users, this provides a standard ISR_ATTR
#if !defined(ISR_ATTR)
#if defined(ARDUINO_ARCH_ESP8266)
#define ISR_ATTR ICACHE_RAM_ATTR
#elif defined(ARDUINO_ARCH_ESP32)
#define ISR_ATTR ICACHE_RAM_ATTR
#else
#define ISR_ATTR
#endif
#endif // !defined(ISR_ATTR)
// for some reason, the DUE board support does not define this, even though other non AVR archs do
#ifndef _BV
#define _BV(b) (1UL << (b))
#endif
extern uint8_t BcdToUint8(uint8_t val);
extern uint8_t Uint8ToBcd(uint8_t val);
extern uint8_t BcdToBin24Hour(uint8_t bcdHour);
#endif // __RTCUTILITY_H__

View File

@@ -0,0 +1,99 @@
#pragma once
//ThreeWire command Read/Write flag
const uint8_t THREEWIRE_READFLAG = 0x01;
class ThreeWire
{
public:
ThreeWire(uint8_t ioPin, uint8_t clkPin, uint8_t cePin) :
_ioPin(ioPin),
_clkPin(clkPin),
_cePin(cePin)
{
}
void begin() {
resetPins();
}
void end() {
resetPins();
}
void beginTransmission(uint8_t command) {
digitalWrite(_cePin, LOW); // default, not enabled
pinMode(_cePin, OUTPUT);
digitalWrite(_clkPin, LOW); // default, clock low
pinMode(_clkPin, OUTPUT);
pinMode(_ioPin, OUTPUT);
digitalWrite(_cePin, HIGH); // start the session
delayMicroseconds(4); // tCC = 4us
write(command, (command & THREEWIRE_READFLAG) == THREEWIRE_READFLAG);
}
void endTransmission() {
digitalWrite(_cePin, LOW);
delayMicroseconds(4); // tCWH = 4us
}
void write(uint8_t value, bool isDataRequestCommand = false) {
for (uint8_t bit = 0; bit < 8; bit++) {
digitalWrite(_ioPin, value & 0x01);
delayMicroseconds(1); // tDC = 200ns
// clock up, data is read by DS1302
digitalWrite(_clkPin, HIGH);
delayMicroseconds(1); // tCH = 1000ns, tCDH = 800ns
// for the last bit before a read
// Set IO line for input before the clock down
if (bit == 7 && isDataRequestCommand) {
pinMode(_ioPin, INPUT);
}
digitalWrite(_clkPin, LOW);
delayMicroseconds(1); // tCL=1000ns, tCDD=800ns
value >>= 1;
}
}
uint8_t read() {
uint8_t value = 0;
for (uint8_t bit = 0; bit < 8; bit++) {
// first bit is present on io pin, so only clock the other
// bits
value |= (digitalRead(_ioPin) << bit);
// Clock up, prepare for next
digitalWrite(_clkPin, HIGH);
delayMicroseconds(1);
// Clock down, value is ready after some time.
digitalWrite(_clkPin, LOW);
delayMicroseconds(1); // tCL=1000ns, tCDD=800ns
}
return value;
}
private:
const uint8_t _ioPin;
const uint8_t _clkPin;
const uint8_t _cePin;
void resetPins() {
// just making sure they are in a default low power use state
// as required state is set when transmissions are started
// three wire devices have internal pull downs so they will be low
pinMode(_clkPin, INPUT);
pinMode(_ioPin, INPUT);
pinMode(_cePin, INPUT);
}
};