RTCLib.cpp was all that I changed from the community library and as explained above just the getTime() methods - included below:
//
#include "RTCLib.h"
#define bcd2bin(n) ( ((n) >> 4) * 10 + ((n) & 0x0F) ) //Macro to convert from BCD to binary format
#define bin2bcd(n) ( (((n) / 10) << 4) + ((n) % 10) ) //Macro to convert from binary to BCD format
//read/return register reg value
static uint8_t read_i2c_register(uint8_t addr, uint8_t reg)
{
Wire.beginTransmission(addr);
Wire.write((byte)reg);
Wire.endTransmission();
Wire.requestFrom(addr, (byte)1);
return Wire.read();
}
//write register reg value val
static void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val)
{
Wire.beginTransmission(addr);
Wire.write((byte)reg);
Wire.write((byte)val);
Wire.endTransmission();
}
//Days in Month lookup
const uint8_t daysInMonth [] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
// number of days since 1/1/2000, valid for 2001..2099
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d)
{
if (y >= 2000) y -= 2000;
uint16_t days = d;
for (uint8_t i = 1; i < m; ++i) days += daysInMonth[i - 1];
if (m > 2 && y % 4 == 0) ++days;
return days + 365 * y + (y + 3) / 4 - 1;
}
//return seconds for days and h:m:s
static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s)
{
return ((days * 24L + h) * 60 + m) * 60 + s;
}
// DateTime implementation - ignores time zones, DST changes and leap seconds
// Input unixtime t populates the DateTime object
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 < 365 + leap) break;
days -= 365 + leap;
}
for (m = 1; ; ++m)
{
uint8_t daysPerMonth = daysInMonth[m - 1];
if (leap && m == 2) ++daysPerMonth;
if (days < daysPerMonth) break;
days -= daysPerMonth;
}
d = days + 1;
}
// Input yyyy, m, d, dow, h, m, s populates DateTime object
DateTime::DateTime (uint16_t year, uint8_t month, uint8_t date, uint8_t hour, uint8_t min, uint8_t sec)
{
if (year >= 2000)
year -= 2000;
yOff = year;
m = month;
d = date;
hh = hour;
mm = min;
ss = sec;
}
//return t unixtime for object DateTime
uint32_t DateTime::unixtime(void) const
{
uint32_t t;
uint16_t days = date2days(yOff, m, d);
t = time2long(days, hh, mm, ss);
t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
return t;
}
//return t seconds since 1/1/2000 00:00:00
long DateTime::secondstime(void) const
{
long t;
uint16_t days = date2days(yOff, m, d);
t = time2long(days, hh, mm, ss);
return t;
}
boolean DS3231::begin(void)
{
Wire.begin();
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= 0x7F; // reset OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
return true;
}
//returns true if Oscillator Stop Flag (OSF) is set meaning the power has been lost
bool DS3231::lostPower(void)
{
return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7);
}
//set the RTC time yyyy, m, d, h, m, s
void DS3231::setTime(uint16_t year, uint8_t month, uint8_t date, uint8_t hour, uint8_t minute, uint8_t second)
{
if (year>=2000) year-=2000; //00-99
write_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC, bin2bcd(second));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN, bin2bcd(minute));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR, bin2bcd(hour));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW, 0);
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE, bin2bcd(date));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MON, bin2bcd(month));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR, bin2bcd(year));
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= 0x7F; // reset OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}
//set the RTC time yyyy, m, d, h, m, s
void DS3231::setTime(uint32_t t)
{
uint32_t ut = t;
t -= SECONDS_FROM_1970_TO_2000;
uint8_t second = t % 60;
t /= 60;
uint8_t minute = t % 60;
t /= 60;
uint8_t hour = t % 24;
uint16_t days = t / 24;
uint8_t leap;
uint8_t date;
uint8_t yOff, year;
uint8_t month, m;
for (yOff = 0; ; ++yOff)
{
leap = (yOff % 4 == 0);
if (days < 365 + leap) break;
days -= 365 + leap;
}
year = yOff;
for (m = 1; ; ++m)
{
uint8_t daysPerMonth = daysInMonth[m - 1];
if (leap && m == 2) ++daysPerMonth;
if (days < daysPerMonth) break;
days -= daysPerMonth;
}
month = m;
date = days + 1;
int dow;
uint8_t mArr[12] = {6,2,2,5,0,3,5,1,4,6,2,4};
dow = (year+2000) % 100;
dow = dow*5/4;
dow += date;
dow += mArr[month-1];
if ((((year+2000) % 4)==0) && (month<3)) dow -= 1;
while (dow>7) dow -= 7;
//Serial.printlnf("setTime %lu yyyy: %i mm: %i dd: %i dow: %i hh: %i mm: %i ss: %i",ut,year+2000,month,date,dow,hour,minute,second);
write_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC, bin2bcd(second));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN, bin2bcd(minute));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR, bin2bcd(hour));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW, dow);
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE, bin2bcd(date));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MON, bin2bcd(month));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR, bin2bcd(year));
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= 0x7F; // reset OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}
//
void DS3231::getTime(uint16_t *y, uint8_t *m, uint8_t *d, uint8_t *hh, uint8_t *mm, uint8_t *ss)
{
uint8_t temp;
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC);
*ss = bcd2bin(temp & 0x7F);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN);
*mm = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR);
*hh = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW);
uint8_t dow = temp & 0x07;
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE);
*d = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_MON);
*m = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR);
*y = (uint16_t) bcd2bin(temp) + 2000;
//Serial.printlnf("getTime bcdy: %0X yyyy: %d mm: %i dd: %i dow: %i hh: %i mm: %i ss: %i",temp,*y,*m,*d,dow,*hh,*mm,*ss);
}
//
DateTime DS3231::getTime()
{
uint8_t temp;
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC);
uint8_t ss = bcd2bin(temp & 0x7F);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN);
uint8_t mm = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR);
uint8_t hh = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW);
uint8_t dow = temp & 0x07;
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE);
uint8_t d = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_MON);
uint8_t m = bcd2bin(temp);
temp = read_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR);
uint16_t y = bcd2bin(temp) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
//return float temperature measurement in C
float DS3231::getTemp()
{
uint8_t _msb = read_i2c_register(DS3231_ADDRESS, DS3231_REG_TEMPM);
uint8_t _lsb = read_i2c_register(DS3231_ADDRESS, DS3231_REG_TEMPL);
return (float)_msb + ((_lsb >> 6) * 0.25f);
}
//
void DS3231::setAlarm(uint8_t num, uint8_t date, uint8_t hour, uint8_t min, uint8_t sec)
{
uint8_t temp;
if (num > 2) return; //out of range, num = 0 will clear the alarm 1 & 2 enabled bits
temp = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
num > 0 ? temp &= ~(1<<(num-1)): temp &= ~3; //clear alarm enable bit to disable
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, temp);
uint8_t stat = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
num > 0 ? stat &= ~(1<<(num-1)): stat &= ~3; //clear alarm flag bit to disable
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, stat); //reset alarm flag
if (num == 1)
{
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A1SEC, bin2bcd(sec));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A1MIN, bin2bcd(min));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A1HR, bin2bcd(hour));
if (date == 0) //set A1M4 bit to alarm on match of hour, min and sec
{
temp = 0x80;
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A1DAT, temp);
}
else //set A1M4 bit to alarm on match of date, hour, min and sec
{
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A1DAT, bin2bcd(date));
}
temp = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
temp |= 0x01; //set bit 0
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, temp); //set alarm 1 enabled
//uint8_t stat = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
//stat &= ~1;
//write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, stat); //reset alarm flag
}
else if (num == 2)
{
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A2MIN, bin2bcd(min));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A2HR, bin2bcd(hour));
if (date == 0) //set A2M4 bit to alarm on match of hour, min and sec=0
{
temp = 0x80;
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A2DAT, temp);
}
else //set A2M4 bit to alarm on match of date, hour, min and sec=0
{
write_i2c_register(DS3231_ADDRESS, DS3231_REG_A2DAT, bin2bcd(date));
}
temp = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
temp |= 0x02; //set bit 1
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, temp); //set alarm 2 enabled
//uint8_t stat = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
//stat &= ~2;
//write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, stat); //reset alarm flag
}
}
//returns true if alarm num [1-2] has alarmed (and clears the alarm flag) and false if not or not set
bool DS3231::alarmed(uint8_t num)
{
bool result = false;
if (num == 1 || num == 2)
{
uint8_t stat = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
uint8_t temp = stat;
uint8_t cont = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
cont &= 1<<(num-1);
if (cont > 0) //alarm enabled
{
temp &= 1<<(num-1); //mask off all but alarm flags
if (temp > 0) //alarm flagged
{
result = true;
stat &= ~(1<<(num-1));
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, stat); //reset alarm flag
}
}
}
return result;
}
//switch on the interrupt output to the /INT \SQW pin (active low)
void DS3231::setOutput(bool _set)
{
uint8_t _reg = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL); //read interrupt control register
_reg &= ~0x04; //clear bit 2 INTCN / turn off
_reg &= ~0x18; //set freq bits to 0
if (_set) _reg |= 0x04; //if set requested then set bit 2 INTCN / turn on
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, _reg); //write interrupt control register
}
//
DateTime DateTime::operator+(const TimeSpan& span) {
return DateTime(unixtime()+span.totalseconds());
}
DateTime DateTime::operator-(const TimeSpan& span) {
return DateTime(unixtime()-span.totalseconds());
}
TimeSpan DateTime::operator-(const DateTime& right) {
return TimeSpan(unixtime()-right.unixtime());
}
// TimeSpan implementation
TimeSpan::TimeSpan (int32_t seconds):
_seconds(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)
{}
//
TimeSpan::TimeSpan (const TimeSpan& copy):
_seconds(copy._seconds)
{}
//
TimeSpan TimeSpan::operator+(const TimeSpan& right) {
return TimeSpan(_seconds+right._seconds);
}
//
TimeSpan TimeSpan::operator-(const TimeSpan& right) {
return TimeSpan(_seconds-right._seconds);
}
//
void DS3231::adjust(const DateTime& dt)
{
write_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC, bin2bcd(dt.second()));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN, bin2bcd(dt.minute()));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR, bin2bcd(dt.hour()));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW, 0);
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE, bin2bcd(dt.day()));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MON, bin2bcd(dt.month()));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR, bin2bcd(dt.year() - 2000));
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= 0x7F; // reset OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}
//set the RTC time using unixtime
void DS3231::adjust(uint32_t t)
{
uint32_t ut = t;
t -= SECONDS_FROM_1970_TO_2000;
uint8_t second = t % 60;
t /= 60;
uint8_t minute = t % 60;
t /= 60;
uint8_t hour = t % 24;
uint16_t days = t / 24;
uint8_t leap;
uint8_t date;
uint8_t yOff, year;
uint8_t month, m;
for (yOff = 0; ; ++yOff)
{
leap = (yOff % 4 == 0);
if (days < 365 + leap) break;
days -= 365 + leap;
}
year = yOff;
for (m = 1; ; ++m)
{
uint8_t daysPerMonth = daysInMonth[m - 1];
if (leap && m == 2) ++daysPerMonth;
if (days < daysPerMonth) break;
days -= daysPerMonth;
}
month = m;
date = days + 1;
int dow;
uint8_t mArr[12] = {6,2,2,5,0,3,5,1,4,6,2,4};
dow = (year+2000) % 100;
dow = dow*5/4;
dow += date;
dow += mArr[month-1];
if ((((year+2000) % 4)==0) && (month<3)) dow -= 1;
while (dow>7) dow -= 7;
write_i2c_register(DS3231_ADDRESS, DS3231_REG_SEC, bin2bcd(second));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MIN, bin2bcd(minute));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_HOUR, bin2bcd(hour));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DOW, dow);
write_i2c_register(DS3231_ADDRESS, DS3231_REG_DATE, bin2bcd(date));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_MON, bin2bcd(month));
write_i2c_register(DS3231_ADDRESS, DS3231_REG_YEAR, bin2bcd(year));
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= 0x7F; // reset OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}