/*----------------------------------------------------------------------* * DS3232RTC.cpp - Arduino library for the Maxim Integrated DS3232 * * Real-Time Clock. This library is intended for use with the Arduino * * Time.h library, http://www.arduino.cc/playground/Code/Time * * * * This library is a drop-in replacement for the DS1307RTC.h library * * by Michael Margolis that is supplied with the Arduino Time library * * above. To change from using a DS1307 RTC to an DS3232 RTC, it is * * only necessary to change the #include statement to include this * * library instead of DS1307RTC.h. * * * * This library is *not* a drop-in replacement for the newer version * * of the DS1307RTC library at * * http://www.pjrc.com/teensy/td_libs_DS1307RTC.html * * * * In addition, this library implements functions to support the * * additional features of the DS3232. * * * * This library will also work with the DS3231 RTC, which has the same * * features of the DS3232 except: (1) Battery-backed SRAM, (2) Battery- * * backed 32kHz output (BB32kHz bit in Control/Status register 0x0F), * * and (3) Adjustable temperature sensor sample rate (CRATE1:0 bits in * * the Control/Status register). * * * * Whether used with the DS3232 or DS3231, the user is responsible for * * ensuring reads and writes do not exceed the device's address space * * (0x00-0x12 for DS3231, 0x00-0xFF for DS3232); no bounds checking * * is done by this library. * * * * Jack Christensen 06Mar2013 * * http://github.com/JChristensen/DS3232RTC * * * * CC BY-SA 4.0 * * "Arduino DS3232RTC Library" by Jack Christensen is licensed under * * CC BY-SA 4.0, http://creativecommons.org/licenses/by-sa/4.0/ * *----------------------------------------------------------------------*/ #include //define release-independent I2C functions #if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) #include #define i2cBegin TinyWireM.begin #define i2cBeginTransmission TinyWireM.beginTransmission #define i2cEndTransmission TinyWireM.endTransmission #define i2cRequestFrom TinyWireM.requestFrom #define i2cRead TinyWireM.receive #define i2cWrite TinyWireM.send #elif ARDUINO >= 100 #include #define i2cBegin Wire.begin #define i2cBeginTransmission Wire.beginTransmission #define i2cEndTransmission Wire.endTransmission #define i2cRequestFrom Wire.requestFrom #define i2cRead Wire.read #define i2cWrite Wire.write #else #include #define i2cBegin Wire.begin #define i2cBeginTransmission Wire.beginTransmission #define i2cEndTransmission Wire.endTransmission #define i2cRequestFrom Wire.requestFrom #define i2cRead Wire.receive #define i2cWrite Wire.send #endif /*----------------------------------------------------------------------* * Constructor. * *----------------------------------------------------------------------*/ DS3232RTC::DS3232RTC() { i2cBegin(); } /*----------------------------------------------------------------------* * Reads the current time from the RTC and returns it as a time_t * * value. Returns a zero value if an I2C error occurred (e.g. RTC * * not present). * *----------------------------------------------------------------------*/ time_t DS3232RTC::get() { tmElements_t tm; if ( read(tm) ) return 0; return( makeTime(tm) ); } /*----------------------------------------------------------------------* * Sets the RTC to the given time_t value and clears the * * oscillator stop flag (OSF) in the Control/Status register. * * Returns the I2C status (zero if successful). * *----------------------------------------------------------------------*/ byte DS3232RTC::set(time_t t) { tmElements_t tm; breakTime(t, tm); return ( write(tm) ); } /*----------------------------------------------------------------------* * Reads the current time from the RTC and returns it in a tmElements_t * * structure. Returns the I2C status (zero if successful). * *----------------------------------------------------------------------*/ byte DS3232RTC::read(tmElements_t &tm) { i2cBeginTransmission(RTC_ADDR); i2cWrite((uint8_t)RTC_SECONDS); if ( byte e = i2cEndTransmission() ) return e; //request 7 bytes (secs, min, hr, dow, date, mth, yr) i2cRequestFrom(RTC_ADDR, tmNbrFields); tm.Second = bcd2dec(i2cRead() & ~_BV(DS1307_CH)); tm.Minute = bcd2dec(i2cRead()); tm.Hour = bcd2dec(i2cRead() & ~_BV(HR1224)); //assumes 24hr clock tm.Wday = i2cRead(); tm.Day = bcd2dec(i2cRead()); tm.Month = bcd2dec(i2cRead() & ~_BV(CENTURY)); //don't use the Century bit tm.Year = y2kYearToTm(bcd2dec(i2cRead())); return 0; } /*----------------------------------------------------------------------* * Sets the RTC's time from a tmElements_t structure and clears the * * oscillator stop flag (OSF) in the Control/Status register. * * Returns the I2C status (zero if successful). * *----------------------------------------------------------------------*/ byte DS3232RTC::write(tmElements_t &tm) { i2cBeginTransmission(RTC_ADDR); i2cWrite((uint8_t)RTC_SECONDS); i2cWrite(dec2bcd(tm.Second)); i2cWrite(dec2bcd(tm.Minute)); i2cWrite(dec2bcd(tm.Hour)); //sets 24 hour format (Bit 6 == 0) i2cWrite(tm.Wday); i2cWrite(dec2bcd(tm.Day)); i2cWrite(dec2bcd(tm.Month)); i2cWrite(dec2bcd(tmYearToY2k(tm.Year))); byte ret = i2cEndTransmission(); uint8_t s = readRTC(RTC_STATUS); //read the status register writeRTC( RTC_STATUS, s & ~_BV(OSF) ); //clear the Oscillator Stop Flag return ret; } /*----------------------------------------------------------------------* * Write multiple bytes to RTC RAM. * * Valid address range is 0x00 - 0xFF, no checking. * * Number of bytes (nBytes) must be between 1 and 31 (Wire library * * limitation). * * Returns the I2C status (zero if successful). * *----------------------------------------------------------------------*/ byte DS3232RTC::writeRTC(byte addr, byte *values, byte nBytes) { i2cBeginTransmission(RTC_ADDR); i2cWrite(addr); for (byte i=0; i= SQWAVE_NONE) { controlReg |= _BV(INTCN); } else { controlReg = (controlReg & 0xE3) | (freq << RS1); } writeRTC(RTC_CONTROL, controlReg); } /*----------------------------------------------------------------------* * Returns the value of the oscillator stop flag (OSF) bit in the * * control/status register which indicates that the oscillator is or * * was stopped, and that the timekeeping data may be invalid. * * Optionally clears the OSF bit depending on the argument passed. * *----------------------------------------------------------------------*/ bool DS3232RTC::oscStopped(bool clearOSF) { uint8_t s = readRTC(RTC_STATUS); //read the status register bool ret = s & _BV(OSF); //isolate the osc stop flag to return to caller if (ret && clearOSF) { //clear OSF if it's set and the caller wants to clear it writeRTC( RTC_STATUS, s & ~_BV(OSF) ); } return ret; } /*----------------------------------------------------------------------* * Returns the temperature in Celsius times four. * *----------------------------------------------------------------------*/ int DS3232RTC::temperature(void) { union int16_byte { int i; byte b[2]; } rtcTemp; rtcTemp.b[0] = readRTC(TEMP_LSB); rtcTemp.b[1] = readRTC(TEMP_MSB); return rtcTemp.i >> 6; } /*----------------------------------------------------------------------* * Decimal-to-BCD conversion * *----------------------------------------------------------------------*/ uint8_t DS3232RTC::dec2bcd(uint8_t n) { return n + 6 * (n / 10); } /*----------------------------------------------------------------------* * BCD-to-Decimal conversion * *----------------------------------------------------------------------*/ uint8_t __attribute__ ((noinline)) DS3232RTC::bcd2dec(uint8_t n) { return n - 6 * (n >> 4); } DS3232RTC RTC = DS3232RTC(); //instantiate an RTC object