First Commit
This commit is contained in:
134
libraries/RTClib/src/RTC_DS1307.cpp
Normal file
134
libraries/RTClib/src/RTC_DS1307.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
#define DS1307_ADDRESS 0x68 ///< I2C address for DS1307
|
||||
#define DS1307_CONTROL 0x07 ///< Control register
|
||||
#define DS1307_NVRAM 0x08 ///< Start of RAM registers - 56 bytes, 0x08 to 0x3f
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the DS1307 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find DS1307 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS1307::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(DS1307_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the DS1307 running? Check the Clock Halt bit in register 0
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_DS1307::isrunning(void) { return !(read_register(0) >> 7); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time in the DS1307
|
||||
@param dt DateTime object containing the desired date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {0,
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
0,
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date and time from the DS1307
|
||||
@return DateTime object containing the current date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS1307::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 0;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
|
||||
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the current mode of the SQW pin
|
||||
@return Mode as Ds1307SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() {
|
||||
return static_cast<Ds1307SqwPinMode>(read_register(DS1307_CONTROL) & 0x93);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Change the SQW pin mode
|
||||
@param mode The mode to use
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) {
|
||||
write_register(DS1307_CONTROL, mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read data from the DS1307's NVRAM
|
||||
@param buf Pointer to a buffer to store the data - make sure it's large
|
||||
enough to hold size bytes
|
||||
@param size Number of bytes to read
|
||||
@param address Starting NVRAM address, from 0 to 55
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::readnvram(uint8_t *buf, uint8_t size, uint8_t address) {
|
||||
uint8_t addrByte = DS1307_NVRAM + address;
|
||||
i2c_dev->write_then_read(&addrByte, 1, buf, size);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Write data to the DS1307 NVRAM
|
||||
@param address Starting NVRAM address, from 0 to 55
|
||||
@param buf Pointer to buffer containing the data to write
|
||||
@param size Number of bytes in buf to write to NVRAM
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writenvram(uint8_t address, const uint8_t *buf, uint8_t size) {
|
||||
uint8_t addrByte = DS1307_NVRAM + address;
|
||||
i2c_dev->write(buf, size, true, &addrByte, 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Shortcut to read one byte from NVRAM
|
||||
@param address NVRAM address, 0 to 55
|
||||
@return The byte read from NVRAM
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_DS1307::readnvram(uint8_t address) {
|
||||
uint8_t data;
|
||||
readnvram(&data, 1, address);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Shortcut to write one byte to NVRAM
|
||||
@param address NVRAM address, 0 to 55
|
||||
@param data One byte to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writenvram(uint8_t address, uint8_t data) {
|
||||
writenvram(address, &data, 1);
|
||||
}
|
||||
384
libraries/RTClib/src/RTC_DS3231.cpp
Normal file
384
libraries/RTClib/src/RTC_DS3231.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
#define DS3231_ADDRESS 0x68 ///< I2C address for DS3231
|
||||
#define DS3231_TIME 0x00 ///< Time register
|
||||
#define DS3231_ALARM1 0x07 ///< Alarm 1 register
|
||||
#define DS3231_ALARM2 0x0B ///< Alarm 2 register
|
||||
#define DS3231_CONTROL 0x0E ///< Control register
|
||||
#define DS3231_STATUSREG 0x0F ///< Status register
|
||||
#define DS3231_TEMPERATUREREG \
|
||||
0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit
|
||||
///< temperature value
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the DS3231 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find DS3231 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(DS3231_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status register Oscillator Stop Flag to see if the DS3231
|
||||
stopped due to power loss
|
||||
@return True if the bit is set (oscillator stopped) or false if it is
|
||||
running
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::lostPower(void) {
|
||||
return read_register(DS3231_STATUSREG) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and flip the Oscillator Stop Flag
|
||||
@param dt DateTime object containing the date/time to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {DS3231_TIME,
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
bin2bcd(dowToDS3231(dt.dayOfTheWeek())),
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
|
||||
uint8_t statreg = read_register(DS3231_STATUSREG);
|
||||
statreg &= ~0x80; // flip OSF bit
|
||||
write_register(DS3231_STATUSREG, statreg);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object with the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 0;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F),
|
||||
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the SQW pin mode
|
||||
@return Pin mode, see Ds3231SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
|
||||
int mode;
|
||||
mode = read_register(DS3231_CONTROL) & 0x1C;
|
||||
if (mode & 0x04)
|
||||
mode = DS3231_OFF;
|
||||
return static_cast<Ds3231SqwPinMode>(mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the SQW pin mode
|
||||
@param mode Desired mode, see Ds3231SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
|
||||
ctrl &= ~0x04; // turn off INTCON
|
||||
ctrl &= ~0x18; // set freq bits to 0
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current temperature from the DS3231's temperature sensor
|
||||
@return Current temperature (float)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float RTC_DS3231::getTemperature() {
|
||||
uint8_t buffer[2] = {DS3231_TEMPERATUREREG, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 2);
|
||||
return (float)buffer[0] + (buffer[1] >> 6) * 0.25f;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set alarm 1 for DS3231
|
||||
@param dt DateTime object
|
||||
@param alarm_mode Desired mode, see Ds3231Alarm1Mode enum
|
||||
@return False if control register is not set, otherwise true
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
if (!(ctrl & 0x04)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7.
|
||||
uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7.
|
||||
uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7.
|
||||
uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7.
|
||||
uint8_t DY_DT = (alarm_mode & 0x10)
|
||||
<< 2; // Day/Date bit 6. Date when 0, day of week when 1.
|
||||
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
|
||||
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, uint8_t(bin2bcd(dt.second()) | A1M1),
|
||||
uint8_t(bin2bcd(dt.minute()) | A1M2),
|
||||
uint8_t(bin2bcd(dt.hour()) | A1M3),
|
||||
uint8_t(bin2bcd(day) | A1M4 | DY_DT)};
|
||||
i2c_dev->write(buffer, 5);
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | 0x01); // AI1E
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set alarm 2 for DS3231
|
||||
@param dt DateTime object
|
||||
@param alarm_mode Desired mode, see Ds3231Alarm2Mode enum
|
||||
@return False if control register is not set, otherwise true
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
if (!(ctrl & 0x04)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7.
|
||||
uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7.
|
||||
uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7.
|
||||
uint8_t DY_DT = (alarm_mode & 0x08)
|
||||
<< 3; // Day/Date bit 6. Date when 0, day of week when 1.
|
||||
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
|
||||
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2),
|
||||
uint8_t(bin2bcd(dt.hour()) | A2M3),
|
||||
uint8_t(bin2bcd(day) | A2M4 | DY_DT)};
|
||||
i2c_dev->write(buffer, 4);
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | 0x02); // AI2E
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the date/time value of Alarm1
|
||||
@return DateTime object with the Alarm1 data set in the
|
||||
day, hour, minutes, and seconds fields
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::getAlarm1() {
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 5);
|
||||
|
||||
uint8_t seconds = bcd2bin(buffer[0] & 0x7F);
|
||||
uint8_t minutes = bcd2bin(buffer[1] & 0x7F);
|
||||
// Fetching the hour assumes 24 hour time (never 12)
|
||||
// because this library exclusively stores the time
|
||||
// in 24 hour format. Note that the DS3231 supports
|
||||
// 12 hour storage, and sets bits to indicate the type
|
||||
// that is stored.
|
||||
uint8_t hour = bcd2bin(buffer[2] & 0x3F);
|
||||
|
||||
// Determine if the alarm is set to fire based on the
|
||||
// day of the week, or an explicit date match.
|
||||
bool isDayOfWeek = (buffer[3] & 0x40) >> 6;
|
||||
uint8_t day;
|
||||
if (isDayOfWeek) {
|
||||
// Alarm set to match on day of the week
|
||||
day = bcd2bin(buffer[3] & 0x0F);
|
||||
} else {
|
||||
// Alarm set to match on day of the month
|
||||
day = bcd2bin(buffer[3] & 0x3F);
|
||||
}
|
||||
|
||||
// On the first week of May 2000, the day-of-the-week number
|
||||
// matches the date number.
|
||||
return DateTime(2000, 5, day, hour, minutes, seconds);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the date/time value of Alarm2
|
||||
@return DateTime object with the Alarm2 data set in the
|
||||
day, hour, and minutes fields
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::getAlarm2() {
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 4);
|
||||
|
||||
uint8_t minutes = bcd2bin(buffer[0] & 0x7F);
|
||||
// Fetching the hour assumes 24 hour time (never 12)
|
||||
// because this library exclusively stores the time
|
||||
// in 24 hour format. Note that the DS3231 supports
|
||||
// 12 hour storage, and sets bits to indicate the type
|
||||
// that is stored.
|
||||
uint8_t hour = bcd2bin(buffer[1] & 0x3F);
|
||||
|
||||
// Determine if the alarm is set to fire based on the
|
||||
// day of the week, or an explicit date match.
|
||||
bool isDayOfWeek = (buffer[2] & 0x40) >> 6;
|
||||
uint8_t day;
|
||||
if (isDayOfWeek) {
|
||||
// Alarm set to match on day of the week
|
||||
day = bcd2bin(buffer[2] & 0x0F);
|
||||
} else {
|
||||
// Alarm set to match on day of the month
|
||||
day = bcd2bin(buffer[2] & 0x3F);
|
||||
}
|
||||
|
||||
// On the first week of May 2000, the day-of-the-week number
|
||||
// matches the date number.
|
||||
return DateTime(2000, 5, day, hour, minutes, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the mode for Alarm1
|
||||
@return Ds3231Alarm1Mode enum value for the current Alarm1 mode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231Alarm1Mode RTC_DS3231::getAlarm1Mode() {
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 5);
|
||||
|
||||
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Seconds bit
|
||||
| (buffer[1] & 0x80) >> 6 // A1M2 - Minutes bit
|
||||
| (buffer[2] & 0x80) >> 5 // A1M3 - Hour bit
|
||||
| (buffer[3] & 0x80) >> 4 // A1M4 - Day/Date bit
|
||||
| (buffer[3] & 0x40) >> 2; // DY_DT
|
||||
|
||||
// Determine which mode the fetched alarm bits map to
|
||||
switch (alarm_mode) {
|
||||
case DS3231_A1_PerSecond:
|
||||
case DS3231_A1_Second:
|
||||
case DS3231_A1_Minute:
|
||||
case DS3231_A1_Hour:
|
||||
case DS3231_A1_Date:
|
||||
case DS3231_A1_Day:
|
||||
return (Ds3231Alarm1Mode)alarm_mode;
|
||||
default:
|
||||
// Default if the alarm mode cannot be read
|
||||
return DS3231_A1_Date;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the mode for Alarm2
|
||||
@return Ds3231Alarm2Mode enum value for the current Alarm2 mode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231Alarm2Mode RTC_DS3231::getAlarm2Mode() {
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 4);
|
||||
|
||||
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A2M2 - Minutes bit
|
||||
| (buffer[1] & 0x80) >> 6 // A2M3 - Hour bit
|
||||
| (buffer[2] & 0x80) >> 5 // A2M4 - Day/Date bit
|
||||
| (buffer[2] & 0x40) >> 3; // DY_DT
|
||||
|
||||
// Determine which mode the fetched alarm bits map to
|
||||
switch (alarm_mode) {
|
||||
case DS3231_A2_PerMinute:
|
||||
case DS3231_A2_Minute:
|
||||
case DS3231_A2_Hour:
|
||||
case DS3231_A2_Date:
|
||||
case DS3231_A2_Day:
|
||||
return (Ds3231Alarm2Mode)alarm_mode;
|
||||
default:
|
||||
// Default if the alarm mode cannot be read
|
||||
return DS3231_A2_Date;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable alarm
|
||||
@param alarm_num Alarm number to disable
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::disableAlarm(uint8_t alarm_num) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
ctrl &= ~(1 << (alarm_num - 1));
|
||||
write_register(DS3231_CONTROL, ctrl);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Clear status of alarm
|
||||
@param alarm_num Alarm number to clear
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::clearAlarm(uint8_t alarm_num) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status &= ~(0x1 << (alarm_num - 1));
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get status of alarm
|
||||
@param alarm_num Alarm number to check status of
|
||||
@return True if alarm has been fired otherwise false
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::alarmFired(uint8_t alarm_num) {
|
||||
return (read_register(DS3231_STATUSREG) >> (alarm_num - 1)) & 0x1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable 32KHz Output
|
||||
@details The 32kHz output is enabled by default. It requires an external
|
||||
pull-up resistor to function correctly
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::enable32K(void) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status |= (0x1 << 0x03);
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable 32KHz Output
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::disable32K(void) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status &= ~(0x1 << 0x03);
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get status of 32KHz Output
|
||||
@return True if enabled otherwise false
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::isEnabled32K(void) {
|
||||
return (read_register(DS3231_STATUSREG) >> 0x03) & 0x01;
|
||||
}
|
||||
33
libraries/RTClib/src/RTC_Micros.cpp
Normal file
33
libraries/RTClib/src/RTC_Micros.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the current date/time of the RTC_Micros clock.
|
||||
@param dt DateTime object with the desired date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Micros::adjust(const DateTime &dt) {
|
||||
lastMicros = micros();
|
||||
lastUnix = dt.unixtime();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Adjust the RTC_Micros clock to compensate for system clock drift
|
||||
@param ppm Adjustment to make. A positive adjustment makes the clock faster.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Micros::adjustDrift(int ppm) { microsPerSecond = 1000000 - ppm; }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time from the RTC_Micros clock.
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_Micros::now() {
|
||||
uint32_t elapsedSeconds = (micros() - lastMicros) / microsPerSecond;
|
||||
lastMicros += elapsedSeconds * microsPerSecond;
|
||||
lastUnix += elapsedSeconds;
|
||||
return lastUnix;
|
||||
}
|
||||
27
libraries/RTClib/src/RTC_Millis.cpp
Normal file
27
libraries/RTClib/src/RTC_Millis.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the current date/time of the RTC_Millis clock.
|
||||
@param dt DateTime object with the desired date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Millis::adjust(const DateTime &dt) {
|
||||
lastMillis = millis();
|
||||
lastUnix = dt.unixtime();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return a DateTime object containing the current date/time.
|
||||
Note that computing (millis() - lastMillis) is rollover-safe as long
|
||||
as this method is called at least once every 49.7 days.
|
||||
@return DateTime object containing current time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_Millis::now() {
|
||||
uint32_t elapsedSeconds = (millis() - lastMillis) / 1000;
|
||||
lastMillis += elapsedSeconds * 1000;
|
||||
lastUnix += elapsedSeconds;
|
||||
return lastUnix;
|
||||
}
|
||||
292
libraries/RTClib/src/RTC_PCF8523.cpp
Normal file
292
libraries/RTClib/src/RTC_PCF8523.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
#define PCF8523_ADDRESS 0x68 ///< I2C address for PCF8523
|
||||
#define PCF8523_CLKOUTCONTROL 0x0F ///< Timer and CLKOUT control register
|
||||
#define PCF8523_CONTROL_1 0x00 ///< Control and status register 1
|
||||
#define PCF8523_CONTROL_2 0x01 ///< Control and status register 2
|
||||
#define PCF8523_CONTROL_3 0x02 ///< Control and status register 3
|
||||
#define PCF8523_TIMER_B_FRCTL 0x12 ///< Timer B source clock frequency control
|
||||
#define PCF8523_TIMER_B_VALUE 0x13 ///< Timer B value (number clock periods)
|
||||
#define PCF8523_OFFSET 0x0E ///< Offset register
|
||||
#define PCF8523_STATUSREG 0x03 ///< Status register
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the PCF8523 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find PCF8523 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(PCF8523_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status register Oscillator Stop flag to see if the PCF8523
|
||||
stopped due to power loss
|
||||
@details When battery or external power is first applied, the PCF8523's
|
||||
crystal oscillator takes up to 2s to stabilize. During this time adjust()
|
||||
cannot clear the 'OS' flag. See datasheet OS flag section for details.
|
||||
@return True if the bit is set (oscillator is or has stopped) and false only
|
||||
after the bit is cleared, for instance with adjust()
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::lostPower(void) {
|
||||
return read_register(PCF8523_STATUSREG) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check control register 3 to see if we've run adjust() yet (setting
|
||||
the date/time and battery switchover mode)
|
||||
@return True if the PCF8523 has been set up, false if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::initialized(void) {
|
||||
return (read_register(PCF8523_CONTROL_3) & 0xE0) != 0xE0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time, set battery switchover mode
|
||||
@param dt DateTime to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {3, // start at location 3
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(0), // skip weekdays
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
|
||||
// set to battery switchover mode
|
||||
write_register(PCF8523_CONTROL_3, 0x00);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_PCF8523::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 3;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
|
||||
bcd2bin(buffer[3]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Resets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::start(void) {
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
|
||||
if (ctlreg & (1 << 5))
|
||||
write_register(PCF8523_CONTROL_1, ctlreg & ~(1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::stop(void) {
|
||||
write_register(PCF8523_CONTROL_1,
|
||||
read_register(PCF8523_CONTROL_1) | (1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the PCF8523 running? Check the STOP bit in register Control_1
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_PCF8523::isrunning() {
|
||||
return !((read_register(PCF8523_CONTROL_1) >> 5) & 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the mode of the INT/SQW pin on the PCF8523
|
||||
@return SQW pin mode as a #Pcf8523SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() {
|
||||
int mode = read_register(PCF8523_CLKOUTCONTROL);
|
||||
mode >>= 3;
|
||||
mode &= 0x7;
|
||||
return static_cast<Pcf8523SqwPinMode>(mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the INT/SQW pin mode on the PCF8523
|
||||
@param mode The mode to set, see the #Pcf8523SqwPinMode enum for options
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) {
|
||||
write_register(PCF8523_CLKOUTCONTROL, mode << 3);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable the Second Timer (1Hz) Interrupt on the PCF8523.
|
||||
@details The INT/SQW pin will pull low for a brief pulse once per second.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableSecondTimer() {
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
|
||||
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
|
||||
// TAM pulse int. mode (shared with Timer A), CLKOUT (aka SQW) disabled
|
||||
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0xB8);
|
||||
// SIE Second timer int. enable
|
||||
write_register(PCF8523_CONTROL_1, ctlreg | (1 << 2));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable the Second Timer (1Hz) Interrupt on the PCF8523.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::disableSecondTimer() {
|
||||
write_register(PCF8523_CONTROL_1,
|
||||
read_register(PCF8523_CONTROL_1) & ~(1 << 2));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable the Countdown Timer Interrupt on the PCF8523.
|
||||
@details The INT/SQW pin will be pulled low at the end of a specified
|
||||
countdown period ranging from 244 microseconds to 10.625 days.
|
||||
Uses PCF8523 Timer B. Any existing CLKOUT square wave, configured with
|
||||
writeSqwPinMode(), will halt. The interrupt low pulse width is adjustable
|
||||
from 3/64ths (default) to 14/64ths of a second.
|
||||
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
|
||||
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
|
||||
@param numPeriods The number of clkFreq periods (1-255) to count down.
|
||||
@param lowPulseWidth Optional: the length of time for the interrupt pin
|
||||
low pulse. See the #PCF8523TimerIntPulse enum for options.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
|
||||
uint8_t numPeriods,
|
||||
uint8_t lowPulseWidth) {
|
||||
// Datasheet cautions against updating countdown value while it's running,
|
||||
// so disabling allows repeated calls with new values to set new countdowns
|
||||
disableCountdownTimer();
|
||||
|
||||
// Leave compatible settings intact
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_2);
|
||||
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
|
||||
|
||||
// CTBIE Countdown Timer B Interrupt Enabled
|
||||
write_register(PCF8523_CONTROL_2, ctlreg |= 0x01);
|
||||
|
||||
// Timer B source clock frequency, optionally int. low pulse width
|
||||
write_register(PCF8523_TIMER_B_FRCTL, lowPulseWidth << 4 | clkFreq);
|
||||
|
||||
// Timer B value (number of source clock periods)
|
||||
write_register(PCF8523_TIMER_B_VALUE, numPeriods);
|
||||
|
||||
// TBM Timer B pulse int. mode, CLKOUT (aka SQW) disabled, TBC start Timer B
|
||||
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0x79);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@overload
|
||||
@brief Enable Countdown Timer using default interrupt low pulse width.
|
||||
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
|
||||
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
|
||||
@param numPeriods The number of clkFreq periods (1-255) to count down.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
|
||||
uint8_t numPeriods) {
|
||||
enableCountdownTimer(clkFreq, numPeriods, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable the Countdown Timer Interrupt on the PCF8523.
|
||||
@details For simplicity, this function strictly disables Timer B by setting
|
||||
TBC to 0. The datasheet describes TBC as the Timer B on/off switch.
|
||||
Timer B is the only countdown timer implemented at this time.
|
||||
The following flags have no effect while TBC is off, they are *not* cleared:
|
||||
- TBM: Timer B will still be set to pulsed mode.
|
||||
- CTBIE: Timer B interrupt would be triggered if TBC were on.
|
||||
- CTBF: Timer B flag indicates that interrupt was triggered. Though
|
||||
typically used for non-pulsed mode, user may wish to query this later.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::disableCountdownTimer() {
|
||||
// TBC disable to stop Timer B clock
|
||||
write_register(PCF8523_CLKOUTCONTROL,
|
||||
~1 & read_register(PCF8523_CLKOUTCONTROL));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Stop all timers, clear their flags and settings on the PCF8523.
|
||||
@details This includes the Countdown Timer, Second Timer, and any CLKOUT
|
||||
square wave configured with writeSqwPinMode().
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::deconfigureAllTimers() {
|
||||
disableSecondTimer(); // Surgically clears CONTROL_1
|
||||
write_register(PCF8523_CONTROL_2, 0);
|
||||
write_register(PCF8523_CLKOUTCONTROL, 0);
|
||||
write_register(PCF8523_TIMER_B_FRCTL, 0);
|
||||
write_register(PCF8523_TIMER_B_VALUE, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compensate the drift of the RTC.
|
||||
@details This method sets the "offset" register of the PCF8523,
|
||||
which can be used to correct a previously measured drift rate.
|
||||
Two correction modes are available:
|
||||
|
||||
- **PCF8523\_TwoHours**: Clock adjustments are performed on
|
||||
`offset` consecutive minutes every two hours. This is the most
|
||||
energy-efficient mode.
|
||||
|
||||
- **PCF8523\_OneMinute**: Clock adjustments are performed on
|
||||
`offset` consecutive seconds every minute. Extra adjustments are
|
||||
performed on the last second of the minute is `abs(offset)>60`.
|
||||
|
||||
The `offset` parameter sets the correction amount in units of
|
||||
roughly 4 ppm. The exact unit depends on the selected mode:
|
||||
|
||||
| mode | offset unit |
|
||||
|---------------------|----------------------------------------|
|
||||
| `PCF8523_TwoHours` | 4.340 ppm = 0.375 s/day = 2.625 s/week |
|
||||
| `PCF8523_OneMinute` | 4.069 ppm = 0.352 s/day = 2.461 s/week |
|
||||
|
||||
See the accompanying sketch pcf8523.ino for an example on how to
|
||||
use this method.
|
||||
|
||||
@param mode Correction mode, either `PCF8523_TwoHours` or
|
||||
`PCF8523_OneMinute`.
|
||||
@param offset Correction amount, from -64 to +63. A positive offset
|
||||
makes the clock slower.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::calibrate(Pcf8523OffsetMode mode, int8_t offset) {
|
||||
write_register(PCF8523_OFFSET, ((uint8_t)offset & 0x7F) | mode);
|
||||
}
|
||||
123
libraries/RTClib/src/RTC_PCF8563.cpp
Normal file
123
libraries/RTClib/src/RTC_PCF8563.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "RTClib.h"
|
||||
|
||||
#define PCF8563_ADDRESS 0x51 ///< I2C address for PCF8563
|
||||
#define PCF8563_CLKOUTCONTROL 0x0D ///< CLKOUT control register
|
||||
#define PCF8563_CONTROL_1 0x00 ///< Control and status register 1
|
||||
#define PCF8563_CONTROL_2 0x01 ///< Control and status register 2
|
||||
#define PCF8563_VL_SECONDS 0x02 ///< register address for VL_SECONDS
|
||||
#define PCF8563_CLKOUT_MASK 0x83 ///< bitmask for SqwPinMode on CLKOUT pin
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the PCF8563 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find PCF8563 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8563::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(PCF8563_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status of the VL bit in the VL_SECONDS register.
|
||||
@details The PCF8563 has an on-chip voltage-low detector. When VDD drops
|
||||
below Vlow, bit VL in the VL_seconds register is set to indicate that
|
||||
the integrity of the clock information is no longer guaranteed.
|
||||
@return True if the bit is set (VDD droped below Vlow) indicating that
|
||||
the clock integrity is not guaranteed and false only after the bit is
|
||||
cleared using adjust()
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8563::lostPower(void) {
|
||||
return read_register(PCF8563_VL_SECONDS) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time
|
||||
@param dt DateTime to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {PCF8563_VL_SECONDS, // start at location 2, VL_SECONDS
|
||||
bin2bcd(dt.second()), bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()), bin2bcd(dt.day()),
|
||||
bin2bcd(0), // skip weekdays
|
||||
bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_PCF8563::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = PCF8563_VL_SECONDS; // start at location 2, VL_SECONDS
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x1F),
|
||||
bcd2bin(buffer[3] & 0x3F), bcd2bin(buffer[2] & 0x3F),
|
||||
bcd2bin(buffer[1] & 0x7F), bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Resets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::start(void) {
|
||||
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
|
||||
if (ctlreg & (1 << 5))
|
||||
write_register(PCF8563_CONTROL_1, ctlreg & ~(1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::stop(void) {
|
||||
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
|
||||
if (!(ctlreg & (1 << 5)))
|
||||
write_register(PCF8563_CONTROL_1, ctlreg | (1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the PCF8563 running? Check the STOP bit in register Control_1
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_PCF8563::isrunning() {
|
||||
return !((read_register(PCF8563_CONTROL_1) >> 5) & 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the mode of the CLKOUT pin on the PCF8563
|
||||
@return CLKOUT pin mode as a #Pcf8563SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Pcf8563SqwPinMode RTC_PCF8563::readSqwPinMode() {
|
||||
int mode = read_register(PCF8563_CLKOUTCONTROL);
|
||||
return static_cast<Pcf8563SqwPinMode>(mode & PCF8563_CLKOUT_MASK);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the CLKOUT pin mode on the PCF8563
|
||||
@param mode The mode to set, see the #Pcf8563SqwPinMode enum for options
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::writeSqwPinMode(Pcf8563SqwPinMode mode) {
|
||||
write_register(PCF8563_CLKOUTCONTROL, mode);
|
||||
}
|
||||
764
libraries/RTClib/src/RTClib.cpp
Normal file
764
libraries/RTClib/src/RTClib.cpp
Normal file
@@ -0,0 +1,764 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file RTClib.cpp
|
||||
|
||||
@mainpage Adafruit RTClib
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
This is a fork of JeeLab's fantastic real time clock library for Arduino.
|
||||
|
||||
For details on using this library with an RTC module like the DS1307, PCF8523,
|
||||
or DS3231, see the guide at:
|
||||
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section classes Available classes
|
||||
|
||||
This library provides the following classes:
|
||||
|
||||
- Classes for manipulating dates, times and durations:
|
||||
- DateTime represents a specific point in time; this is the data
|
||||
type used for setting and reading the supported RTCs
|
||||
- TimeSpan represents the length of a time interval
|
||||
- Interfacing specific RTC chips:
|
||||
- RTC_DS1307
|
||||
- RTC_DS3231
|
||||
- RTC_PCF8523
|
||||
- RTC_PCF8563
|
||||
- RTC emulated in software; do not expect much accuracy out of these:
|
||||
- RTC_Millis is based on `millis()`
|
||||
- RTC_Micros is based on `micros()`; its drift rate can be tuned by
|
||||
the user
|
||||
|
||||
@section license License
|
||||
|
||||
Original library by JeeLabs https://jeelabs.org/pub/docs/rtclib/, released to
|
||||
the public domain.
|
||||
|
||||
This version: MIT (see LICENSE)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
// nothing special needed
|
||||
#elif defined(ARDUINO_SAM_DUE)
|
||||
#define PROGMEM
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Write value to register.
|
||||
@param reg register address
|
||||
@param val value to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_I2C::write_register(uint8_t reg, uint8_t val) {
|
||||
uint8_t buffer[2] = {reg, val};
|
||||
i2c_dev->write(buffer, 2);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read value from register.
|
||||
@param reg register address
|
||||
@return value of register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_I2C::read_register(uint8_t reg) {
|
||||
uint8_t buffer[1];
|
||||
i2c_dev->write(®, 1);
|
||||
i2c_dev->read(buffer, 1);
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
// utility code, some of this could be exposed in the DateTime API if needed
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
Number of days in each month, from January to November. December is not
|
||||
needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time
|
||||
library. C.f. https://github.com/adafruit/RTClib/issues/114
|
||||
*/
|
||||
const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30,
|
||||
31, 31, 30, 31, 30};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Given a date, return number of days since 2000/01/01,
|
||||
valid for 2000--2099
|
||||
@param y Year
|
||||
@param m Month
|
||||
@param d Day
|
||||
@return Number of days
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
|
||||
if (y >= 2000U)
|
||||
y -= 2000U;
|
||||
uint16_t days = d;
|
||||
for (uint8_t i = 1; i < m; ++i)
|
||||
days += pgm_read_byte(daysInMonth + i - 1);
|
||||
if (m > 2 && y % 4 == 0)
|
||||
++days;
|
||||
return days + 365 * y + (y + 3) / 4 - 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Given a number of days, hours, minutes, and seconds, return the
|
||||
total seconds
|
||||
@param days Days
|
||||
@param h Hours
|
||||
@param m Minutes
|
||||
@param s Seconds
|
||||
@return Number of seconds total
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
|
||||
return ((days * 24UL + h) * 60 + m) * 60 + s;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor from
|
||||
[Unix time](https://en.wikipedia.org/wiki/Unix_time).
|
||||
|
||||
This builds a DateTime from an integer specifying the number of seconds
|
||||
elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous
|
||||
to Unix time, with two small differences:
|
||||
|
||||
- The Unix epoch is specified to be at 00:00:00
|
||||
[UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time),
|
||||
whereas this class has no notion of time zones. The epoch used in
|
||||
this class is then at 00:00:00 on whatever time zone the user chooses
|
||||
to use, ignoring changes in DST.
|
||||
|
||||
- Unix time is conventionally represented with signed numbers, whereas
|
||||
this constructor takes an unsigned argument. Because of this, it does
|
||||
_not_ suffer from the
|
||||
[year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem).
|
||||
|
||||
If called without argument, it returns the earliest time representable
|
||||
by this class: 2000-01-01 00:00:00.
|
||||
|
||||
@see The `unixtime()` method is the converse of this constructor.
|
||||
|
||||
@param t Time elapsed in seconds since 1970-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(uint32_t t) {
|
||||
t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970
|
||||
|
||||
ss = t % 60;
|
||||
t /= 60;
|
||||
mm = t % 60;
|
||||
t /= 60;
|
||||
hh = t % 24;
|
||||
uint16_t days = t / 24;
|
||||
uint8_t leap;
|
||||
for (yOff = 0;; ++yOff) {
|
||||
leap = yOff % 4 == 0;
|
||||
if (days < 365U + leap)
|
||||
break;
|
||||
days -= 365 + leap;
|
||||
}
|
||||
for (m = 1; m < 12; ++m) {
|
||||
uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
|
||||
if (leap && m == 2)
|
||||
++daysPerMonth;
|
||||
if (days < daysPerMonth)
|
||||
break;
|
||||
days -= daysPerMonth;
|
||||
}
|
||||
d = days + 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor from (year, month, day, hour, minute, second).
|
||||
@warning If the provided parameters are not valid (e.g. 31 February),
|
||||
the constructed DateTime will be invalid.
|
||||
@see The `isValid()` method can be used to test whether the
|
||||
constructed DateTime is valid.
|
||||
@param year Either the full year (range: 2000--2099) or the offset from
|
||||
year 2000 (range: 0--99).
|
||||
@param month Month number (1--12).
|
||||
@param day Day of the month (1--31).
|
||||
@param hour,min,sec Hour (0--23), minute (0--59) and second (0--59).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
|
||||
uint8_t min, uint8_t sec) {
|
||||
if (year >= 2000U)
|
||||
year -= 2000U;
|
||||
yOff = year;
|
||||
m = month;
|
||||
d = day;
|
||||
hh = hour;
|
||||
mm = min;
|
||||
ss = sec;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Copy constructor.
|
||||
@param copy DateTime to copy.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const DateTime ©)
|
||||
: yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm),
|
||||
ss(copy.ss) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Convert a string containing two digits to uint8_t, e.g. "09" returns
|
||||
9
|
||||
@param p Pointer to a string containing two digits
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint8_t conv2d(const char *p) {
|
||||
uint8_t v = 0;
|
||||
if ('0' <= *p && *p <= '9')
|
||||
v = *p - '0';
|
||||
return 10 * v + *++p - '0';
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor for generating the build time.
|
||||
|
||||
This constructor expects its parameters to be strings in the format
|
||||
generated by the compiler's preprocessor macros `__DATE__` and
|
||||
`__TIME__`. Usage:
|
||||
|
||||
```
|
||||
DateTime buildTime(__DATE__, __TIME__);
|
||||
```
|
||||
|
||||
@note The `F()` macro can be used to reduce the RAM footprint, see
|
||||
the next constructor.
|
||||
|
||||
@param date Date string, e.g. "Apr 16 2020".
|
||||
@param time Time string, e.g. "18:34:56".
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const char *date, const char *time) {
|
||||
yOff = conv2d(date + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (date[0]) {
|
||||
case 'J':
|
||||
m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
|
||||
break;
|
||||
case 'F':
|
||||
m = 2;
|
||||
break;
|
||||
case 'A':
|
||||
m = date[2] == 'r' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
m = date[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
m = 9;
|
||||
break;
|
||||
case 'O':
|
||||
m = 10;
|
||||
break;
|
||||
case 'N':
|
||||
m = 11;
|
||||
break;
|
||||
case 'D':
|
||||
m = 12;
|
||||
break;
|
||||
}
|
||||
d = conv2d(date + 4);
|
||||
hh = conv2d(time);
|
||||
mm = conv2d(time + 3);
|
||||
ss = conv2d(time + 6);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Memory friendly constructor for generating the build time.
|
||||
|
||||
This version is intended to save RAM by keeping the date and time
|
||||
strings in program memory. Use it with the `F()` macro:
|
||||
|
||||
```
|
||||
DateTime buildTime(F(__DATE__), F(__TIME__));
|
||||
```
|
||||
|
||||
@param date Date PROGMEM string, e.g. F("Apr 16 2020").
|
||||
@param time Time PROGMEM string, e.g. F("18:34:56").
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const __FlashStringHelper *date,
|
||||
const __FlashStringHelper *time) {
|
||||
char buff[11];
|
||||
memcpy_P(buff, date, 11);
|
||||
yOff = conv2d(buff + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (buff[0]) {
|
||||
case 'J':
|
||||
m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7);
|
||||
break;
|
||||
case 'F':
|
||||
m = 2;
|
||||
break;
|
||||
case 'A':
|
||||
m = buff[2] == 'r' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
m = buff[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
m = 9;
|
||||
break;
|
||||
case 'O':
|
||||
m = 10;
|
||||
break;
|
||||
case 'N':
|
||||
m = 11;
|
||||
break;
|
||||
case 'D':
|
||||
m = 12;
|
||||
break;
|
||||
}
|
||||
d = conv2d(buff + 4);
|
||||
memcpy_P(buff, time, 8);
|
||||
hh = conv2d(buff);
|
||||
mm = conv2d(buff + 3);
|
||||
ss = conv2d(buff + 6);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor for creating a DateTime from an ISO8601 date string.
|
||||
|
||||
This constructor expects its parameters to be a string in the
|
||||
https://en.wikipedia.org/wiki/ISO_8601 format, e.g:
|
||||
|
||||
"2020-06-25T15:29:37"
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
DateTime dt("2020-06-25T15:29:37");
|
||||
```
|
||||
|
||||
@note The year must be > 2000, as only the yOff is considered.
|
||||
|
||||
@param iso8601dateTime
|
||||
A dateTime string in iso8601 format,
|
||||
e.g. "2020-06-25T15:29:37".
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const char *iso8601dateTime) {
|
||||
char ref[] = "2000-01-01T00:00:00";
|
||||
memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime)));
|
||||
yOff = conv2d(ref + 2);
|
||||
m = conv2d(ref + 5);
|
||||
d = conv2d(ref + 8);
|
||||
hh = conv2d(ref + 11);
|
||||
mm = conv2d(ref + 14);
|
||||
ss = conv2d(ref + 17);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check whether this DateTime is valid.
|
||||
@return true if valid, false if not.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::isValid() const {
|
||||
if (yOff >= 100)
|
||||
return false;
|
||||
DateTime other(unixtime());
|
||||
return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh &&
|
||||
mm == other.mm && ss == other.ss;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes the DateTime as a string in a user-defined format.
|
||||
|
||||
The _buffer_ parameter should be initialized by the caller with a string
|
||||
specifying the requested format. This format string may contain any of
|
||||
the following specifiers:
|
||||
|
||||
| specifier | output |
|
||||
|-----------|--------------------------------------------------------|
|
||||
| YYYY | the year as a 4-digit number (2000--2099) |
|
||||
| YY | the year as a 2-digit number (00--99) |
|
||||
| MM | the month as a 2-digit number (01--12) |
|
||||
| MMM | the abbreviated English month name ("Jan"--"Dec") |
|
||||
| DD | the day as a 2-digit number (01--31) |
|
||||
| DDD | the abbreviated English day of the week ("Mon"--"Sun") |
|
||||
| AP | either "AM" or "PM" |
|
||||
| ap | either "am" or "pm" |
|
||||
| hh | the hour as a 2-digit number (00--23 or 01--12) |
|
||||
| mm | the minute as a 2-digit number (00--59) |
|
||||
| ss | the second as a 2-digit number (00--59) |
|
||||
|
||||
If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode
|
||||
(range: 01--12). Otherwise it works in 24-hour mode (range: 00--23).
|
||||
|
||||
The specifiers within _buffer_ will be overwritten with the appropriate
|
||||
values from the DateTime. Any characters not belonging to one of the
|
||||
above specifiers are left as-is.
|
||||
|
||||
__Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output
|
||||
of the form "Thu, 16 Apr 2020 18:34:56.
|
||||
|
||||
@see The `timestamp()` method provides similar functionnality, but it
|
||||
returns a `String` object and supports a limited choice of
|
||||
predefined formats.
|
||||
|
||||
@param[in,out] buffer Array of `char` for holding the format description
|
||||
and the formatted DateTime. Before calling this method, the buffer
|
||||
should be initialized by the user with the format string. The method
|
||||
will overwrite the buffer with the formatted date and/or time.
|
||||
|
||||
@return A pointer to the provided buffer. This is returned for
|
||||
convenience, in order to enable idioms such as
|
||||
`Serial.println(now.toString(buffer));`
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
char *DateTime::toString(char *buffer) const {
|
||||
uint8_t apTag =
|
||||
(strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr);
|
||||
uint8_t hourReformatted = 0, isPM = false;
|
||||
if (apTag) { // 12 Hour Mode
|
||||
if (hh == 0) { // midnight
|
||||
isPM = false;
|
||||
hourReformatted = 12;
|
||||
} else if (hh == 12) { // noon
|
||||
isPM = true;
|
||||
hourReformatted = 12;
|
||||
} else if (hh < 12) { // morning
|
||||
isPM = false;
|
||||
hourReformatted = hh;
|
||||
} else { // 1 o'clock or after
|
||||
isPM = true;
|
||||
hourReformatted = hh - 12;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < strlen(buffer) - 1; i++) {
|
||||
if (buffer[i] == 'h' && buffer[i + 1] == 'h') {
|
||||
if (!apTag) { // 24 Hour Mode
|
||||
buffer[i] = '0' + hh / 10;
|
||||
buffer[i + 1] = '0' + hh % 10;
|
||||
} else { // 12 Hour Mode
|
||||
buffer[i] = '0' + hourReformatted / 10;
|
||||
buffer[i + 1] = '0' + hourReformatted % 10;
|
||||
}
|
||||
}
|
||||
if (buffer[i] == 'm' && buffer[i + 1] == 'm') {
|
||||
buffer[i] = '0' + mm / 10;
|
||||
buffer[i + 1] = '0' + mm % 10;
|
||||
}
|
||||
if (buffer[i] == 's' && buffer[i + 1] == 's') {
|
||||
buffer[i] = '0' + ss / 10;
|
||||
buffer[i + 1] = '0' + ss % 10;
|
||||
}
|
||||
if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') {
|
||||
static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat";
|
||||
const char *p = &day_names[3 * dayOfTheWeek()];
|
||||
buffer[i] = pgm_read_byte(p);
|
||||
buffer[i + 1] = pgm_read_byte(p + 1);
|
||||
buffer[i + 2] = pgm_read_byte(p + 2);
|
||||
} else if (buffer[i] == 'D' && buffer[i + 1] == 'D') {
|
||||
buffer[i] = '0' + d / 10;
|
||||
buffer[i + 1] = '0' + d % 10;
|
||||
}
|
||||
if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') {
|
||||
static PROGMEM const char month_names[] =
|
||||
"JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
const char *p = &month_names[3 * (m - 1)];
|
||||
buffer[i] = pgm_read_byte(p);
|
||||
buffer[i + 1] = pgm_read_byte(p + 1);
|
||||
buffer[i + 2] = pgm_read_byte(p + 2);
|
||||
} else if (buffer[i] == 'M' && buffer[i + 1] == 'M') {
|
||||
buffer[i] = '0' + m / 10;
|
||||
buffer[i + 1] = '0' + m % 10;
|
||||
}
|
||||
if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' &&
|
||||
buffer[i + 3] == 'Y') {
|
||||
buffer[i] = '2';
|
||||
buffer[i + 1] = '0';
|
||||
buffer[i + 2] = '0' + (yOff / 10) % 10;
|
||||
buffer[i + 3] = '0' + yOff % 10;
|
||||
} else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') {
|
||||
buffer[i] = '0' + (yOff / 10) % 10;
|
||||
buffer[i + 1] = '0' + yOff % 10;
|
||||
}
|
||||
if (buffer[i] == 'A' && buffer[i + 1] == 'P') {
|
||||
if (isPM) {
|
||||
buffer[i] = 'P';
|
||||
buffer[i + 1] = 'M';
|
||||
} else {
|
||||
buffer[i] = 'A';
|
||||
buffer[i + 1] = 'M';
|
||||
}
|
||||
} else if (buffer[i] == 'a' && buffer[i + 1] == 'p') {
|
||||
if (isPM) {
|
||||
buffer[i] = 'p';
|
||||
buffer[i + 1] = 'm';
|
||||
} else {
|
||||
buffer[i] = 'a';
|
||||
buffer[i + 1] = 'm';
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return the hour in 12-hour format.
|
||||
@return Hour (1--12).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t DateTime::twelveHour() const {
|
||||
if (hh == 0 || hh == 12) { // midnight or noon
|
||||
return 12;
|
||||
} else if (hh > 12) { // 1 o'clock or later
|
||||
return hh - 12;
|
||||
} else { // morning
|
||||
return hh;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return the day of the week.
|
||||
@return Day of week as an integer from 0 (Sunday) to 6 (Saturday).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t DateTime::dayOfTheWeek() const {
|
||||
uint16_t day = date2days(yOff, m, d);
|
||||
return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return Unix time: seconds since 1 Jan 1970.
|
||||
|
||||
@see The `DateTime::DateTime(uint32_t)` constructor is the converse of
|
||||
this method.
|
||||
|
||||
@return Number of seconds since 1970-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t DateTime::unixtime(void) const {
|
||||
uint32_t t;
|
||||
uint16_t days = date2days(yOff, m, d);
|
||||
t = time2ulong(days, hh, mm, ss);
|
||||
t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Convert the DateTime to seconds since 1 Jan 2000
|
||||
|
||||
The result can be converted back to a DateTime with:
|
||||
|
||||
```cpp
|
||||
DateTime(SECONDS_FROM_1970_TO_2000 + value)
|
||||
```
|
||||
|
||||
@return Number of seconds since 2000-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t DateTime::secondstime(void) const {
|
||||
uint32_t t;
|
||||
uint16_t days = date2days(yOff, m, d);
|
||||
t = time2ulong(days, hh, mm, ss);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Add a TimeSpan to the DateTime object
|
||||
@param span TimeSpan object
|
||||
@return New DateTime object with span added to it.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime DateTime::operator+(const TimeSpan &span) const {
|
||||
return DateTime(unixtime() + span.totalseconds());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract a TimeSpan from the DateTime object
|
||||
@param span TimeSpan object
|
||||
@return New DateTime object with span subtracted from it.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime DateTime::operator-(const TimeSpan &span) const {
|
||||
return DateTime(unixtime() - span.totalseconds());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract one DateTime from another
|
||||
|
||||
@note Since a TimeSpan cannot be negative, the subtracted DateTime
|
||||
should be less (earlier) than or equal to the one it is
|
||||
subtracted from.
|
||||
|
||||
@param right The DateTime object to subtract from self (the left object)
|
||||
@return TimeSpan of the difference between DateTimes.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan DateTime::operator-(const DateTime &right) const {
|
||||
return TimeSpan(unixtime() - right.unixtime());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@author Anton Rieutskyi
|
||||
@brief Test if one DateTime is less (earlier) than another.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right Comparison DateTime object
|
||||
@return True if the left DateTime is earlier than the right one,
|
||||
false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::operator<(const DateTime &right) const {
|
||||
return (yOff + 2000U < right.year() ||
|
||||
(yOff + 2000U == right.year() &&
|
||||
(m < right.month() ||
|
||||
(m == right.month() &&
|
||||
(d < right.day() ||
|
||||
(d == right.day() &&
|
||||
(hh < right.hour() ||
|
||||
(hh == right.hour() &&
|
||||
(mm < right.minute() ||
|
||||
(mm == right.minute() && ss < right.second()))))))))));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@author Anton Rieutskyi
|
||||
@brief Test if two DateTime objects are equal.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right Comparison DateTime object
|
||||
@return True if both DateTime objects are the same, false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::operator==(const DateTime &right) const {
|
||||
return (right.year() == yOff + 2000U && right.month() == m &&
|
||||
right.day() == d && right.hour() == hh && right.minute() == mm &&
|
||||
right.second() == ss);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return a ISO 8601 timestamp as a `String` object.
|
||||
|
||||
The generated timestamp conforms to one of the predefined, ISO
|
||||
8601-compatible formats for representing the date (if _opt_ is
|
||||
`TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both
|
||||
(`TIMESTAMP_FULL`).
|
||||
|
||||
@see The `toString()` method provides more general string formatting.
|
||||
|
||||
@param opt Format of the timestamp
|
||||
@return Timestamp string, e.g. "2020-04-16T18:34:56".
|
||||
*/
|
||||
/**************************************************************************/
|
||||
String DateTime::timestamp(timestampOpt opt) const {
|
||||
char buffer[25]; // large enough for any DateTime, including invalid ones
|
||||
|
||||
// Generate timestamp according to opt
|
||||
switch (opt) {
|
||||
case TIMESTAMP_TIME:
|
||||
// Only time
|
||||
sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss);
|
||||
break;
|
||||
case TIMESTAMP_DATE:
|
||||
// Only date
|
||||
sprintf(buffer, "%u-%02d-%02d", 2000U + yOff, m, d);
|
||||
break;
|
||||
default:
|
||||
// Full
|
||||
sprintf(buffer, "%u-%02d-%02dT%02d:%02d:%02d", 2000U + yOff, m, d, hh, mm,
|
||||
ss);
|
||||
}
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Create a new TimeSpan object in seconds
|
||||
@param seconds Number of seconds
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Create a new TimeSpan object using a number of
|
||||
days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes:
|
||||
new TimeSpan(0, 3, 45, 0);
|
||||
@param days Number of days
|
||||
@param hours Number of hours
|
||||
@param minutes Number of minutes
|
||||
@param seconds Number of seconds
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds)
|
||||
: _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 +
|
||||
(int32_t)minutes * 60 + seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Copy constructor, make a new TimeSpan using an existing one
|
||||
@param copy The TimeSpan to copy
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(const TimeSpan ©) : _seconds(copy._seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Add two TimeSpans
|
||||
@param right TimeSpan to add
|
||||
@return New TimeSpan object, sum of left and right
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan TimeSpan::operator+(const TimeSpan &right) const {
|
||||
return TimeSpan(_seconds + right._seconds);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract a TimeSpan
|
||||
@param right TimeSpan to subtract
|
||||
@return New TimeSpan object, right subtracted from left
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan TimeSpan::operator-(const TimeSpan &right) const {
|
||||
return TimeSpan(_seconds - right._seconds);
|
||||
}
|
||||
519
libraries/RTClib/src/RTClib.h
Normal file
519
libraries/RTClib/src/RTClib.h
Normal file
@@ -0,0 +1,519 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file RTClib.h
|
||||
|
||||
Original library by JeeLabs http://news.jeelabs.org/code/, released to the
|
||||
public domain
|
||||
|
||||
License: MIT (see LICENSE)
|
||||
|
||||
This is a fork of JeeLab's fantastic real time clock library for Arduino.
|
||||
|
||||
For details on using this library with an RTC module like the DS1307, PCF8523,
|
||||
or DS3231, see the guide at:
|
||||
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _RTCLIB_H_
|
||||
#define _RTCLIB_H_
|
||||
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
class TimeSpan;
|
||||
|
||||
/** Constants */
|
||||
#define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24
|
||||
#define SECONDS_FROM_1970_TO_2000 \
|
||||
946684800 ///< Unixtime for 2000-01-01 00:00:00, useful for initialization
|
||||
|
||||
/** DS1307 SQW pin mode settings */
|
||||
enum Ds1307SqwPinMode {
|
||||
DS1307_OFF = 0x00, // Low
|
||||
DS1307_ON = 0x80, // High
|
||||
DS1307_SquareWave1HZ = 0x10, // 1Hz square wave
|
||||
DS1307_SquareWave4kHz = 0x11, // 4kHz square wave
|
||||
DS1307_SquareWave8kHz = 0x12, // 8kHz square wave
|
||||
DS1307_SquareWave32kHz = 0x13 // 32kHz square wave
|
||||
};
|
||||
|
||||
/** DS3231 SQW pin mode settings */
|
||||
enum Ds3231SqwPinMode {
|
||||
DS3231_OFF = 0x1C, /**< Off */
|
||||
DS3231_SquareWave1Hz = 0x00, /**< 1Hz square wave */
|
||||
DS3231_SquareWave1kHz = 0x08, /**< 1kHz square wave */
|
||||
DS3231_SquareWave4kHz = 0x10, /**< 4kHz square wave */
|
||||
DS3231_SquareWave8kHz = 0x18 /**< 8kHz square wave */
|
||||
};
|
||||
|
||||
/** DS3231 Alarm modes for alarm 1 */
|
||||
enum Ds3231Alarm1Mode {
|
||||
DS3231_A1_PerSecond = 0x0F, /**< Alarm once per second */
|
||||
DS3231_A1_Second = 0x0E, /**< Alarm when seconds match */
|
||||
DS3231_A1_Minute = 0x0C, /**< Alarm when minutes and seconds match */
|
||||
DS3231_A1_Hour = 0x08, /**< Alarm when hours, minutes
|
||||
and seconds match */
|
||||
DS3231_A1_Date = 0x00, /**< Alarm when date (day of month), hours,
|
||||
minutes and seconds match */
|
||||
DS3231_A1_Day = 0x10 /**< Alarm when day (day of week), hours,
|
||||
minutes and seconds match */
|
||||
};
|
||||
/** DS3231 Alarm modes for alarm 2 */
|
||||
enum Ds3231Alarm2Mode {
|
||||
DS3231_A2_PerMinute = 0x7, /**< Alarm once per minute
|
||||
(whenever seconds are 0) */
|
||||
DS3231_A2_Minute = 0x6, /**< Alarm when minutes match */
|
||||
DS3231_A2_Hour = 0x4, /**< Alarm when hours and minutes match */
|
||||
DS3231_A2_Date = 0x0, /**< Alarm when date (day of month), hours
|
||||
and minutes match */
|
||||
DS3231_A2_Day = 0x8 /**< Alarm when day (day of week), hours
|
||||
and minutes match */
|
||||
};
|
||||
/** PCF8523 INT/SQW pin mode settings */
|
||||
enum Pcf8523SqwPinMode {
|
||||
PCF8523_OFF = 7, /**< Off */
|
||||
PCF8523_SquareWave1HZ = 6, /**< 1Hz square wave */
|
||||
PCF8523_SquareWave32HZ = 5, /**< 32Hz square wave */
|
||||
PCF8523_SquareWave1kHz = 4, /**< 1kHz square wave */
|
||||
PCF8523_SquareWave4kHz = 3, /**< 4kHz square wave */
|
||||
PCF8523_SquareWave8kHz = 2, /**< 8kHz square wave */
|
||||
PCF8523_SquareWave16kHz = 1, /**< 16kHz square wave */
|
||||
PCF8523_SquareWave32kHz = 0 /**< 32kHz square wave */
|
||||
};
|
||||
|
||||
/** PCF8523 Timer Source Clock Frequencies for Timers A and B */
|
||||
enum PCF8523TimerClockFreq {
|
||||
PCF8523_Frequency4kHz = 0, /**< 1/4096th second = 244 microseconds,
|
||||
max 62.256 milliseconds */
|
||||
PCF8523_Frequency64Hz = 1, /**< 1/64th second = 15.625 milliseconds,
|
||||
max 3.984375 seconds */
|
||||
PCF8523_FrequencySecond = 2, /**< 1 second, max 255 seconds = 4.25 minutes */
|
||||
PCF8523_FrequencyMinute = 3, /**< 1 minute, max 255 minutes = 4.25 hours */
|
||||
PCF8523_FrequencyHour = 4, /**< 1 hour, max 255 hours = 10.625 days */
|
||||
};
|
||||
|
||||
/** PCF8523 Timer Interrupt Low Pulse Width options for Timer B only */
|
||||
enum PCF8523TimerIntPulse {
|
||||
PCF8523_LowPulse3x64Hz = 0, /**< 46.875 ms 3/64ths second */
|
||||
PCF8523_LowPulse4x64Hz = 1, /**< 62.500 ms 4/64ths second */
|
||||
PCF8523_LowPulse5x64Hz = 2, /**< 78.125 ms 5/64ths second */
|
||||
PCF8523_LowPulse6x64Hz = 3, /**< 93.750 ms 6/64ths second */
|
||||
PCF8523_LowPulse8x64Hz = 4, /**< 125.000 ms 8/64ths second */
|
||||
PCF8523_LowPulse10x64Hz = 5, /**< 156.250 ms 10/64ths second */
|
||||
PCF8523_LowPulse12x64Hz = 6, /**< 187.500 ms 12/64ths second */
|
||||
PCF8523_LowPulse14x64Hz = 7 /**< 218.750 ms 14/64ths second */
|
||||
};
|
||||
|
||||
/** PCF8523 Offset modes for making temperature/aging/accuracy adjustments */
|
||||
enum Pcf8523OffsetMode {
|
||||
PCF8523_TwoHours = 0x00, /**< Offset made every two hours */
|
||||
PCF8523_OneMinute = 0x80 /**< Offset made every minute */
|
||||
};
|
||||
|
||||
/** PCF8563 CLKOUT pin mode settings */
|
||||
enum Pcf8563SqwPinMode {
|
||||
PCF8563_SquareWaveOFF = 0x00, /**< Off */
|
||||
PCF8563_SquareWave1Hz = 0x83, /**< 1Hz square wave */
|
||||
PCF8563_SquareWave32Hz = 0x82, /**< 32Hz square wave */
|
||||
PCF8563_SquareWave1kHz = 0x81, /**< 1kHz square wave */
|
||||
PCF8563_SquareWave32kHz = 0x80 /**< 32kHz square wave */
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Simple general-purpose date/time class (no TZ / DST / leap
|
||||
seconds).
|
||||
|
||||
This class stores date and time information in a broken-down form, as a
|
||||
tuple (year, month, day, hour, minute, second). The day of the week is
|
||||
not stored, but computed on request. The class has no notion of time
|
||||
zones, daylight saving time, or
|
||||
[leap seconds](http://en.wikipedia.org/wiki/Leap_second): time is stored
|
||||
in whatever time zone the user chooses to use.
|
||||
|
||||
The class supports dates in the range from 1 Jan 2000 to 31 Dec 2099
|
||||
inclusive.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class DateTime {
|
||||
public:
|
||||
DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000);
|
||||
DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0,
|
||||
uint8_t min = 0, uint8_t sec = 0);
|
||||
DateTime(const DateTime ©);
|
||||
DateTime(const char *date, const char *time);
|
||||
DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time);
|
||||
DateTime(const char *iso8601date);
|
||||
bool isValid() const;
|
||||
char *toString(char *buffer) const;
|
||||
|
||||
/*!
|
||||
@brief Return the year.
|
||||
@return Year (range: 2000--2099).
|
||||
*/
|
||||
uint16_t year() const { return 2000U + yOff; }
|
||||
/*!
|
||||
@brief Return the month.
|
||||
@return Month number (1--12).
|
||||
*/
|
||||
uint8_t month() const { return m; }
|
||||
/*!
|
||||
@brief Return the day of the month.
|
||||
@return Day of the month (1--31).
|
||||
*/
|
||||
uint8_t day() const { return d; }
|
||||
/*!
|
||||
@brief Return the hour
|
||||
@return Hour (0--23).
|
||||
*/
|
||||
uint8_t hour() const { return hh; }
|
||||
|
||||
uint8_t twelveHour() const;
|
||||
/*!
|
||||
@brief Return whether the time is PM.
|
||||
@return 0 if the time is AM, 1 if it's PM.
|
||||
*/
|
||||
uint8_t isPM() const { return hh >= 12; }
|
||||
/*!
|
||||
@brief Return the minute.
|
||||
@return Minute (0--59).
|
||||
*/
|
||||
uint8_t minute() const { return mm; }
|
||||
/*!
|
||||
@brief Return the second.
|
||||
@return Second (0--59).
|
||||
*/
|
||||
uint8_t second() const { return ss; }
|
||||
|
||||
uint8_t dayOfTheWeek() const;
|
||||
|
||||
/* 32-bit times as seconds since 2000-01-01. */
|
||||
uint32_t secondstime() const;
|
||||
|
||||
/* 32-bit times as seconds since 1970-01-01. */
|
||||
uint32_t unixtime(void) const;
|
||||
|
||||
/*!
|
||||
Format of the ISO 8601 timestamp generated by `timestamp()`. Each
|
||||
option corresponds to a `toString()` format as follows:
|
||||
*/
|
||||
enum timestampOpt {
|
||||
TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss`
|
||||
TIMESTAMP_TIME, //!< `hh:mm:ss`
|
||||
TIMESTAMP_DATE //!< `YYYY-MM-DD`
|
||||
};
|
||||
String timestamp(timestampOpt opt = TIMESTAMP_FULL) const;
|
||||
|
||||
DateTime operator+(const TimeSpan &span) const;
|
||||
DateTime operator-(const TimeSpan &span) const;
|
||||
TimeSpan operator-(const DateTime &right) const;
|
||||
bool operator<(const DateTime &right) const;
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is greater (later) than another.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is later than the right one,
|
||||
false otherwise
|
||||
*/
|
||||
bool operator>(const DateTime &right) const { return right < *this; }
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is less (earlier) than or equal to another
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is earlier than or equal to the
|
||||
right one, false otherwise
|
||||
*/
|
||||
bool operator<=(const DateTime &right) const { return !(*this > right); }
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is greater (later) than or equal to another
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is later than or equal to the right
|
||||
one, false otherwise
|
||||
*/
|
||||
bool operator>=(const DateTime &right) const { return !(*this < right); }
|
||||
bool operator==(const DateTime &right) const;
|
||||
|
||||
/*!
|
||||
@brief Test if two DateTime objects are not equal.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the two objects are not equal, false if they are
|
||||
*/
|
||||
bool operator!=(const DateTime &right) const { return !(*this == right); }
|
||||
|
||||
protected:
|
||||
uint8_t yOff; ///< Year offset from 2000
|
||||
uint8_t m; ///< Month 1-12
|
||||
uint8_t d; ///< Day 1-31
|
||||
uint8_t hh; ///< Hours 0-23
|
||||
uint8_t mm; ///< Minutes 0-59
|
||||
uint8_t ss; ///< Seconds 0-59
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Timespan which can represent changes in time with seconds accuracy.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class TimeSpan {
|
||||
public:
|
||||
TimeSpan(int32_t seconds = 0);
|
||||
TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
|
||||
TimeSpan(const TimeSpan ©);
|
||||
|
||||
/*!
|
||||
@brief Number of days in the TimeSpan
|
||||
e.g. 4
|
||||
@return int16_t days
|
||||
*/
|
||||
int16_t days() const { return _seconds / 86400L; }
|
||||
/*!
|
||||
@brief Number of hours in the TimeSpan
|
||||
This is not the total hours, it includes the days
|
||||
e.g. 4 days, 3 hours - NOT 99 hours
|
||||
@return int8_t hours
|
||||
*/
|
||||
int8_t hours() const { return _seconds / 3600 % 24; }
|
||||
/*!
|
||||
@brief Number of minutes in the TimeSpan
|
||||
This is not the total minutes, it includes days/hours
|
||||
e.g. 4 days, 3 hours, 27 minutes
|
||||
@return int8_t minutes
|
||||
*/
|
||||
int8_t minutes() const { return _seconds / 60 % 60; }
|
||||
/*!
|
||||
@brief Number of seconds in the TimeSpan
|
||||
This is not the total seconds, it includes the days/hours/minutes
|
||||
e.g. 4 days, 3 hours, 27 minutes, 7 seconds
|
||||
@return int8_t seconds
|
||||
*/
|
||||
int8_t seconds() const { return _seconds % 60; }
|
||||
/*!
|
||||
@brief Total number of seconds in the TimeSpan, e.g. 358027
|
||||
@return int32_t seconds
|
||||
*/
|
||||
int32_t totalseconds() const { return _seconds; }
|
||||
|
||||
TimeSpan operator+(const TimeSpan &right) const;
|
||||
TimeSpan operator-(const TimeSpan &right) const;
|
||||
|
||||
protected:
|
||||
int32_t _seconds; ///< Actual TimeSpan value is stored as seconds
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief A generic I2C RTC base class. DO NOT USE DIRECTLY
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_I2C {
|
||||
protected:
|
||||
/*!
|
||||
@brief Convert a binary coded decimal value to binary. RTC stores
|
||||
time/date values as BCD.
|
||||
@param val BCD value
|
||||
@return Binary value
|
||||
*/
|
||||
static uint8_t bcd2bin(uint8_t val) { return val - 6 * (val >> 4); }
|
||||
/*!
|
||||
@brief Convert a binary value to BCD format for the RTC registers
|
||||
@param val Binary value
|
||||
@return BCD value
|
||||
*/
|
||||
static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); }
|
||||
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
|
||||
uint8_t read_register(uint8_t reg);
|
||||
void write_register(uint8_t reg, uint8_t val);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the DS1307 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_DS1307 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
uint8_t isrunning(void);
|
||||
DateTime now();
|
||||
Ds1307SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Ds1307SqwPinMode mode);
|
||||
uint8_t readnvram(uint8_t address);
|
||||
void readnvram(uint8_t *buf, uint8_t size, uint8_t address);
|
||||
void writenvram(uint8_t address, uint8_t data);
|
||||
void writenvram(uint8_t address, const uint8_t *buf, uint8_t size);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the DS3231 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_DS3231 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
bool lostPower(void);
|
||||
DateTime now();
|
||||
Ds3231SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Ds3231SqwPinMode mode);
|
||||
bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode);
|
||||
bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode);
|
||||
DateTime getAlarm1();
|
||||
DateTime getAlarm2();
|
||||
Ds3231Alarm1Mode getAlarm1Mode();
|
||||
Ds3231Alarm2Mode getAlarm2Mode();
|
||||
void disableAlarm(uint8_t alarm_num);
|
||||
void clearAlarm(uint8_t alarm_num);
|
||||
bool alarmFired(uint8_t alarm_num);
|
||||
void enable32K(void);
|
||||
void disable32K(void);
|
||||
bool isEnabled32K(void);
|
||||
float getTemperature(); // in Celsius degree
|
||||
/*!
|
||||
@brief Convert the day of the week to a representation suitable for
|
||||
storing in the DS3231: from 1 (Monday) to 7 (Sunday).
|
||||
@param d Day of the week as represented by the library:
|
||||
from 0 (Sunday) to 6 (Saturday).
|
||||
@return the converted value
|
||||
*/
|
||||
static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; }
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the PCF8523 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_PCF8523 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
bool lostPower(void);
|
||||
bool initialized(void);
|
||||
DateTime now();
|
||||
void start(void);
|
||||
void stop(void);
|
||||
uint8_t isrunning();
|
||||
Pcf8523SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Pcf8523SqwPinMode mode);
|
||||
void enableSecondTimer(void);
|
||||
void disableSecondTimer(void);
|
||||
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods,
|
||||
uint8_t lowPulseWidth);
|
||||
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods);
|
||||
void disableCountdownTimer(void);
|
||||
void deconfigureAllTimers(void);
|
||||
void calibrate(Pcf8523OffsetMode mode, int8_t offset);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the PCF8563 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_PCF8563 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
bool lostPower(void);
|
||||
void adjust(const DateTime &dt);
|
||||
DateTime now();
|
||||
void start(void);
|
||||
void stop(void);
|
||||
uint8_t isrunning();
|
||||
Pcf8563SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Pcf8563SqwPinMode mode);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC using the internal millis() clock, has to be initialized before
|
||||
use. NOTE: this is immune to millis() rollover events.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_Millis {
|
||||
public:
|
||||
/*!
|
||||
@brief Start the RTC
|
||||
@param dt DateTime object with the date/time to set
|
||||
*/
|
||||
void begin(const DateTime &dt) { adjust(dt); }
|
||||
void adjust(const DateTime &dt);
|
||||
DateTime now();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Unix time from the previous call to now().
|
||||
|
||||
This, together with `lastMillis`, defines the alignment between
|
||||
the `millis()` timescale and the Unix timescale. Both variables
|
||||
are updated on each call to now(), which prevents rollover issues.
|
||||
*/
|
||||
uint32_t lastUnix;
|
||||
/*!
|
||||
`millis()` value corresponding `lastUnix`.
|
||||
|
||||
Note that this is **not** the `millis()` value of the last call to
|
||||
now(): it's the `millis()` value corresponding to the last **full
|
||||
second** of Unix time preceding the last call to now().
|
||||
*/
|
||||
uint32_t lastMillis;
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC using the internal micros() clock, has to be initialized before
|
||||
use. Unlike RTC_Millis, this can be tuned in order to compensate for
|
||||
the natural drift of the system clock. Note that now() has to be
|
||||
called more frequently than the micros() rollover period, which is
|
||||
approximately 71.6 minutes.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_Micros {
|
||||
public:
|
||||
/*!
|
||||
@brief Start the RTC
|
||||
@param dt DateTime object with the date/time to set
|
||||
*/
|
||||
void begin(const DateTime &dt) { adjust(dt); }
|
||||
void adjust(const DateTime &dt);
|
||||
void adjustDrift(int ppm);
|
||||
DateTime now();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Number of microseconds reported by `micros()` per "true"
|
||||
(calibrated) second.
|
||||
*/
|
||||
uint32_t microsPerSecond = 1000000;
|
||||
/*!
|
||||
Unix time from the previous call to now().
|
||||
|
||||
The timing logic is identical to RTC_Millis.
|
||||
*/
|
||||
uint32_t lastUnix;
|
||||
/*!
|
||||
`micros()` value corresponding to `lastUnix`.
|
||||
*/
|
||||
uint32_t lastMicros;
|
||||
};
|
||||
|
||||
#endif // _RTCLIB_H_
|
||||
Reference in New Issue
Block a user