Many improvements made. Next update will have data logging to memory card.
// PowerJack Inverter Generator control.
// monitors voltage and current of DC side to detect when inverter is providing no current to the battery bank.
// When the low voltage trigger level has been reached if the generator is not in off time set by start and end hours
// the relay will be triggered for the duration there is current travelling into the batteries. Once the target volatage
// has been reached.
// Uses a ADS1115 to get a differential reading of current across CT or shunt, allowing for current travelling in either
// direction. Uses analog input pin and a external voltage divider to get voltage values. 120k to 10k divider gives ratio
// of 13 and a range of 0-65v. Uses a DS3231 rtc for time keeping.
// PINS
// A0 - Voltage divider
// SDA - To ADS1115 ADC and DS3231 RTC
// SCL - To ADS1115 ADC and DS3231 RTC
// 7 - Relay to operate generator.
// 5 - Relay On indicator.
// Incorporates the DS3231 code due to changes.
// Outputs DATE,TIME,ADC RAW VALUE,ADC AVERAGE VALUE,VOLTAGE,AMPS,WATTS,OFFTIME,RELAY STATE on serial line.
#include <EEPROM.h>
#include <Wire.h> // wire library for comms to ds3231 and ads1115
#include <Adafruit_ADS1015.h>
#include <SoftwareSerial.h>
#include <ResponsiveAnalogRead.h>
#ifndef _RTCLIB_H_
#define _RTCLIB_H_
#include <Arduino.h>
class TimeSpan;
///DS3231 BEGIN
#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))
#define Wire Wire1
#endif
#if (ARDUINO >= 100)
#include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems
// Macro to deal with the difference in I2C write functions from old and new Arduino versions.
#define _I2C_WRITE write
#define _I2C_READ read
#else
#include <WProgram.h>
#define _I2C_WRITE send
#define _I2C_READ receive
#endif
#define DS3231_ADDRESS 0x68
#define DS3231_CONTROL 0x0E
#define DS3231_STATUSREG 0x0F
#define SECONDS_PER_DAY 86400L
#define SECONDS_FROM_1970_TO_2000 946684800
// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
public:
DateTime (uint32_t t = 0);
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& copy);
DateTime (const char* date, const char* time);
DateTime (const __FlashStringHelper* date, const __FlashStringHelper* time);
uint16_t year() const {
return 2000 + yOff;
}
uint8_t month() const {
return m;
}
uint8_t day() const {
return d;
}
uint8_t hour() const {
return hh;
}
uint8_t minute() const {
return mm;
}
uint8_t second() const {
return ss;
}
uint8_t dayOfTheWeek() const;
// 32-bit times as seconds since 1/1/2000
long secondstime() const;
// 32-bit times as seconds since 1/1/1970
uint32_t unixtime(void) const;
DateTime operator+(const TimeSpan& span);
DateTime operator-(const TimeSpan& span);
TimeSpan operator-(const DateTime& right);
protected:
uint8_t yOff, m, d, hh, mm, ss;
};
// 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& copy);
int16_t days() const {
return _seconds / 86400L;
}
int8_t hours() const {
return _seconds / 3600 % 24;
}
int8_t minutes() const {
return _seconds / 60 % 60;
}
int8_t seconds() const {
return _seconds % 60;
}
int32_t totalseconds() const {
return _seconds;
}
TimeSpan operator+(const TimeSpan& right);
TimeSpan operator-(const TimeSpan& right);
protected:
int32_t _seconds;
};
// RTC based on the DS3231 chip connected via I2C and the Wire library
enum Ds3231SqwPinMode { DS3231_OFF = 0x01, DS3231_SquareWave1Hz = 0x00, DS3231_SquareWave1kHz = 0x08, DS3231_SquareWave4kHz = 0x10, DS3231_SquareWave8kHz = 0x18 };
class RTC_DS3231 {
public:
boolean begin(void);
static void adjust(const DateTime& dt);
bool lostPower(void);
static DateTime now();
static Ds3231SqwPinMode readSqwPinMode();
static void writeSqwPinMode(Ds3231SqwPinMode mode);
};
// RTC using the internal millis() clock, has to be initialized before use
// NOTE: this clock won't be correct once the millis() timer rolls over (>49d?)
class RTC_Millis {
public:
static void begin(const DateTime& dt) {
adjust(dt);
}
static void adjust(const DateTime& dt);
static DateTime now();
protected:
static long offset;
};
#endif // _RTCLIB_H_
RTC_DS3231 rtc;
#define VOLTIN A0 // Voltage input pin
#define OUTPIN 7 // Output pin to control
#define INDPIN 5 // Output Indicator pin
#define INVINDPIN 4 // Inverse Output indicator pin
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
Adafruit_ADS1115 ads; // ADS1115 Connected to SDA / SCL
//////////////////////////////////////////////////////////
//EEPROM MEMORY MAP
int Eaddress1 = 0; //first run
int Eaddress2 = 1; //low voltage trigger
int Eaddress3 = 2; //target voltage trigger
int Eaddress4 = 3; // multiplier
int Eaddress5 = 4; // relay off time
int Eaddress6 = 5; // relay on time
int Eaddress7 = 6;
byte value;
/////////////////////////////////////////////////////////////////////////
//USER SETTINGS BEGIN
float targetvolt = 54; // When this target voltage is reached switch off relay only if current is 0
float lowvolt = 48; // Voltage to trigger on relay.
float multiplier = 5.75; // 2 - convert reading to 75mv / 300amp shunt. 1 is 100mv/100amp - 1.33 is 75mv/100amp
float offset = 1.025 ; // correction factor for analog voltage input.
int starthouroff = 23; // relay not on after 11 pm
int stophouroff = 6 ; // relay not on before 6 am
//USER SETTINGS END
//////////////////////////////////////////////////////////////////////////////
int lowvoltset ;
int targetvoltset;
int starthouroffset;
int stophouroffset;
//prescaler bits
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
float amps;
int16_t adcresult;
float voltage;
float ampsaverage;
int sensorValue;
bool offtime = false ;
bool overrideoff = false;
const int numReadings = 100;
int16_t readings[numReadings];
int readIndex = 0;
int16_t total = 0;
int16_t average = 0;
ResponsiveAnalogRead analog(VOLTIN, true); // setup filtering
void setup(void)
{
ADCSRA &= ~PS_128; // remove bits set by Arduino library
ADCSRA |= PS_16; // set our own prescaler to 16 - 1mhz sampling
pinMode(OUTPIN, OUTPUT);
digitalWrite(OUTPIN, HIGH); //set to off on startup
ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
ads.begin();
rtc.begin();
Serial.begin(115200);
Serial.println("Press P for details, O for relay on, R for relay off, E for settings");
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
//get saved settings
if (EEPROM.read(Eaddress1) == 1) {
lowvolt = EEPROM.read(Eaddress2);
targetvolt = EEPROM.read(Eaddress3);
starthouroff = EEPROM.read(Eaddress5);
stophouroff = EEPROM.read(Eaddress6);
}
else
{
EEPROM.write(Eaddress1, 1) ;
EEPROM.write(Eaddress2, lowvolt) ;
EEPROM.write(Eaddress3, targetvolt);
EEPROM.write(Eaddress5, starthouroff);
EEPROM.write(Eaddress6, stophouroff);
}
}
void loop(void)
{
digitalWrite(INDPIN, digitalRead(OUTPIN));
digitalWrite(INVINDPIN, !digitalRead(OUTPIN));
DateTime now = rtc.now(); //get the current date and time
adcresult = ads.readADC_Differential_2_3();
total = total - readings[readIndex];
readings[readIndex] = adcresult;
total = total + readings[readIndex];
readIndex = readIndex + 1;
if (readIndex >= numReadings)
{
readIndex = 0;
}
average = total / numReadings;
amps = ((float)average * 256) / 32768; // 100mv / 100amp shunt
amps = amps * multiplier; // convert reading to other shunt.
analog.update();
voltage = analog.getValue() * (5.0 / 1023.0); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
voltage = voltage * 13 ; //multiply by 13 due to divider resistors input 0-65v 120k/10k-r1/r2
voltage = voltage * offset ;
if (now.hour() >= starthouroff || now.hour() < stophouroff )
{
offtime = true;
}
else
{
offtime = false;
}
if (offtime == true || overrideoff == true)
{
if (digitalRead(OUTPIN) != HIGH) {
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
if (offtime == true) {
Serial.println("Offtime - Relay OFF");
}
else
{
Serial.println("Override - Relay OFF");
}
}
digitalWrite(OUTPIN, HIGH); // if offtime or override is true then just switch off regardless.
}
else
{
if (voltage >= targetvolt && adcresult >= -40)
{
if (digitalRead(OUTPIN) != HIGH) {
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.println("Finished charging - Relay OFF");
}
digitalWrite(OUTPIN, HIGH); ///switch off relay because charger has stopped charging.
}
else
{
if (adcresult < -100) {
if (digitalRead(OUTPIN) != LOW)
{
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.println("Relay ON - Resumed");
}
digitalWrite(OUTPIN, LOW); //switch on relay because it's in the middle of charging, resume.
}
}
if (voltage <= lowvolt) {
if (digitalRead(OUTPIN) != LOW)
{
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.println("Low voltage triggered - Relay ON");
}
digitalWrite(OUTPIN, LOW); // low voltage trigger switch on relay if offtime is not true.
}
}
if (voltage <= lowvolt && digitalRead(OUTPIN) == LOW)
{
//generators yet to start, failed to start or breaker has tripped.
//maybe do something here.
}
if ( Serial.available() > 0)
{
char c = toupper(Serial.read());
if ( c == 'O' )
{ // override relay
digitalWrite(OUTPIN, LOW);
overrideoff = false;
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.println("Override - Relay ON");
}
else if ( c == 'P' )
{ // print details.
Serial.print(now.day(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.year(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.print(" raw adc: ");
Serial.print(adcresult);
Serial.print(" average adc: ");
Serial.print(average);
Serial.print(" / volt: ");
Serial.print(voltage);
Serial.print(" / amps: ");
Serial.print(amps);
Serial.print(" / watts: ");
Serial.print(voltage * amps);
if (offtime == true)
{
Serial.print(" / OFFTIME");
}
else
{
Serial.print(" / ONTIME");
}
if (digitalRead(OUTPIN) == LOW)
{
Serial.print(" / Relay On");
}
else
{
Serial.print(" / Relay Off");
}
if (overrideoff == true)
{
Serial.print(" / MAN OFF");
}
Serial.println();
}
else if ( c == 'E' )
{ // print settings.
Serial.print("low volt level: ");
Serial.print(lowvolt);
Serial.print(" target voltage: ");
Serial.print(targetvolt);
Serial.print(" start off hour: ");
Serial.print(starthouroff);
Serial.print(" stop off hour: ");
Serial.print(stophouroff);
Serial.print(" volt offset: ");
Serial.println(offset, 4);
Serial.println("L(INT) Sets low voltage trigger. T(INT) Sets target voltage trigger. X(INT) Sets start of off time HR. Y(INT) Sets end of off time HR.");
Serial.println("Examples. L48 sets low voltage trigger to 48v. Y5 sets generator can start after 05:00 AM. X19 sets generator can not start after 19:00 PM");
}
else if ( c == 'R' )
{
//digitalWrite(OUTPIN, HIGH);
overrideoff = true;
}
else if ( c == 'L' )
{
lowvoltset = Serial.parseInt();
if (lowvoltset <= 65 && lowvoltset > 0)
{
lowvolt = lowvoltset;
EEPROM.update(Eaddress2, lowvoltset) ;
Serial.println("Set lowvolt");
}
else
{
Serial.println("Incorrect input");
}
}
else if ( c == 'T' )
{
targetvoltset = Serial.parseInt();
if (targetvoltset <= 65 && targetvoltset > 0)
{
targetvolt = targetvoltset ;
EEPROM.update(Eaddress3, targetvoltset) ;
Serial.println("Set targetvolt");
}
else
{
Serial.println("Incorrect input");
}
}
else if ( c == 'X' )
{
starthouroffset = Serial.parseInt();
if (starthouroffset <= 24 && starthouroffset > 0)
{
starthouroff = starthouroffset;
EEPROM.update(Eaddress5, starthouroffset) ;
Serial.println("Set starthouroff");
}
else
{
Serial.println("Incorrect input");
}
}
else if ( c == 'Y' )
{
stophouroffset = Serial.parseInt();
if (stophouroffset <= 24 && stophouroffset > 0)
{
stophouroff = stophouroffset;
EEPROM.update(Eaddress6, stophouroffset) ;
Serial.println("Set stophouroff");
}
else
{
Serial.println("Incorrect input");
}
}
else
{
Serial.println("Syntax Error");
Serial.flush();
}
}
}
//float targetvolt = 54; // When this target voltage is reached switch off relay only if current is 0
//float lowvolt = 48; /
//int starthouroff = 23; // relay not on after 11 pm
//int stophouroff = 6 ; // relay not on before 6 am
//EEPROM.write(Eaddress1, 1) ;
////
//int Eaddress1 = 0; //first run
//int Eaddress2 = 1; //low voltage trigger
//int Eaddress3 = 2; //target voltage trigger
//int Eaddress4 = 3; // multiplier
//int Eaddress5 = 4; // relay off time
//int Eaddress6 = 5; // relay on time
//int Eaddress7 = 6;
//int lowvoltset ;
//int targetvoltset;
//int starthouroffset;
//int stophouroffset;
///////////////////////////////////////////////////////////////////////////////////////////////////////
//LOOP END
static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
Wire.beginTransmission(addr);
Wire._I2C_WRITE((byte)reg);
Wire.endTransmission();
Wire.requestFrom(addr, (byte)1);
return Wire._I2C_READ();
}
static void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
Wire.beginTransmission(addr);
Wire._I2C_WRITE((byte)reg);
Wire._I2C_WRITE((byte)val);
Wire.endTransmission();
}
////////////////////////////////////////////////////////////////////////////////
// utility code, some of this could be exposed in the DateTime API if needed
const uint8_t daysInMonth [] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// number of days since 2000/01/01, 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 += pgm_read_byte(daysInMonth + i - 1);
if (m > 2 && y % 4 == 0)
++days;
return days + 365 * y + (y + 3) / 4 - 1;
}
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 and DST changes
// NOTE: also ignores leap seconds
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 = pgm_read_byte(daysInMonth + m - 1);
if (leap && m == 2)
++daysPerMonth;
if (days < daysPerMonth)
break;
days -= daysPerMonth;
}
d = days + 1;
}
DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
if (year >= 2000)
year -= 2000;
yOff = year;
m = month;
d = day;
hh = hour;
mm = min;
ss = sec;
}
DateTime::DateTime (const DateTime & copy):
yOff(copy.yOff),
m(copy.m),
d(copy.d),
hh(copy.hh),
mm(copy.mm),
ss(copy.ss)
{}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
// A convenient constructor for using "the compiler's time":
// DateTime now (__DATE__, __TIME__);
// NOTE: using F() would further reduce the RAM footprint, see below.
DateTime::DateTime (const char* date, const char* time) {
// sample input: date = "Dec 26 2009", time = "12:34:56"
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 : m = 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);
}
// A convenient constructor for using "the compiler's time":
// This version will save RAM by using PROGMEM to store it by using the F macro.
// DateTime now (F(__DATE__), F(__TIME__));
DateTime::DateTime (const __FlashStringHelper * date, const __FlashStringHelper * time) {
// sample input: date = "Dec 26 2009", time = "12:34:56"
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 : m = 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);
}
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
}
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;
}
long DateTime::secondstime(void) const {
long t;
uint16_t days = date2days(yOff, m, d);
t = time2long(days, hh, mm, ss);
return t;
}
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);
}
static uint8_t bcd2bin (uint8_t val) {
return val - 6 * (val >> 4);
}
static uint8_t bin2bcd (uint8_t val) {
return val + 6 * (val / 10);
}
////////////////////////////////////////////////////////////////////////////////
// RTC_Millis implementation
long RTC_Millis::offset = 0;
void RTC_Millis::adjust(const DateTime & dt) {
offset = dt.unixtime() - millis() / 1000;
}
DateTime RTC_Millis::now() {
return (uint32_t)(offset + millis() / 1000);
}
////////////////////////////////////////////////////////////////////////////////
// RTC_DS3231 implementation
boolean RTC_DS3231::begin(void) {
Wire.begin();
return true;
}
bool RTC_DS3231::lostPower(void) {
return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7);
}
void RTC_DS3231::adjust(const DateTime & dt) {
Wire.beginTransmission(DS3231_ADDRESS);
Wire._I2C_WRITE((byte)0); // start at location 0
Wire._I2C_WRITE(bin2bcd(dt.second()));
Wire._I2C_WRITE(bin2bcd(dt.minute()));
Wire._I2C_WRITE(bin2bcd(dt.hour()));
Wire._I2C_WRITE(bin2bcd(0));
Wire._I2C_WRITE(bin2bcd(dt.day()));
Wire._I2C_WRITE(bin2bcd(dt.month()));
Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
Wire.endTransmission();
uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
statreg &= ~0x80; // flip OSF bit
write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}
DateTime RTC_DS3231::now() {
Wire.beginTransmission(DS3231_ADDRESS);
Wire._I2C_WRITE((byte)0);
Wire.endTransmission();
Wire.requestFrom(DS3231_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
uint8_t mm = bcd2bin(Wire._I2C_READ());
uint8_t hh = bcd2bin(Wire._I2C_READ() & 0b111111); // & 0b111111 Makes clock hours 24 hour format.
Wire._I2C_READ();
uint8_t d = bcd2bin(Wire._I2C_READ());
uint8_t m = bcd2bin(Wire._I2C_READ());
uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
int mode;
Wire.beginTransmission(DS3231_ADDRESS);
Wire._I2C_WRITE(DS3231_CONTROL);
Wire.endTransmission();
Wire.requestFrom((uint8_t)DS3231_ADDRESS, (uint8_t)1);
mode = Wire._I2C_READ();
mode &= 0x93;
return static_cast<Ds3231SqwPinMode>(mode);
}
void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
uint8_t ctrl;
ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
ctrl &= ~0x04; // turn off INTCON
ctrl &= ~0x18; // set freq bits to 0
if (mode == DS3231_OFF) {
ctrl |= 0x04; // turn on INTCN
} else {
ctrl |= mode;
}
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl);
//Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);debug
}