DS3231.cpp

#incude <DS3231>


DS3231 Datsheet
Public Functions
date2days() time2long() DateTime unixtime()
isleapYear() now() getSecond() getMinute()
getHour() getDow() getDate() getMonth()
getYear() getA2Time() getTemperature() getA1Time()
getA2Time() setEpoch() setSecond() setMinute()
setHour() setDow() setDate() setMonth()
setYear() setClockMode() setA1Time() setA2Time()
turnOnAlarm() turnOffAlarm() checkAlarmEnabled() checkifAlarm()
checkIfAlarm() enableOscillator() enable32kHz() oscillatorCheck()
Private Functions
decToBcd() bcdToDec() readControlByte() writeControlByte()
Support LIbs
Wire


 /*H*******************************************************
DS3231.cpp: DS3231 Real-Time Clock library
Eric Ayars 4/1/11
Spliced in DateTime all-at-once reading (to avoid rollover) and unix time
from Jean-Claude Wippler and Limor Fried
Andy Wickert 5/15/11
Fixed problem with SD processors(no function call) by replacing all occurences
of term PM, which 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 setting of PM flag for 12:xx PM.  These address certain
 DS3231 errors in properly setting the AM/PM (bit 5) flag in 02h register when
passing from AM to PM and PM to AM.
David Merrifield 04/14/2020
Released into public domain.
********************************************************/
#include "DS3231.h"
// These included for DateTime class inclusion; will try to find a way to not 
// need them in future...
#if defined(__AVR__)
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#endif
// Changed following to work on 1.0
//#include "WProgram.h"
#include <Arduino.h>

//****************** DEFINES *****************************
#define CLOCK_ADDRESS 0x68
#define SECONDS_FROM_1970_TO_2000 946684800


/*F******************************************************************** * Constructor **********************************************************************/ DS3231::DS3231(): _Wire( Wire ) { // NOTHING TO DO FOR THIS CONSTRUCTOR } /*F******************************************************************** * **********************************************************************/ DS3231::DS3231( TwoWire & w ): _Wire( w ) { } /*H******************************************************************** * UTILITIES FROM JeeLabs/Ladyada SOME OF THIS COULD BE EXPOSED IN DateTime API IF NEEDED DS3231 IS SMART ENOUGH TO KNOW THIS, BUT KEEPING IT FOR NOW SO I DON'T HAVE TO REWRITE THEIR CODE. -ADW **********************************************************************/ static const uint8_t // NUMBER OF DAYS SINCE 2000/01/01, VALID FOR 2001..2099 daysInMonth[] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
/*F******************************************************************** * **********************************************************************/ 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 && isleapYear( y ) ) ++days; return( days + 365 * y + (y + 3) / 4 - 1 ); }
/*F******************************************************************** * **********************************************************************/ 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 *****************************************/ /******************************************************************************* * TO GET ALL DATE/TIME INFORMATION AT ONCE AND AVOID THE CHANCE OF ROLLOVER * DateTime implementation spliced in here from Jean-Claude Wippler's (JeeLabs) * RTClib, as modified by Limor Fried (Ladyada); source code at: * https://github.com/adafruit/RTClib ******************************************************************************/
/*F******************************************************************** * DateTime implementation - ignores time zones and DST changes NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second **********************************************************************/ 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 = isleapYear( yOff ); 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; } /*F******************************************************************** * **********************************************************************/ 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; } /*F******************************************************************** * supported formats are date "Mmm dd yyyy" and time "hh:mm:ss" (same as __DATE__ and __TIME__) **********************************************************************/ DateTime:: DateTime( const char *date, const char *time) { static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; static char buff[4] = { '0','0 ','0','0 '}; int y; sscanf( date, "%s %hhu %d", buff, &d, &y); yOff = y >= 2000 ? y - 2000 : y; m = (strstr(month_names, buff) - month_names) / 3 + 1; sscanf( time, "%hhu:%hhu:%hhu", &hh, &mm, &ss); }
/*F******************************************************************** * UNIX time: IS CORRECT ONLY WHEN SET TO UTC!!! **********************************************************************/ const uint32_t DateTime:: unixtime( void ) { 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 ); }
/*F******************************************************************** * Slightly modified from JeeLabs / Ladyada Get all date/time at once to avoid rollover (e.g., minute/second don't match) **********************************************************************/ static uint8_t bcd2bin( uint8_t val) { return( val - 6 * (val >> 4) ); }
/*F******************************************************************** * Commented to avoid compiler warnings, but keeping in case we want this eventually **********************************************************************/ static uint8_t bin2bcd( uint8_t val ) { return( val + 6 * (val / 10) ); }
/*F******************************************************************** * **********************************************************************/ bool isleapYear( const uint8_t y ) { if( y & 3) // CHECK IF DIVISIBLE BY 4 return( false ); return( y % 100 || y % 400 == 0 );// ONLY CHECK OTHER, WHEN FIRST FAILED }
/*F******************************************************************** * **********************************************************************/ DateTime RTClib:: now( TwoWire & _Wire ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0 ); // THIS IS FIRST REGISTER ADDRESS (SECONDS) // READ 7 BYTES FROM HERE: SECS REG, MINS REG, HRS, DAYS, MONS AND YRS _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 7); uint16_t ss = bcd2bin(_Wire.read() & 0x7F); uint16_t mm = bcd2bin(_Wire.read()); uint16_t hh = bcd2bin(_Wire.read()); _Wire.read(); 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 ) ); }
/*F******************************************************************** * ERIC'S ORIGINAL CODE FOLLOWS **********************************************************************/ byte DS3231:: getSecond() { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x00 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( bcdToDec( _Wire.read()) ); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getMinute() _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x01 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( bcdToDec(_Wire.read()) ); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getHour( bool &h12, bool &PM_time) { byte temp_buffer, hour; _Wire.beginTransmission( CLOCK_ADDRESS ); // SOME KIND OF SYNC MECHANISM? _Wire.write( 0x02 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); temp_buffer = _Wire.read(); h12 = temp_buffer & 0b01000000; if( h12 ) { PM_time = temp_buffer & 0b00100000; hour = bcdToDec( temp_buffer & 0b00011111); } else hour = bcdToDec( temp_buffer &0b00111111); return( hour ); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getDoW() { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x03 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( bcdToDec( _Wire.read() ) ); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getDate() { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x04); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( bcdToDec( _Wire.read()) ); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getMonth( bool& Century) { byte temp_buffer; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x05); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); temp_buffer = _Wire.read(); Century = temp_buffer & 0b10000000; return( bcdToDec( temp_buffer & 0b01111111)); }
/*F******************************************************************** * **********************************************************************/ byte DS3231:: getYear() { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x06 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( bcdToDec( _Wire.read()) ); }
/*F******************************************************************** * setEpoch passes epoch as parameter and feeds RTC epoch = UnixTime and starts at 01.01.1970 00:00:00 **********************************************************************/ void DS3231:: setEpoch( time_t epoch, bool flag_localtime) { struct tm tmnow; if( flag_localtime ) localtime_r( &epoch, &tmnow); else gmtime_r( &epoch, &tmnow); setSecond( tmnow.tm_sec ); setMinute( tmnow. tm_min ); setHour( tmnow.tm_hour); setDoW( tmnow.tm_wday + 1); setDate( tmnow.tm_mday); setMonth( tmnow.tm_mon + 1); setYear( tmnow.tm_year - 100); }
/*F******************************************************************** * Sets seconds also resets Oscillator Stop Flag, which is set * whenever power is interrupted. **********************************************************************/ void DS3231:: setSecond( byte Second ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x00 ); _Wire.write( decToBcd( Second ) ); _Wire.endTransmission(); // Clear OSF flag byte temp_buffer = readControlByte( 1 ); writeControlByte( (temp_buffer & 0b01111111), 1); }
/*F******************************************************************** * Sets minutes **********************************************************************/ void DS3231:: setMinute( byte Minute ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x01 ); _Wire.write( decToBcd( Minute ) ); _Wire.endTransmission(); }
/*F******************************************************************** Sets hour, without changing 12/24h mode. hour must be in 24h format. * setHour revision by David Merrifield 4/14/2020 correcting handling of 12-hour clock **********************************************************************/ void DS3231:: setHour( byte Hour ) { bool h12, amPm; byte tmpHr; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x02 ); // SEND REGISTER # _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); // READ 1 BYTE FROM RTC h12 = (_Wire.read() & 0b01000000); // READ 12/*24 FLAG BIT if( h12 ) // IF H12 IS TRUE, IT'S 12H MODE; FALSE IS 24H { // 12 HOUR MODE amPm = (Hour > 11); tmpHr = Hour; if( tmpHr > 11) tmpHr = tmpHr - 12; if( tmpHr == 0) tmpHr = 12; // BUILD 12HR SetVal: INCL AM/PM BIT and 12/24 HR BIT tmpHr = decToBcd( tmpHr ) | ( amPm << 5) | 0b01000000; } else // 24 HOUR tmpHr = decToBcd( Hour ) & 0b10111111; // BUILD 24 HR SET VAL _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x02 ); _Wire.write( tmpHr); _Wire.endTransmission(); }
/*F******************************************************************** * Sets Day of Week **********************************************************************/ void DS3231:: setDoW( byte DoW ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x03); _Wire.write( decToBcd( DoW ) ); _Wire.endTransmission(); }
/*F******************************************************************** * Sets Date **********************************************************************/ void DS3231:: setDate( byte Date ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x04 ); _Wire.write( decToBcd( Date ) ); _Wire.endTransmission(); }
/*F******************************************************************** * Sets month **********************************************************************/ void DS3231:: setMonth( byte Month ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x05); _Wire.write( decToBcd( Month ) ); _Wire.endTransmission(); }
/*F******************************************************************** * Sets year **********************************************************************/ void DS3231:: setYear( byte Year ) { _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x06); _Wire.write( decToBcd( Year ) ); _Wire.endTransmission(); }
/*F******************************************************************** * **********************************************************************/ void DS3231:: setClockMode( bool h12 ) { // sets mode to 12-hour (true) or 24-hour (false). // One thing that bothers me about how I've written this is that // if read and right happen at right hourly millisecnd, // clock will be set back an hour. Not sure how to do it better, // though, and as long as one doesn't set mode frequently it's // a very minimal risk. // It's zero risk if you call this BEFORE setting hour, since // setHour() function doesn't change this mode. byte temp_buffer; // Start by reading byte 0x02. _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x02); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); temp_buffer = _Wire.read(); // Set flag to requested value: if( h12 ) temp_buffer = temp_buffer | 0b01000000; else temp_buffer = temp_buffer & 0b10111111; // Write byte _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x02); _Wire.write( temp_buffer); _Wire.endTransmission(); }
/*F******************************************************************** * Checks internal thermometer on DS3231 and returns temperature as a floating-point value. **********************************************************************/ float DS3231:: getTemperature() { // 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); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 2 ); // SHOULD I DO MORE "IF AVAILABLE" CHECKS HERE? if(_Wire.available() ) { tMSB = _Wire.read(); // 2'S COMPLEMENT INT PORTION tLSB = _Wire.read(); // FRACTION PORTION // SHIFT UPPER BYTE, ADD LOWER int16_t itemp = ( tMSB << 8 | (tLSB & 0xC0) ); temp3231 = ( (float)itemp / 256.0 ); // SCALE AND RETURN } else temp3231 = -9999; // IMPOSSIBLE TEMPERATURE; ERROR VALUE return( temp3231 ); }
/*F******************************************************************** * **********************************************************************/ void DS3231:: getA1Time( byte &A1Day, byte &A1Hour, byte &A1Minute , byte &A1Second, byte &AlarmBits, bool &A1Dy , bool& A1h12, bool &A1PM) { byte temp_buffer; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x07 ); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 4); temp_buffer = _Wire.read(); // GET A1M1 AND A1 SECONDS A1Second = bcdToDec( temp_buffer &0b01111111 ); // PUT A1M1 BIT IN POSITION 0 OF DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer &0b10000000)>> 7; temp_buffer = _Wire.read(); // Get A1M2 and A1 minutes A1Minute = bcdToDec( temp_buffer &0b01111111 ); // PUT A1M2 BIT IN POSITION 1 OF DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer &0b10000000) >> 6; temp_buffer = _Wire.read(); // Get A1M3 and A1 Hour // PUT A1M3 BIT IN POSITION 2 OF DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer &0b10000000) >> 5; // determine A1 12/24 mode A1h12 = temp_buffer &0b01000000; if( A1h12 ) { A1PM = temp_buffer &0b00100000; // DETERMINE AM/PM A1Hour = bcdToDec( temp_buffer &0b00011111); // 12-HOUR } else A1Hour = bcdToDec( temp_buffer &0b00111111); // 24-HOUR temp_buffer = _Wire.read(); // GET A1M4 AND A1 DAY/DATE // PUT A1M3 BIT IN POSITION 3 OF DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer &0b10000000) >> 4; // determine A1 day or date flag A1Dy = (temp_buffer &0b01000000) >> 6; if( A1Dy ) A1Day = bcdToDec( temp_buffer & 0b00001111); else // ALARM IS BY DATE, NOT DAY OF WEEK A1Day = bcdToDec( temp_buffer &0b00111111 ); }
/*F******************************************************************** * **********************************************************************/ void DS3231:: getA1Time( byte &A1Day, byte &A1Hour, byte &A1Minute , byte &A1Second, byte &AlarmBits, bool &A1Dy , bool &A1h12, bool &A1PM, bool clearAlarmBits ) { if( clearAlarmBits ) AlarmBits = 0x0; getA1Time( A1Day, A1Hour, A1Minute, A1Second, AlarmBits, A1Dy, A1h12 , A1PM); }
/*F******************************************************************** * **********************************************************************/ void DS3231:: getA2Time( byte &A2Day, byte &A2Hour, byte &A2Minute , byte &AlarmBits, bool &A2Dy, bool &A2h12, bool &A2PM ) { byte temp_buffer; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x0b); _Wire.endTransmission(); _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 AlarmBits = AlarmBits | (temp_buffer & 0b10000000) >> 3; temp_buffer = _Wire.read(); // Get A2M3 and A2 Hour // put A2M3 bit in position 5 of DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer & 0b10000000) >> 2; // determine A2 12/24 mode A2h12 = temp_buffer & 0b01000000; if( A2h12 ) { A2PM = temp_buffer & 0b00100000; // determine am/pm A2Hour = bcdToDec( temp_buffer & 0b00011111); // 12-hour } else A2Hour = bcdToDec( temp_buffer & 0b00111111); // 24-hour temp_buffer = _Wire.read(); // Get A2M4 and A1 Day/Date // put A2M4 bit in position 6 of DS3231_AlarmBits AlarmBits = AlarmBits | (temp_buffer & 0b10000000) >> 1; // determine A2 day or date flag A2Dy = ( temp_buffer & 0b01000000) >> 6; if( A2Dy ) { // alarm is by day of week, not date. A2Day = bcdToDec( temp_buffer & 0b00001111); } else // alarm is by date, not day of week { A2Day = bcdToDec( temp_buffer & 0b00111111); } }
/*F******************************************************************** * **********************************************************************/ void DS3231:: getA2Time( byte &A2Day, byte &A2Hour, byte &A2Minute , byte &AlarmBits, bool &A2Dy, bool &A2h12, bool &A2PM , bool clearAlarmBits) { if( clearAlarmBits) AlarmBits = 0x0; getA2Time( A2Day, A2Hour, A2Minute, AlarmBits, A2Dy, A2h12, A2PM); }
/*F******************************************************************** * Sets alarm-1 date and time on DS3231, using A1* information **********************************************************************/ void DS3231:: setA1Time( byte A1Day, byte A1Hour, byte A1Minute, byte A1Second , byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM ) { byte temp_buffer; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x07); // A1 starts at 07h // Send A1 second and A1M1 _Wire.write( decToBcd(A1Second) | ((AlarmBits & 0b00000001) << 7)); // Send A1 Minute and A1M2 _Wire.write( decToBcd(A1Minute) | ((AlarmBits & 0b00000010) << 6)); // Figure out A1 hour if( A1h12 ) { // Start by converting existing time to h12 if it was given in 24h if( A1Hour > 12 ) { // well, then, this obviously isn't a h12 time, is it? A1Hour = A1Hour - 12; A1PM = true; } if( A1PM ) { // Afternoon // Convert hour to BCD and add appropriate flags. temp_buffer = decToBcd( A1Hour) | 0b01100000; } else // Morning { // Convert hour to BCD and add appropriate flags temp_buffer = decToBcd(A1Hour) | 0b01000000; } } else // Now for 24h temp_buffer = decToBcd(A1Hour); temp_buffer = temp_buffer | ((AlarmBits & 0b00000100) << 5); // A1 hour is figured out, send it _Wire.write( temp_buffer ); // Figure out A1 day/date and A1M4 temp_buffer = (( AlarmBits & 0b00001000) << 4) | decToBcd(A1Day); if( A1Dy ) { // Set A1 Day/Date flag (Otherwise it's zero) temp_buffer = temp_buffer | 0b01000000; } _Wire.write( temp_buffer); _Wire.endTransmission(); // All done }
/*F******************************************************************** * **********************************************************************/ void DS3231:: setA2Time( byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits , bool A2Dy, bool A2h12, bool A2PM) { // Sets alarm-2 date and time on DS3231, using A2* information byte temp_buffer; _Wire.beginTransmission( CLOCK_ADDRESS ); _Wire.write( 0x0b ); // A1 starts at 0bh // Send A2 Minute and A2M2 _Wire.write( decToBcd(A2Minute) | ((AlarmBits & 0b00010000) << 3)); if( A2h12 ) // Figure out A2 hour { // Start by converting existing time to h12 if it was given in 24h if( A2Hour > 12 ) { // well, then, this obviously isn't a h12 time, is it? A2Hour = A2Hour - 12; A2PM = true; } if( A2PM ) // Afternoon { // Convert hour to BCD and add appropriate flags temp_buffer = decToBcd(A2Hour) | 0b01100000; } else // Morning { // Convert hour to BCD and add appropriate flags temp_buffer = decToBcd(A2Hour) | 0b01000000; } } else { // Now for 24h 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 ); // Figure out A2 day/date and A2M4 temp_buffer = ((AlarmBits & 0b01000000) << 1) | decToBcd(A2Day); if( A2Dy ) { // Set A2 Day/Date flag (Otherwise it's zero) temp_buffer = temp_buffer | 0b01000000; } _Wire.write( temp_buffer ); _Wire.endTransmission(); // All done }
/*F******************************************************************** * turns on alarm number "Alarm". Defaults to 2 if Alarm is not 1. **********************************************************************/ void DS3231:: turnOnAlarm( byte Alarm) { byte temp_buffer = readControlByte( 0 ); if( Alarm == 1) temp_buffer = temp_buffer | 0b00000101; // modify control byte else temp_buffer = temp_buffer | 0b00000110; writeControlByte( temp_buffer, 0); }
/*F******************************************************************** * turns off alarm number "Alarm". Defaults to 2 if Alarm is not 1. Leaves interrupt pin alone. **********************************************************************/ void DS3231:: turnOffAlarm( byte Alarm ) { byte temp_buffer = readControlByte( 0 ); // modify control byte if( Alarm == 1) temp_buffer = temp_buffer & 0b11111110; else temp_buffer = temp_buffer & 0b11111101; writeControlByte( temp_buffer, 0); }
/*F******************************************************************** * Checks whether given alarm is enabled. **********************************************************************/ bool DS3231:: checkAlarmEnabled( byte Alarm) { byte result = 0x0; byte temp_buffer = readControlByte( 0 ); if( Alarm == 1 ) result = temp_buffer & 0b00000001; else result = temp_buffer & 0b00000010; return( result ); }
/*F******************************************************************** * Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly. **********************************************************************/ bool DS3231:: checkIfAlarm( byte Alarm ) { // Turns flag off, also. // defaults to checking alarm 2, unless Alarm == 1. byte result; byte temp_buffer = readControlByte( 1 ); if( Alarm == 1 ) { result = temp_buffer & 0b00000001; // Did alarm 1 go off temp_buffer = temp_buffer & 0b11111110; // clear flag } else { // Did alarm 2 go off? result = temp_buffer & 0b00000010; temp_buffer = temp_buffer & 0b11111101; // clear flag } writeControlByte( temp_buffer, 1); return( result ); }
/*F******************************************************************** * Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly **********************************************************************/ bool DS3231:: checkIfAlarm( byte Alarm, bool clearflag) { // 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; temp_buffer = temp_buffer & 0b11111110; // clear flag } else { // Did alarm 2 go off? result = temp_buffer & 0b00000010; temp_buffer = temp_buffer & 0b11111101; // clear flag } if( clearflag ) writeControlByte( temp_buffer, 1); return( result ); }
/*F******************************************************************** * 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. frequency must be 0, 1, 2, or 3. 0 = 1 Hz 1 = 1.024 kHz 2 = 4.096 kHz 3 = 8.192 kHz (Default if frequency byte is out of range) **********************************************************************/ void DS3231:: enableOscillator( bool TF, bool battery, byte frequency) { if( frequency > 3 ) frequency = 3; // READ CONTROL BYTE IN, BUT ZERO OUT CURRENT STATE OF RS2 AND RS1 byte temp_buffer = readControlByte( 0 ) & 0b11100111; if( battery ) temp_buffer = temp_buffer | 0b01000000; // TURN ON BBSQW FLAG else temp_buffer = temp_buffer & 0b10111111; // TURN OFF BBSQW FLAG if( TF ) temp_buffer = temp_buffer & 0b01111011; // SET ~EOSC & INTCN =0 else temp_buffer = temp_buffer | 0b10000000; // SET ~EOSC = 1, IGNORE INTCN frequency = frequency << 3; // SHFT FREQ TO BITS 3 AND 4 AND SEt temp_buffer = temp_buffer | frequency; writeControlByte( temp_buffer, 0 ); // AND WRITE CONTROL BITS }
/*F******************************************************************** * turn 32kHz pin on or off **********************************************************************/ void DS3231:: enable32kHz( bool TF) { byte temp_buffer = readControlByte( 1 ); if( TF ) { temp_buffer = temp_buffer | 0b00001000; // turn on 32kHz pin } else temp_buffer = temp_buffer & 0b11110111; // turn off 32kHz pin writeControlByte( temp_buffer, 1); }
/*F******************************************************************** * Returns false if oscillator has been off for some reason. If this is case, time is probably not correct. **********************************************************************/ bool DS3231:: oscillatorCheck() { byte temp_buffer = readControlByte( 1 ); bool result = true; if( temp_buffer & 0b10000000) { // Oscillator Stop Flag (OSF) is set, so return false result = false; } return( result ); }
/*H******************************************************************** * Private Functions **********************************************************************/
/*F******************************************************************** * Convert normal decimal numbers to binary coded decimal **********************************************************************/ byte DS3231:: decToBcd( byte val ) { return( ( (val/10 * 16) + (val%10) ); }
/*F******************************************************************** * Convert binary coded decimal to normal decimal numbers **********************************************************************/ byte DS3231:: bcdToDec(byte val) { return( (val/16 * 10) + (val%16) ); }
/*F******************************************************************** * Read selected control byte first byte (0) is 0x0e, second (1) is 0x0f **********************************************************************/ byte DS3231:: readControlByte( bool which) { _Wire.beginTransmission( CLOCK_ADDRESS ); if( which ) _Wire.write( 0x0f ); // second control byte else // first control byte _Wire.write( 0x0e); _Wire.endTransmission(); _Wire.requestFrom( CLOCK_ADDRESS, 1); return( _Wire.read() ); }
/*F******************************************************************** * Write selected control byte, which= false -> 0x0e, true->0x0f. **********************************************************************/ void DS3231:: writeControlByte( byte control, bool which) { _Wire.beginTransmission( CLOCK_ADDRESS ); if( which ) _Wire.write( 0x0f ); else _Wire.write( 0x0e ); _Wire.write( control ); _Wire.endTransmission(); }