diff --git a/DS3231.cpp b/DS3231.cpp index ea89586..b5c2bba 100644 --- a/DS3231.cpp +++ b/DS3231.cpp @@ -9,12 +9,12 @@ Andy Wickert 5/15/11 Fixed problem with SD processors(no function call) by replacing all occurences of the term PM, which -is defined as a macro on SAMD controllers by PM_time. +is defined as a macro on SAMD controllers by PM_time. Simon Gassner 11/28/2017 -Fixed setting 12-hour clock in setHour function so that 12:xx AM is not stored as 00:xx and corrected -the setting of the PM flag for 12:xx PM. These address certain DS3231 errors in properly setting the +Fixed setting 12-hour clock in setHour function so that 12:xx AM is not stored as 00:xx and corrected +the setting of the PM flag for 12:xx PM. These address certain DS3231 errors in properly setting the AM/PM (bit 5) flag in the 02h register when passing from AM to PM and PM to AM. David Merrifield 04/14/2020 @@ -74,7 +74,7 @@ static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { return ((days * 24L + h) * 60 + m) * 60 + s; } -/***************************************** +/***************************************** Public Functions *****************************************/ @@ -167,7 +167,7 @@ DateTime RTClib::now(TwoWire & _Wire) { _Wire.write(0); // This is the first register address (Seconds) // We'll read from here on for 7 bytes: secs reg, minutes reg, hours, days, months and years. _Wire.endTransmission(); - + _Wire.requestFrom(CLOCK_ADDRESS, 7); uint16_t ss = bcd2bin(_Wire.read() & 0x7F); uint16_t mm = bcd2bin(_Wire.read()); @@ -176,7 +176,7 @@ DateTime RTClib::now(TwoWire & _Wire) { uint16_t d = bcd2bin(_Wire.read()); uint16_t m = bcd2bin(_Wire.read()); uint16_t y = bcd2bin(_Wire.read()) + 2000; - + return DateTime (y, m, d, hh, mm, ss); } @@ -278,12 +278,12 @@ void DS3231::setEpoch(time_t epoch, bool flag_localtime) { } void DS3231::setSecond(byte Second) { - // Sets the seconds + // Sets the seconds // This function also resets the Oscillator Stop Flag, which is set // whenever power is interrupted. _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x00); - _Wire.write(decToBcd(Second)); + _Wire.write(decToBcd(Second)); _Wire.endTransmission(); // Clear OSF flag byte temp_buffer = readControlByte(1); @@ -291,10 +291,10 @@ void DS3231::setSecond(byte Second) { } void DS3231::setMinute(byte Minute) { - // Sets the minutes + // Sets the minutes _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x01); - _Wire.write(decToBcd(Minute)); + _Wire.write(decToBcd(Minute)); _Wire.endTransmission(); } @@ -341,7 +341,7 @@ void DS3231::setDoW(byte DoW) { // Sets the Day of Week _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x03); - _Wire.write(decToBcd(DoW)); + _Wire.write(decToBcd(DoW)); _Wire.endTransmission(); } @@ -349,7 +349,7 @@ void DS3231::setDate(byte Date) { // Sets the Date _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x04); - _Wire.write(decToBcd(Date)); + _Wire.write(decToBcd(Date)); _Wire.endTransmission(); } @@ -357,7 +357,7 @@ void DS3231::setMonth(byte Month) { // Sets the month _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x05); - _Wire.write(decToBcd(Month)); + _Wire.write(decToBcd(Month)); _Wire.endTransmission(); } @@ -365,7 +365,7 @@ void DS3231::setYear(byte Year) { // Sets the year _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x06); - _Wire.write(decToBcd(Year)); + _Wire.write(decToBcd(Year)); _Wire.endTransmission(); } @@ -373,12 +373,12 @@ void DS3231::setClockMode(bool h12) { // sets the mode to 12-hour (true) or 24-hour (false). // One thing that bothers me about how I've written this is that // if the read and right happen at the right hourly millisecnd, - // the clock will be set back an hour. Not sure how to do it better, + // the clock will be set back an hour. Not sure how to do it better, // though, and as long as one doesn't set the mode frequently it's - // a very minimal risk. + // a very minimal risk. // It's zero risk if you call this BEFORE setting the hour, since // the setHour() function doesn't change this mode. - + byte temp_buffer; // Start by reading byte 0x02. @@ -403,15 +403,15 @@ void DS3231::setClockMode(bool h12) { } float DS3231::getTemperature() { - // Checks the internal thermometer on the DS3231 and returns the + // Checks the internal thermometer on the DS3231 and returns the // temperature as a floating-point value. // Updated / modified a tiny bit from "Coding Badly" and "Tri-Again" // http://forum.arduino.cc/index.php/topic,22301.0.html - + byte tMSB, tLSB; float temp3231; - + // temp registers (11h-12h) get updated automatically every 64s _Wire.beginTransmission(CLOCK_ADDRESS); _Wire.write(0x11); @@ -429,7 +429,7 @@ float DS3231::getTemperature() { else { temp3231 = -9999; // Impossible temperature; error value } - + return temp3231; } @@ -483,7 +483,7 @@ void DS3231::getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBit _Wire.write(0x0b); _Wire.endTransmission(); - _Wire.requestFrom(CLOCK_ADDRESS, 3); + _Wire.requestFrom(CLOCK_ADDRESS, 3); temp_buffer = _Wire.read(); // Get A2M2 and A2 Minutes A2Minute = bcdToDec(temp_buffer & 0b01111111); // put A2M2 bit in position 4 of DS3231_AlarmBits. @@ -524,7 +524,7 @@ void DS3231::setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, by _Wire.write(decToBcd(A1Second) | ((AlarmBits & 0b00000001) << 7)); // Send A1 Minute and A1M2 _Wire.write(decToBcd(A1Minute) | ((AlarmBits & 0b00000010) << 6)); - // Figure out A1 hour + // Figure out A1 hour if (A1h12) { // Start by converting existing time to h12 if it was given in 24h. if (A1Hour > 12) { @@ -543,11 +543,11 @@ void DS3231::setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, by } } else { // Now for 24h - temp_buffer = decToBcd(A1Hour); + temp_buffer = decToBcd(A1Hour); } temp_buffer = temp_buffer | ((AlarmBits & 0b00000100)<<5); // A1 hour is figured out, send it - _Wire.write(temp_buffer); + _Wire.write(temp_buffer); // Figure out A1 day/date and A1M4 temp_buffer = ((AlarmBits & 0b00001000)<<4) | decToBcd(A1Day); if (A1Dy) { @@ -566,7 +566,7 @@ void DS3231::setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, b _Wire.write(0x0b); // A1 starts at 0bh // Send A2 Minute and A2M2 _Wire.write(decToBcd(A2Minute) | ((AlarmBits & 0b00010000) << 3)); - // Figure out A2 hour + // Figure out A2 hour if (A2h12) { // Start by converting existing time to h12 if it was given in 24h. if (A2Hour > 12) { @@ -585,12 +585,12 @@ void DS3231::setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, b } } else { // Now for 24h - temp_buffer = decToBcd(A2Hour); + temp_buffer = decToBcd(A2Hour); } // add in A2M3 bit temp_buffer = temp_buffer | ((AlarmBits & 0b00100000)<<2); // A2 hour is figured out, send it - _Wire.write(temp_buffer); + _Wire.write(temp_buffer); // Figure out A2 day/date and A2M4 temp_buffer = ((AlarmBits & 0b01000000)<<1) | decToBcd(A2Day); if (A2Dy) { @@ -660,6 +660,29 @@ bool DS3231::checkIfAlarm(byte Alarm) { return result; } +bool DS3231::checkIfAlarm(byte Alarm, bool clearflag) { + // Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly. + // Clears flag, if clearflag is set + // defaults to checking alarm 2, unless Alarm == 1. + byte result; + byte temp_buffer = readControlByte(1); + if (Alarm == 1) { + // Did alarm 1 go off? + result = temp_buffer & 0b00000001; + // clear flag + temp_buffer = temp_buffer & 0b11111110; + } else { + // Did alarm 2 go off? + result = temp_buffer & 0b00000010; + // clear flag + temp_buffer = temp_buffer & 0b11111101; + } + if (clearflag) { + writeControlByte(temp_buffer, 1); + } + return result; +} + void DS3231::enableOscillator(bool TF, bool battery, byte frequency) { // turns oscillator on or off. True is on, false is off. // if battery is true, turns on even for battery-only operation, @@ -718,7 +741,7 @@ bool DS3231::oscillatorCheck() { return result; } -/***************************************** +/***************************************** Private Functions *****************************************/ @@ -745,7 +768,7 @@ byte DS3231::readControlByte(bool which) { } _Wire.endTransmission(); _Wire.requestFrom(CLOCK_ADDRESS, 1); - return _Wire.read(); + return _Wire.read(); } void DS3231::writeControlByte(byte control, bool which) { @@ -760,4 +783,3 @@ void DS3231::writeControlByte(byte control, bool which) { _Wire.write(control); _Wire.endTransmission(); } - diff --git a/DS3231.h b/DS3231.h index e65af0c..d32ec5a 100644 --- a/DS3231.h +++ b/DS3231.h @@ -61,7 +61,7 @@ class RTClib { // Eric's original code is everything below this line class DS3231 { public: - + //Constructor DS3231(); DS3231(TwoWire & w); @@ -69,55 +69,55 @@ class DS3231 { TwoWire & _Wire; // Time-retrieval functions - + // the get*() functions retrieve current values of the registers. - byte getSecond(); - byte getMinute(); - byte getHour(bool& h12, bool& PM_time); + byte getSecond(); + byte getMinute(); + byte getHour(bool& h12, bool& PM_time); // In addition to returning the hour register, this function // returns the values of the 12/24-hour flag and the AM/PM flag. - byte getDoW(); - byte getDate(); - byte getMonth(bool& Century); + byte getDoW(); + byte getDate(); + byte getMonth(bool& Century); // Also sets the flag indicating century roll-over. - byte getYear(); + byte getYear(); // Last 2 digits only // Time-setting functions // Note that none of these check for sensibility: You can set the // date to July 42nd and strange things will probably result. - + // set epoch function gives the epoch as parameter and feeds the RTC // epoch = UnixTime and starts at 01.01.1970 00:00:00 void setEpoch(time_t epoch = 0, bool flag_localtime = false); - void setSecond(byte Second); - // In addition to setting the seconds, this clears the + void setSecond(byte Second); + // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". - void setMinute(byte Minute); + void setMinute(byte Minute); // Sets the minute - void setHour(byte Hour); + void setHour(byte Hour); // Sets the hour - void setDoW(byte DoW); + void setDoW(byte DoW); // Sets the Day of the Week (1-7); - void setDate(byte Date); + void setDate(byte Date); // Sets the Date of the Month - void setMonth(byte Month); + void setMonth(byte Month); // Sets the Month of the year - void setYear(byte Year); + void setYear(byte Year); // Last two digits of the year - void setClockMode(bool h12); + void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function - float getTemperature(); + float getTemperature(); // Alarm functions - - void getA1Time(byte& A1Day, byte& A1Hour, byte& A1Minute, byte& A1Second, byte& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM); + + void getA1Time(byte& A1Day, byte& A1Hour, byte& A1Minute, byte& A1Second, byte& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM); /* Retrieves everything you could want to know about alarm - * one. + * one. * A1Dy true makes the alarm go on A1Day = Day of Week, * A1Dy false makes the alarm go on A1Day = Date of month. * @@ -137,28 +137,31 @@ class DS3231 { * 0 0 0 0 Alarm when date, hour, min match * 1 0 0 0 Alarm when DoW, hour, min match */ - void getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM); + void getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM); // Same as getA1Time();, but A2 only goes on seconds == 00. - void setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM); + void setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM); // Set the details for Alarm 1 - void setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM); + void setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM); // Set the details for Alarm 2 - void turnOnAlarm(byte Alarm); + void turnOnAlarm(byte Alarm); // Enables alarm 1 or 2 and the external interrupt pin. // If Alarm != 1, it assumes Alarm == 2. - void turnOffAlarm(byte Alarm); + void turnOffAlarm(byte Alarm); // Disables alarm 1 or 2 (default is 2 if Alarm != 1); // and leaves the interrupt pin alone. - bool checkAlarmEnabled(byte Alarm); + bool checkAlarmEnabled(byte Alarm); // Returns T/F to indicate whether the requested alarm is // enabled. Defaults to 2 if Alarm != 1. - bool checkIfAlarm(byte Alarm); + bool checkIfAlarm(byte Alarm); + // Checks whether the indicated alarm (1 or 2, 2 default); + // has been activated. Always clears flag. + bool checkIfAlarm(byte Alarm, bool clearflag); // Checks whether the indicated alarm (1 or 2, 2 default); - // has been activated. + // has been activated. IF clearflag is set, clears alarm flag. // Oscillator functions - void enableOscillator(bool TF, bool battery, byte frequency); + void enableOscillator(bool TF, bool battery, byte frequency); // turns oscillator on or off. True is on, false is off. // if battery is true, turns on even for battery-only operation, // otherwise turns off if Vcc is off. @@ -167,7 +170,7 @@ class DS3231 { // 1 = 1.024 kHz // 2 = 4.096 kHz // 3 = 8.192 kHz (Default if frequency byte is out of range); - void enable32kHz(bool TF); + void enable32kHz(bool TF); // Turns the 32kHz output pin on (true); or off (false). bool oscillatorCheck();; // Checks the status of the OSF (Oscillator Stop Flag);. @@ -177,17 +180,17 @@ class DS3231 { private: - byte decToBcd(byte val); + byte decToBcd(byte val); // Convert normal decimal numbers to binary coded decimal - byte bcdToDec(byte val); + byte bcdToDec(byte val); // Convert binary coded decimal to normal decimal numbers protected: - byte readControlByte(bool which); + byte readControlByte(bool which); // Read selected control byte: (0); reads 0x0e, (1) reads 0x0f - void writeControlByte(byte control, bool which); - // Write the selected control byte. + void writeControlByte(byte control, bool which); + // Write the selected control byte. // which == false -> 0x0e, true->0x0f. }; diff --git a/examples/AlarmPolling/AlarmPolling.ino b/examples/AlarmPolling/AlarmPolling.ino new file mode 100644 index 0000000..6153f76 --- /dev/null +++ b/examples/AlarmPolling/AlarmPolling.ino @@ -0,0 +1,50 @@ +/* +AlarmPolilng.ino +Jacob Nuernberg +08/22 + +Example on using DS3231 alarms with polling and test checkIfAlarm() + +Tested on: +- Arduino nano + +*/ + +#include +#include + +// Setup clock +DS3231 myRTC; + + +void setup() { + // Begin I2C communication + Wire.begin(); + + // Setup alarm one to fire every second + myRTC.turnOffAlarm(1); + myRTC.setA1Time(0, 0, 0, 0, 0b01111111, false, false, false); + myRTC.turnOnAlarm(1); + myRTC.checkIfAlarm(1); + + // Use builtin LED to blink + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); +} + +void loop() { + // static variable to keep track of LED on/off state + static byte state = false; + + // if alarm went of, do alarm stuff + // first call to checkIFAlarm does not clear alarm flag + if (myRTC.checkIfAlarm(1, false)) { + state = ~state; + digitalWrite(LED_BUILTIN, state); + // Clear alarm state + myRTC.checkIfAlarm(1, true); + } + + // Loop delay to emulate other running code + delay(10); +}