From 4e50789137e58487ddd2b9d6ca92863154d40577 Mon Sep 17 00:00:00 2001 From: Patrice Godard Date: Fri, 1 May 2015 19:26:25 +0200 Subject: [PATCH] DS3231, driving by external interrupts & DST changes seem OK on an Arduino Uno (ATMega 328) --- DS3231/.gitignore | 3 + DS3231/DS3231.cpp | 689 ++++++++++++++++++ DS3231/DS3231.h | 183 +++++ DS3231/LICENSE | 24 + DS3231/README.md | 14 + .../DS3231_oscillator_test.pde | 38 + DS3231/examples/DS3231_set/DS3231_set.pde | 113 +++ DS3231/examples/DS3231_test/DS3231_test.pde | 142 ++++ DS3231/examples/echo_time/echo_time.pde | 45 ++ DS3231/examples/now/now.pde | 41 ++ DS3231/examples/set_echo/set_echo.pde | 127 ++++ DS3231/keywords.txt | 33 + HorlogeBodet.atsuo | Bin 13824 -> 16384 bytes HorlogeBodet.cppproj | 167 ++++- HorlogeBodet.ino | 154 +++- Visual Micro/.HorlogeBodet.vsarduino.h | 10 +- Visual Micro/Compile.vmps.xml | 4 +- Visual Micro/Configuration.Debug.vmps.xml | 4 +- Visual Micro/Upload.vmps.xml | 4 +- 19 files changed, 1729 insertions(+), 66 deletions(-) create mode 100644 DS3231/.gitignore create mode 100644 DS3231/DS3231.cpp create mode 100644 DS3231/DS3231.h create mode 100644 DS3231/LICENSE create mode 100644 DS3231/README.md create mode 100644 DS3231/examples/DS3231_oscillator_test/DS3231_oscillator_test.pde create mode 100644 DS3231/examples/DS3231_set/DS3231_set.pde create mode 100644 DS3231/examples/DS3231_test/DS3231_test.pde create mode 100644 DS3231/examples/echo_time/echo_time.pde create mode 100644 DS3231/examples/now/now.pde create mode 100644 DS3231/examples/set_echo/set_echo.pde create mode 100644 DS3231/keywords.txt diff --git a/DS3231/.gitignore b/DS3231/.gitignore new file mode 100644 index 0000000..27ce29b --- /dev/null +++ b/DS3231/.gitignore @@ -0,0 +1,3 @@ +# Linux temp files # +################### +*~ diff --git a/DS3231/DS3231.cpp b/DS3231/DS3231.cpp new file mode 100644 index 0000000..9437230 --- /dev/null +++ b/DS3231/DS3231.cpp @@ -0,0 +1,689 @@ +/* +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 + +Released into the public domain. +*/ + +#include + +// These included for the DateTime class inclusion; will try to find a way to +// not need them in the future... +#include +// Changed the following to work on 1.0 +//#include "WProgram.h" +#include + + +#define CLOCK_ADDRESS 0x68 + +#define SECONDS_FROM_1970_TO_2000 946684800 + + +// Constructor +DS3231::DS3231() { + // nothing to do for this constructor. +} + +// Utilities from JeeLabs/Ladyada + +//////////////////////////////////////////////////////////////////////////////// +// utility code, some of this could be exposed in the 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 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; +} + +/***************************************** + 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 + ******************************************************************************/ + +//////////////////////////////////////////////////////////////////////////////// +// 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 = 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; +} + +static uint8_t conv2d(const char* p) { + uint8_t v = 0; + if ('0' <= *p && *p <= '9') + v = *p - '0'; + return 10 * v + *++p - '0'; +} + +// UNIX time: IS CORRECT ONLY WHEN SET TO UTC!!! +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; +} + +// 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); } +static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); } + +DateTime RTClib::now() { + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0); // I'm guessing the "0" is the I2C start signal + // i.e. go over everything, not just 1 register -ADW + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 7); + uint8_t ss = bcd2bin(Wire.read() & 0x7F); + uint8_t mm = bcd2bin(Wire.read()); + uint8_t hh = bcd2bin(Wire.read()); + Wire.read(); + uint8_t d = bcd2bin(Wire.read()); + uint8_t m = bcd2bin(Wire.read()); + uint16_t y = bcd2bin(Wire.read()) + 2000; + + return DateTime (y, m, d, hh, mm, ss); +} + +///// 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()); +} + +byte DS3231::getMinute() { + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x01); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 1); + return bcdToDec(Wire.read()); +} + +byte DS3231::getHour(bool& h12, bool& PM) { + byte temp_buffer; + byte hour; + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x02); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 1); + temp_buffer = Wire.read(); + h12 = temp_buffer & 0b01000000; + if (h12) { + PM = temp_buffer & 0b00100000; + hour = bcdToDec(temp_buffer & 0b00011111); + } else { + hour = bcdToDec(temp_buffer & 0b00111111); + } + return hour; +} + +byte DS3231::getDoW() { + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x03); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 1); + return bcdToDec(Wire.read()); +} + +byte DS3231::getDate() { + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x04); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 1); + return bcdToDec(Wire.read()); +} + +byte DS3231::getMonth(bool& Century) { + byte temp_buffer; + byte hour; + 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)) ; +} + +byte DS3231::getYear() { + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x06); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 1); + return bcdToDec(Wire.read()); +} + +void DS3231::setSecond(byte Second) { + // 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.endTransmission(); + // Clear OSF flag + byte temp_buffer = readControlByte(1); + writeControlByte((temp_buffer & 0b01111111), 1); +} + +void DS3231::setMinute(byte Minute) { + // Sets the minutes + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x01); + Wire.write(decToBcd(Minute)); + Wire.endTransmission(); +} + +void DS3231::setHour(byte Hour) { + // Sets the hour, without changing 12/24h mode. + // The hour must be in 24h format. + + bool h12; + + // Start by figuring out what the 12/24 mode is + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x02); + Wire.endTransmission(); + Wire.requestFrom(CLOCK_ADDRESS, 1); + h12 = (Wire.read() & 0b01000000); + // if h12 is true, it's 12h mode; false is 24h. + + if (h12) { + // 12 hour + if (Hour > 12) { + Hour = decToBcd(Hour-12) | 0b01100000; + } else { + Hour = decToBcd(Hour) & 0b11011111; + } + } else { + // 24 hour + Hour = decToBcd(Hour) & 0b10111111; + } + + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x02); + Wire.write(Hour); + Wire.endTransmission(); +} + +void DS3231::setDoW(byte DoW) { + // Sets the Day of Week + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x03); + Wire.write(decToBcd(DoW)); + Wire.endTransmission(); +} + +void DS3231::setDate(byte Date) { + // Sets the Date + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x04); + Wire.write(decToBcd(Date)); + Wire.endTransmission(); +} + +void DS3231::setMonth(byte Month) { + // Sets the month + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x05); + Wire.write(decToBcd(Month)); + Wire.endTransmission(); +} + +void DS3231::setYear(byte Year) { + // Sets the year + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x06); + Wire.write(decToBcd(Year)); + Wire.endTransmission(); +} + +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, + // though, and as long as one doesn't set the mode frequently it's + // 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. + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x02); + Wire.endTransmission(); + Wire.requestFrom(CLOCK_ADDRESS, 1); + temp_buffer = Wire.read(); + + // Set the flag to the requested value: + if (h12) { + temp_buffer = temp_buffer | 0x01000000; + } else { + temp_buffer = temp_buffer & 0x10111111; + } + + // Write the byte + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x02); + Wire.write(temp_buffer); + Wire.endTransmission(); +} + +float DS3231::getTemperature() { + // Checks the internal thermometer on the DS3231 and returns the + // temperature as a floating-point value. + byte temp; + Wire.beginTransmission(CLOCK_ADDRESS); + Wire.write(0x11); + Wire.endTransmission(); + + Wire.requestFrom(CLOCK_ADDRESS, 2); + temp = Wire.read(); // Here's the MSB + return float(temp) + 0.25*(Wire.read()>>6); +} + +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) { + // alarm is by day of week, not date. + A1Day = bcdToDec(temp_buffer & 0b00001111); + } else { + // alarm is by date, not day of week. + A1Day = bcdToDec(temp_buffer & 0b00111111); + } +} + +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); + } +} + +void DS3231::setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM) { + // Sets the alarm-1 date and time on the DS3231, using A1* information + 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 the hour to BCD and add appropriate flags. + temp_buffer = decToBcd(A1Hour) | 0b01100000; + } else { + // Morning + // Convert the 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); + // All done! + Wire.endTransmission(); +} + +void DS3231::setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM) { + // Sets the alarm-2 date and time on the 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)); + // Figure out A2 hour + if (A2h12) { + // 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 the hour to BCD and add appropriate flags. + temp_buffer = decToBcd(A2Hour) | 0b01100000; + } else { + // Morning + // Convert the 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); + // All done! + Wire.endTransmission(); +} + +void DS3231::turnOnAlarm(byte Alarm) { + // turns on alarm number "Alarm". Defaults to 2 if Alarm is not 1. + byte temp_buffer = readControlByte(0); + // modify control byte + if (Alarm == 1) { + temp_buffer = temp_buffer | 0b00000101; + } else { + temp_buffer = temp_buffer | 0b00000110; + } + writeControlByte(temp_buffer, 0); +} + +void DS3231::turnOffAlarm(byte Alarm) { + // turns off alarm number "Alarm". Defaults to 2 if Alarm is not 1. + // Leaves interrupt pin alone. + 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); +} + +bool DS3231::checkAlarmEnabled(byte Alarm) { + // Checks whether the given alarm is enabled. + byte result = 0x0; + byte temp_buffer = readControlByte(0); + if (Alarm == 1) { + result = temp_buffer & 0b00000001; + } else { + result = temp_buffer & 0b00000010; + } + return result; +} + +bool DS3231::checkIfAlarm(byte Alarm) { + // Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly. + // Turns flag off, also. + // 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; + } + 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, + // 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) + 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) { + // turn on BBSQW flag + temp_buffer = temp_buffer | 0b01000000; + } else { + // turn off BBSQW flag + temp_buffer = temp_buffer & 0b10111111; + } + if (TF) { + // set ~EOSC to 0 and INTCN to zero. + temp_buffer = temp_buffer & 0b01111011; + } else { + // set ~EOSC to 1, leave INTCN as is. + temp_buffer = temp_buffer | 0b10000000; + } + // shift frequency into bits 3 and 4 and set. + frequency = frequency << 3; + temp_buffer = temp_buffer | frequency; + // And write the control bits + writeControlByte(temp_buffer, 0); +} + +void DS3231::enable32kHz(bool TF) { + // turn 32kHz pin on or off + byte temp_buffer = readControlByte(1); + if (TF) { + // turn on 32kHz pin + temp_buffer = temp_buffer | 0b00001000; + } else { + // turn off 32kHz pin + temp_buffer = temp_buffer & 0b11110111; + } + writeControlByte(temp_buffer, 1); +} + +bool DS3231::oscillatorCheck() { + // Returns false if the oscillator has been off for some reason. + // If this is the case, the time is probably not correct. + 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; +} + +/***************************************** + Private Functions + *****************************************/ + +byte DS3231::decToBcd(byte val) { +// Convert normal decimal numbers to binary coded decimal + return ( (val/10*16) + (val%10) ); +} + +byte DS3231::bcdToDec(byte val) { +// Convert binary coded decimal to normal decimal numbers + return ( (val/16*10) + (val%16) ); +} + +byte DS3231::readControlByte(bool which) { + // Read selected control byte + // first byte (0) is 0x0e, second (1) is 0x0f + Wire.beginTransmission(CLOCK_ADDRESS); + if (which) { + // second control byte + Wire.write(0x0f); + } else { + // first control byte + Wire.write(0x0e); + } + Wire.endTransmission(); + Wire.requestFrom(CLOCK_ADDRESS, 1); + return Wire.read(); +} + +void DS3231::writeControlByte(byte control, bool which) { + // Write the selected control byte. + // which=false -> 0x0e, true->0x0f. + Wire.beginTransmission(CLOCK_ADDRESS); + if (which) { + Wire.write(0x0f); + } else { + Wire.write(0x0e); + } + Wire.write(control); + Wire.endTransmission(); +} + diff --git a/DS3231/DS3231.h b/DS3231/DS3231.h new file mode 100644 index 0000000..a0d6008 --- /dev/null +++ b/DS3231/DS3231.h @@ -0,0 +1,183 @@ +/* + * DS3231.h + * + * Arduino Library for the DS3231 Real-Time Clock chip + * + * (c) Eric Ayars + * 4/1/11 + * released into the public domain. If you use this, please let me know + * (just out of pure curiosity!) by sending me an email: + * eric@ayars.org + * + */ + +// Modified by Andy Wickert 5/15/11: Spliced in stuff from RTClib + +#ifndef DS3231_h +#define DS3231_h + +// Changed the following to work on 1.0 +//#include "WProgram.h" +#include + +#include + +// DateTime (get everything at once) from JeeLabs / Adafruit +// 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 char* date, const char* 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 dayOfWeek() const; + + // 32-bit times as seconds since 1/1/2000 + long secondstime() const; + // 32-bit times as seconds since 1/1/1970 + // THE ABOVE COMMENT IS CORRECT FOR LOCAL TIME; TO USE THIS COMMAND TO + // OBTAIN TRUE UNIX TIME SINCE EPOCH, YOU MUST CALL THIS COMMAND AFTER + // SETTING YOUR CLOCK TO UTC + uint32_t unixtime(void) const; + +protected: + uint8_t yOff, m, d, hh, mm, ss; +}; + +class RTClib { + public: + // Get date and time snapshot + static DateTime now(); +}; + +// Eric's original code is everything below this line +class DS3231 { + public: + + //Constructor + DS3231(); + + // Time-retrieval functions + + // the get*() functions retrieve current values of the registers. + byte getSecond(); + byte getMinute(); + byte getHour(bool& h12, bool& PM); + // 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); + // Also sets the flag indicating century roll-over. + 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. + + void setSecond(byte Second); + // In addition to setting the seconds, this clears the + // "Oscillator Stop Flag". + void setMinute(byte Minute); + // Sets the minute + void setHour(byte Hour); + // Sets the hour + void setDoW(byte DoW); + // Sets the Day of the Week (1-7); + void setDate(byte Date); + // Sets the Date of the Month + void setMonth(byte Month); + // Sets the Month of the year + void setYear(byte Year); + // Last two digits of the year + void setClockMode(bool h12); + // Set 12/24h mode. True is 12-h, false is 24-hour. + + // Temperature function + + float getTemperature(); + + // Alarm functions + + 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. + * A1Dy true makes the alarm go on A1Day = Day of Week, + * A1Dy false makes the alarm go on A1Day = Date of month. + * + * byte AlarmBits sets the behavior of the alarms: + * Dy A1M4 A1M3 A1M2 A1M1 Rate + * X 1 1 1 1 Once per second + * X 1 1 1 0 Alarm when seconds match + * X 1 1 0 0 Alarm when min, sec match + * X 1 0 0 0 Alarm when hour, min, sec match + * 0 0 0 0 0 Alarm when date, h, m, s match + * 1 0 0 0 0 Alarm when DoW, h, m, s match + * + * Dy A2M4 A2M3 A2M2 Rate + * X 1 1 1 Once per minute (at seconds = 00) + * X 1 1 0 Alarm when minutes match + * X 1 0 0 Alarm when hours and minutes match + * 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); + // 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); + // Set the details for Alarm 1 + 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); + // Enables alarm 1 or 2 and the external interrupt pin. + // If Alarm != 1, it assumes Alarm == 2. + 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); + // Returns T/F to indicate whether the requested alarm is + // enabled. Defaults to 2 if Alarm != 1. + bool checkIfAlarm(byte Alarm); + // Checks whether the indicated alarm (1 or 2, 2 default); + // has been activated. + + // Oscillator functions + + 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. + // 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 enable32kHz(bool TF); + // Turns the 32kHz output pin on (true); or off (false). + bool oscillatorCheck();; + // Checks the status of the OSF (Oscillator Stop Flag);. + // If this returns false, then the clock is probably not + // giving you the correct time. + // The OSF is cleared by function setSecond();. + + private: + + byte decToBcd(byte val); + // Convert normal decimal numbers to binary coded decimal + byte bcdToDec(byte val); + // Convert binary coded decimal to normal decimal numbers + 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. + // which == false -> 0x0e, true->0x0f. + +}; + +#endif diff --git a/DS3231/LICENSE b/DS3231/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/DS3231/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/DS3231/README.md b/DS3231/README.md new file mode 100644 index 0000000..0ce41f5 --- /dev/null +++ b/DS3231/README.md @@ -0,0 +1,14 @@ +DS3231 +====== + +Library to communicate with Maxim's DS3231 high-precision real-time clock (RTC) + +Eric Ayars DS3231 library with JeeLabs/Ladyada's RTC libraries spliced in by +Andy Wickert + +Released into the public domain by Jeelabs, Ladyada, and Eric Ayars; public +domain release maintained by Andy Wickert, as his changes were mostly minor: +splicing the libraries, Arduino 1.0 compatibility for Eric's DS3231 library, +and adding an example or two. + +15 May 2011 (text but not code updated on 11 September 2013) diff --git a/DS3231/examples/DS3231_oscillator_test/DS3231_oscillator_test.pde b/DS3231/examples/DS3231_oscillator_test/DS3231_oscillator_test.pde new file mode 100644 index 0000000..9d30710 --- /dev/null +++ b/DS3231/examples/DS3231_oscillator_test/DS3231_oscillator_test.pde @@ -0,0 +1,38 @@ +/* +oscillator_test.pde +Eric Ayars +4/11 + +Test/demo of oscillator routines for a DS3231 RTC. + +Use a scope after loading this to check if things are +working as they should. + +*/ + +#include +#include + +DS3231 Clock; +byte j; +bool on = false; + +void setup() { + // Start the I2C interface + Wire.begin(); + // Start the serial interface + Serial.begin(9600); +} + +void loop() { + for (j=0;j<4;j++) { + // invert state of 32kHz oscillator. + on = !on; + Clock.enable32kHz(on); + // Turn on oscillator pin, frequency j + Clock.enableOscillator(true, false, j); + delay(4000); + } + // So... The 32kHz oscillator (pin 1) will turn on or off once each 2s, + // and the oscillator out pin (pin 3) will cycle through frequencies. +} diff --git a/DS3231/examples/DS3231_set/DS3231_set.pde b/DS3231/examples/DS3231_set/DS3231_set.pde new file mode 100644 index 0000000..3a758c2 --- /dev/null +++ b/DS3231/examples/DS3231_set/DS3231_set.pde @@ -0,0 +1,113 @@ +/* +DS3231_set.pde +Eric Ayars +4/11 + +Test of set-time routines for a DS3231 RTC + +*/ + +#include +#include + +DS3231 Clock; + +byte Year; +byte Month; +byte Date; +byte DoW; +byte Hour; +byte Minute; +byte Second; + +void GetDateStuff(byte& Year, byte& Month, byte& Day, byte& DoW, + byte& Hour, byte& Minute, byte& Second) { + // Call this if you notice something coming in on + // the serial port. The stuff coming in should be in + // the order YYMMDDwHHMMSS, with an 'x' at the end. + boolean GotString = false; + char InChar; + byte Temp1, Temp2; + char InString[20]; + + byte j=0; + while (!GotString) { + if (Serial.available()) { + InChar = Serial.read(); + InString[j] = InChar; + j += 1; + if (InChar == 'x') { + GotString = true; + } + } + } + Serial.println(InString); + // Read Year first + Temp1 = (byte)InString[0] -48; + Temp2 = (byte)InString[1] -48; + Year = Temp1*10 + Temp2; + // now month + Temp1 = (byte)InString[2] -48; + Temp2 = (byte)InString[3] -48; + Month = Temp1*10 + Temp2; + // now date + Temp1 = (byte)InString[4] -48; + Temp2 = (byte)InString[5] -48; + Day = Temp1*10 + Temp2; + // now Day of Week + DoW = (byte)InString[6] - 48; + // now Hour + Temp1 = (byte)InString[7] -48; + Temp2 = (byte)InString[8] -48; + Hour = Temp1*10 + Temp2; + // now Minute + Temp1 = (byte)InString[9] -48; + Temp2 = (byte)InString[10] -48; + Minute = Temp1*10 + Temp2; + // now Second + Temp1 = (byte)InString[11] -48; + Temp2 = (byte)InString[12] -48; + Second = Temp1*10 + Temp2; +} + +void setup() { + // Start the serial port + Serial.begin(9600); + + // Start the I2C interface + Wire.begin(); +} + +void loop() { + + // If something is coming in on the serial line, it's + // a time correction so set the clock accordingly. + if (Serial.available()) { + GetDateStuff(Year, Month, Date, DoW, Hour, Minute, Second); + + Clock.setClockMode(false); // set to 24h + //setClockMode(true); // set to 12h + + Clock.setYear(Year); + Clock.setMonth(Month); + Clock.setDate(Date); + Clock.setDoW(DoW); + Clock.setHour(Hour); + Clock.setMinute(Minute); + Clock.setSecond(Second); + + // Test of alarm functions + // set A1 to one minute past the time we just set the clock + // on current day of week. + Clock.setA1Time(DoW, Hour, Minute+1, Second, 0x0, true, + false, false); + // set A2 to two minutes past, on current day of month. + Clock.setA2Time(Date, Hour, Minute+2, 0x0, false, false, + false); + // Turn on both alarms, with external interrupt + Clock.turnOnAlarm(1); + Clock.turnOnAlarm(2); + + } + delay(1000); +} diff --git a/DS3231/examples/DS3231_test/DS3231_test.pde b/DS3231/examples/DS3231_test/DS3231_test.pde new file mode 100644 index 0000000..8d97185 --- /dev/null +++ b/DS3231/examples/DS3231_test/DS3231_test.pde @@ -0,0 +1,142 @@ +/* +DS3231_test.pde +Eric Ayars +4/11 + +Test/demo of read routines for a DS3231 RTC. + +Turn on the serial monitor after loading this to check if things are +working as they should. + +*/ + +#include +#include + +DS3231 Clock; +bool Century=false; +bool h12; +bool PM; +byte ADay, AHour, AMinute, ASecond, ABits; +bool ADy, A12h, Apm; + +void setup() { + // Start the I2C interface + Wire.begin(); + // Start the serial interface + Serial.begin(9600); +} + +void loop() { + // send what's going on to the serial monitor. + // Start with the year + Serial.print("2"); + if (Century) { // Won't need this for 89 years. + Serial.print("1"); + } else { + Serial.print("0"); + } + Serial.print(Clock.getYear(), DEC); + Serial.print(' '); + // then the month + Serial.print(Clock.getMonth(Century), DEC); + Serial.print(' '); + // then the date + Serial.print(Clock.getDate(), DEC); + Serial.print(' '); + // and the day of the week + Serial.print(Clock.getDoW(), DEC); + Serial.print(' '); + // Finally the hour, minute, and second + Serial.print(Clock.getHour(h12, PM), DEC); + Serial.print(' '); + Serial.print(Clock.getMinute(), DEC); + Serial.print(' '); + Serial.print(Clock.getSecond(), DEC); + // Add AM/PM indicator + if (h12) { + if (PM) { + Serial.print(" PM "); + } else { + Serial.print(" AM "); + } + } else { + Serial.print(" 24h "); + } + // Display the temperature + Serial.print("T="); + Serial.print(Clock.getTemperature(), 2); + // Tell whether the time is (likely to be) valid + if (Clock.oscillatorCheck()) { + Serial.print(" O+"); + } else { + Serial.print(" O-"); + } + // Indicate whether an alarm went off + if (Clock.checkIfAlarm(1)) { + Serial.print(" A1!"); + } + if (Clock.checkIfAlarm(2)) { + Serial.print(" A2!"); + } + // New line on display + Serial.print('\n'); + // Display Alarm 1 information + Serial.print("Alarm 1: "); + Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm); + Serial.print(ADay, DEC); + if (ADy) { + Serial.print(" DoW"); + } else { + Serial.print(" Date"); + } + Serial.print(' '); + Serial.print(AHour, DEC); + Serial.print(' '); + Serial.print(AMinute, DEC); + Serial.print(' '); + Serial.print(ASecond, DEC); + Serial.print(' '); + if (A12h) { + if (Apm) { + Serial.print('pm '); + } else { + Serial.print('am '); + } + } + if (Clock.checkAlarmEnabled(1)) { + Serial.print("enabled"); + } + Serial.print('\n'); + // Display Alarm 2 information + Serial.print("Alarm 2: "); + Clock.getA2Time(ADay, AHour, AMinute, ABits, ADy, A12h, Apm); + Serial.print(ADay, DEC); + if (ADy) { + Serial.print(" DoW"); + } else { + Serial.print(" Date"); + } + Serial.print(' '); + Serial.print(AHour, DEC); + Serial.print(' '); + Serial.print(AMinute, DEC); + Serial.print(' '); + if (A12h) { + if (Apm) { + Serial.print('pm'); + } else { + Serial.print('am'); + } + } + if (Clock.checkAlarmEnabled(2)) { + Serial.print("enabled"); + } + // display alarm bits + Serial.print('\nAlarm bits: '); + Serial.print(ABits, BIN); + + Serial.print('\n'); + Serial.print('\n'); + delay(1000); +} diff --git a/DS3231/examples/echo_time/echo_time.pde b/DS3231/examples/echo_time/echo_time.pde new file mode 100644 index 0000000..9cfecb1 --- /dev/null +++ b/DS3231/examples/echo_time/echo_time.pde @@ -0,0 +1,45 @@ +/* + +Sets the time and prints back time stamps for 5 seconds + +Based on DS3231_set.pde +by Eric Ayars +4/11 + +Added printing back of time stamps and increased baud rate +(to better synchronize computer and RTC) +Andy Wickert +5/15/2011 + +*/ + +#include +#include + +DS3231 Clock; + +void setup() { + // Start the serial port + Serial.begin(57600); + + // Start the I2C interface + Wire.begin(); + + + for (int i=0; i<5; i++){ + delay(1000); + Serial.print(Clock.getYear(), DEC); + Serial.print("-"); + Serial.print(Clock.getMonth(Century), DEC); + Serial.print("-"); + Serial.print(Clock.getDate(), DEC); + Serial.print(" "); + Serial.print(Clock.getHour(h12, PM), DEC); //24-hr + Serial.print(":"); + Serial.print(Clock.getMinute(), DEC); + Serial.print(":"); + Serial.println(Clock.getSecond(), DEC); +} + +void loop() {} + diff --git a/DS3231/examples/now/now.pde b/DS3231/examples/now/now.pde new file mode 100644 index 0000000..62e3bb4 --- /dev/null +++ b/DS3231/examples/now/now.pde @@ -0,0 +1,41 @@ +// now.pde +// Prints a snapshot of the current date and time along with the UNIX time +// Modified by Andy Wickert from the JeeLabs / Ladyada RTC library examples +// 5/15/11 + +#include +#include "DS3231.h" + +RTClib RTC; + +void setup () { + Serial.begin(57600); + Wire.begin(); +} + +void loop () { + + delay(1000); + + DateTime now = RTC.now(); + + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + + Serial.print(" since midnight 1/1/1970 = "); + Serial.print(now.unixtime()); + Serial.print("s = "); + Serial.print(now.unixtime() / 86400L); + Serial.println("d"); +} + diff --git a/DS3231/examples/set_echo/set_echo.pde b/DS3231/examples/set_echo/set_echo.pde new file mode 100644 index 0000000..e0031e7 --- /dev/null +++ b/DS3231/examples/set_echo/set_echo.pde @@ -0,0 +1,127 @@ +/* + +Sets the time and prints back time stamps for 5 seconds + +Based on DS3231_set.pde +by Eric Ayars +4/11 + +Added printing back of time stamps and increased baud rate +(to better synchronize computer and RTC) +Andy Wickert +5/15/2011 + +*/ + +#include +#include + +DS3231 Clock; + +byte Year; +byte Month; +byte Date; +byte DoW; +byte Hour; +byte Minute; +byte Second; + +bool Century=false; +bool h12; +bool PM; + +void GetDateStuff(byte& Year, byte& Month, byte& Day, byte& DoW, + byte& Hour, byte& Minute, byte& Second) { + // Call this if you notice something coming in on + // the serial port. The stuff coming in should be in + // the order YYMMDDwHHMMSS, with an 'x' at the end. + boolean GotString = false; + char InChar; + byte Temp1, Temp2; + char InString[20]; + + byte j=0; + while (!GotString) { + if (Serial.available()) { + InChar = Serial.read(); + InString[j] = InChar; + j += 1; + if (InChar == 'x') { + GotString = true; + } + } + } + Serial.println(InString); + // Read Year first + Temp1 = (byte)InString[0] -48; + Temp2 = (byte)InString[1] -48; + Year = Temp1*10 + Temp2; + // now month + Temp1 = (byte)InString[2] -48; + Temp2 = (byte)InString[3] -48; + Month = Temp1*10 + Temp2; + // now date + Temp1 = (byte)InString[4] -48; + Temp2 = (byte)InString[5] -48; + Day = Temp1*10 + Temp2; + // now Day of Week + DoW = (byte)InString[6] - 48; + // now Hour + Temp1 = (byte)InString[7] -48; + Temp2 = (byte)InString[8] -48; + Hour = Temp1*10 + Temp2; + // now Minute + Temp1 = (byte)InString[9] -48; + Temp2 = (byte)InString[10] -48; + Minute = Temp1*10 + Temp2; + // now Second + Temp1 = (byte)InString[11] -48; + Temp2 = (byte)InString[12] -48; + Second = Temp1*10 + Temp2; +} + +void setup() { + // Start the serial port + Serial.begin(57600); + + // Start the I2C interface + Wire.begin(); +} + +void loop() { + + // If something is coming in on the serial line, it's + // a time correction so set the clock accordingly. + if (Serial.available()) { + GetDateStuff(Year, Month, Date, DoW, Hour, Minute, Second); + + Clock.setClockMode(false); // set to 24h + //setClockMode(true); // set to 12h + + Clock.setYear(Year); + Clock.setMonth(Month); + Clock.setDate(Date); + Clock.setDoW(DoW); + Clock.setHour(Hour); + Clock.setMinute(Minute); + Clock.setSecond(Second); + + // Give time at next five seconds + for (int i=0; i<5; i++){ + delay(1000); + Serial.print(Clock.getYear(), DEC); + Serial.print("-"); + Serial.print(Clock.getMonth(Century), DEC); + Serial.print("-"); + Serial.print(Clock.getDate(), DEC); + Serial.print(" "); + Serial.print(Clock.getHour(h12, PM), DEC); //24-hr + Serial.print(":"); + Serial.print(Clock.getMinute(), DEC); + Serial.print(":"); + Serial.println(Clock.getSecond(), DEC); + } + + } + delay(1000); +} diff --git a/DS3231/keywords.txt b/DS3231/keywords.txt new file mode 100644 index 0000000..a82da80 --- /dev/null +++ b/DS3231/keywords.txt @@ -0,0 +1,33 @@ +DS3231 KEYWORD1 +RTClib KEYWORD1 +DateTime KEYWORD1 +now KEYWORD2 +secondstime KEYWORD2 +unixtime KEYWORD2 +getSecond KEYWORD2 +getMinute KEYWORD2 +getHour KEYWORD2 +getDoW KEYWORD2 +getDate KEYWORD2 +getMonth KEYWORD2 +getYear KEYWORD2 +setSecond KEYWORD2 +setMinute KEYWORD2 +setHour KEYWORD2 +setDoW KEYWORD2 +setDate KEYWORD2 +setMonth KEYWORD2 +setYear KEYWORD2 +setClockMode KEYWORD2 +getTemperature KEYWORD2 +getA1Time KEYWORD2 +getA2Time KEYWORD2 +setA1Time KEYWORD2 +setA2Time KEYWORD2 +turnOnAlarm KEYWORD2 +turnOffAlarm KEYWORD2 +checkAlarmEnabled KEYWORD2 +checkIfAlarm KEYWORD2 +enableOscillator KEYWORD2 +enable32kHz KEYWORD2 +oscillatorCheck KEYWORD2 diff --git a/HorlogeBodet.atsuo b/HorlogeBodet.atsuo index a3a623c4e2616e95bedd259ed3640f41ec887f99..abcc8a6964c2ec86102bd72dad53ae4e9057f5a2 100644 GIT binary patch delta 1381 zcmb7EU1(Eh82-NGJ8e$e*&fsM$EG#4DYj|zXIlgnmsG*l3P$iU7s6PHk@Jd8vSG|~(8K3VoDRX1sUU>38@6Y*i z-k`99%a>AFX&I@miR|!90NWEW&s(`L*KB?am4~MN*T9L z-IJd3M$%J>tWi`2w;`z{YnNpxRUk!rQFBjaD(E|9zp+#sQEXkX>dGF{wf!{G+;1#t zU-DX`nlUT8!gp>76nq}~!M`-XcW6ciu<1#J~=8@ zwQXWDmD(;TV`J#2leF$xUQK7a1KP12$>C%?9bHkr@l2tAM65xgxgvW1eOUtOUNmC^ zymF6Zq%H$;3y?zl`mWvZY1}CKPjedX*i38vGjCggS^CO3E59v_WAJh*D)JqOTyvWD z_ZJ49@vqQJ2QN^#ca%m0jqCTYG@D{x7BO`Ki|55c##xT(3>ICsIqV17@6T$cPkukV z;o*fxPfH7hU+u&_b|rxvAN@6OO4};#K0p5?q1-VZygbpng`4qnv4&kb4vMlc3uoV- zOirYuspNavcs7~H$w{oN<-Zy~o{XEvbkG(o`{^DcHVsa}IqSXUAcl06qogfX{%Fz$rjp-Y=j}m-!j!1$>IW z;pbujH400LoZcu!>etcYP(WT7$l~99cyid)RQ16O+gTJkw=kb-0W^G4QF`-pp(YIvbc-V+C-&=(wms!ZUv za6!OsuFQ}4KqWS)Itlz1-gG{GEk5m#+1|9qCtP8r3k-RNs|?o|xPIM?MKdn3xC~ly z;+0gxt17{hkW1*)kO`K!7w(dq5JW~U!kInAS6^klDdEh*; z^QZ0(S_4_wQ8Zc_e9^<*!shTvNDrm4Ojm|7f^?i|Uh^+8$jB2!_k0x#4#6G&Hhun8Ca0V19;<%g1pUYn^&UFI(3VXp5 zUTcJANS`?eN}&%jW~*-d50o)xlW4X@CTuY9Ltlm!434lBz8qCxIO2gVZF=8Pj2e;q z7}NxTtQrzisE8I3M51w8Nd)kTWT$`s{&v81bxdVvI-$q)@u}#&M(jIAfHgN5r)tVA zKNTO(ZC$Ewf13EZzOrry9PEdj*9ED#q_}@9HGe*Q5ZqncrDcS58+#pv6.2 com.Atmel.AVRGCC8.CPP {07b459b4-8d76-4638-bc6d-a459ba2d616b} - atmega32u4 + atmega328p none Executable CPP @@ -52,8 +52,8 @@ True - __AVR_ATmega32u4__ - __AVR_ATmega32U4__ + __AVR_ATmega328p__ + __AVR_ATmega328P__ ARDUINO=105 ARDUINO_MAIN F_CPU=16000000L @@ -79,7 +79,7 @@ D:/arduino/arduino-1.0.5/libraries/Wire D:/arduino/arduino-1.0.5/libraries/EEPROM/utility D:/arduino/arduino-1.0.5/libraries/EEPROM - D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo + D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino @@ -92,8 +92,8 @@ True - __AVR_ATmega32u4__ - __AVR_ATmega32U4__ + __AVR_ATmega328p__ + __AVR_ATmega328P__ ARDUINO=105 ARDUINO_MAIN F_CPU=16000000L @@ -119,7 +119,7 @@ D:/arduino/arduino-1.0.5/libraries/Wire D:/arduino/arduino-1.0.5/libraries/EEPROM/utility D:/arduino/arduino-1.0.5/libraries/EEPROM - D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo + D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino @@ -139,7 +139,68 @@ D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino;D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo;D:/arduino/arduino-1.0.5/libraries;D:/arduino/arduino-1.0.5/hardware/arduino/libraries;C:/Program Files (x86)/Visual Micro/Visual Micro for Arduino/Micro Platforms/default/debuggers;C:/Users/xnrq8224/Documents/Arduino/libraries;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/include/;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/include/avr/;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/;d:/arduino/arduino-1.0.5/hardware/tools/avr/lib/gcc/avr/4.3.2/include/;;C:/Users/xnrq8224/Documents/Arduino/libraries/DS3231;C:/Users/xnrq8224/Documents/Arduino/libraries/DS3231/utility;D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard;D:/arduino/arduino-1.0.5/libraries/Wire;D:/arduino/arduino-1.0.5/libraries/Wire/utility;D:/arduino/arduino-1.0.5/libraries/EEPROM;D:/arduino/arduino-1.0.5/libraries/EEPROM/utility;D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino/avr-libc;C:/Users/xnrq8224/Documents/Arduino/libraries/Low-Power-master;C:/Users/xnrq8224/Documents/Arduino/libraries/Low-Power-master/utility; - COM6 + COM5 + uno + Arduino Uno + name=Arduino Uno +upload.protocol=arduino +upload.maximum_size=32256 +upload.speed=115200 +bootloader.low_fuses=0xff +bootloader.high_fuses=0xde +bootloader.extended_fuses=0x05 +bootloader.path=optiboot +bootloader.file=optiboot_atmega328.hex +bootloader.unlock_bits=0x3F +bootloader.lock_bits=0x0F +build.mcu=atmega328p +build.f_cpu=16000000L +build.core=arduino +build.variant=standard +runtime.ide.path=D:\arduino\arduino-1.0.5 +build.system.path=D:\arduino\arduino-1.0.5\hardware\arduino\system +runtime.ide.version=105 +originalid=uno +vm.platform.root.path=C:\Program Files (x86)\Visual Micro\Visual Micro for Arduino\Micro Platforms\arduino10x +ide.hint=Arduino 0023 and 1.0.x Ide +ide.location.key=Arduino +ide.location.ide.winreg=Arduino 1.0.x Application +ide.location.sketchbook.winreg=Arduino 1.0.x Sketchbook +ide.location.sketchbook.preferences=sketchbook.path +ide.location.sketchbook.default=%MYDOCUMENTS%\arduino +ide.location.preferences=%VM_APPDATA_ROAMING%\arduino\preferences.txt +ide.default.package=arduino +ide.default.platform=avr +ide.multiplatform=true +ide.includes=arduino.h +ide.platformswithoutpackage=true +ide.includes.fallback=wprogram.h +ide.extension=ino +ide.extension.fallback=pde +ide.versionLTEQ=149 +ide.exe=arduino.exe +ide.hosts=atmel +ide.url=http://arduino.cc/en/Main/Software +vm.debug=true +software=ARDUINO +ide.appid=arduino10x +location.sketchbook=C:\Users\xnrq8224\Documents\Arduino\ +vm.core.include=arduino.h +build.board=AVR_UNO +vm.boardsource.path=D:\arduino\arduino-1.0.5\hardware\arduino +runtime.platform.path=D:\arduino\arduino-1.0.5\hardware\arduino +vm.platformname.name=avr +build.arch=AVR + + atmega328p + 16000000L + arduino + arduino + 115200 + 32256 + arduino10x + arduino + avr @@ -155,8 +216,8 @@ True - __AVR_ATmega32u4__ - __AVR_ATmega32U4__ + __AVR_ATmega328p__ + __AVR_ATmega328P__ ARDUINO=105 ARDUINO_MAIN F_CPU=16000000L @@ -182,7 +243,7 @@ D:/arduino/arduino-1.0.5/libraries/Wire D:/arduino/arduino-1.0.5/libraries/EEPROM/utility D:/arduino/arduino-1.0.5/libraries/EEPROM - D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo + D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino @@ -195,8 +256,8 @@ True - __AVR_ATmega32u4__ - __AVR_ATmega32U4__ + __AVR_ATmega328p__ + __AVR_ATmega328P__ ARDUINO=105 ARDUINO_MAIN F_CPU=16000000L @@ -222,7 +283,7 @@ D:/arduino/arduino-1.0.5/libraries/Wire D:/arduino/arduino-1.0.5/libraries/EEPROM/utility D:/arduino/arduino-1.0.5/libraries/EEPROM - D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo + D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino @@ -242,7 +303,68 @@ D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino;D:/arduino/arduino-1.0.5/hardware/arduino/variants/leonardo;D:/arduino/arduino-1.0.5/libraries;D:/arduino/arduino-1.0.5/hardware/arduino/libraries;C:/Program Files (x86)/Visual Micro/Visual Micro for Arduino/Micro Platforms/default/debuggers;C:/Users/xnrq8224/Documents/Arduino/libraries;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/include/;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/include/avr/;d:/arduino/arduino-1.0.5/hardware/tools/avr/avr/;d:/arduino/arduino-1.0.5/hardware/tools/avr/lib/gcc/avr/4.3.2/include/;;C:/Users/xnrq8224/Documents/Arduino/libraries/DS3231;C:/Users/xnrq8224/Documents/Arduino/libraries/DS3231/utility;D:/arduino/arduino-1.0.5/hardware/arduino/variants/standard;D:/arduino/arduino-1.0.5/libraries/Wire;D:/arduino/arduino-1.0.5/libraries/Wire/utility;D:/arduino/arduino-1.0.5/libraries/EEPROM;D:/arduino/arduino-1.0.5/libraries/EEPROM/utility;D:/arduino/arduino-1.0.5/hardware/arduino/cores/arduino/avr-libc;C:/Users/xnrq8224/Documents/Arduino/libraries/Low-Power-master;C:/Users/xnrq8224/Documents/Arduino/libraries/Low-Power-master/utility; - COM6 + COM5 + uno + Arduino Uno + name=Arduino Uno +upload.protocol=arduino +upload.maximum_size=32256 +upload.speed=115200 +bootloader.low_fuses=0xff +bootloader.high_fuses=0xde +bootloader.extended_fuses=0x05 +bootloader.path=optiboot +bootloader.file=optiboot_atmega328.hex +bootloader.unlock_bits=0x3F +bootloader.lock_bits=0x0F +build.mcu=atmega328p +build.f_cpu=16000000L +build.core=arduino +build.variant=standard +runtime.ide.path=D:\arduino\arduino-1.0.5 +build.system.path=D:\arduino\arduino-1.0.5\hardware\arduino\system +runtime.ide.version=105 +originalid=uno +vm.platform.root.path=C:\Program Files (x86)\Visual Micro\Visual Micro for Arduino\Micro Platforms\arduino10x +ide.hint=Arduino 0023 and 1.0.x Ide +ide.location.key=Arduino +ide.location.ide.winreg=Arduino 1.0.x Application +ide.location.sketchbook.winreg=Arduino 1.0.x Sketchbook +ide.location.sketchbook.preferences=sketchbook.path +ide.location.sketchbook.default=%MYDOCUMENTS%\arduino +ide.location.preferences=%VM_APPDATA_ROAMING%\arduino\preferences.txt +ide.default.package=arduino +ide.default.platform=avr +ide.multiplatform=true +ide.includes=arduino.h +ide.platformswithoutpackage=true +ide.includes.fallback=wprogram.h +ide.extension=ino +ide.extension.fallback=pde +ide.versionLTEQ=149 +ide.exe=arduino.exe +ide.hosts=atmel +ide.url=http://arduino.cc/en/Main/Software +vm.debug=true +software=ARDUINO +ide.appid=arduino10x +location.sketchbook=C:\Users\xnrq8224\Documents\Arduino\ +vm.core.include=arduino.h +build.board=AVR_UNO +vm.boardsource.path=D:\arduino\arduino-1.0.5\hardware\arduino +runtime.platform.path=D:\arduino\arduino-1.0.5\hardware\arduino +vm.platformname.name=avr +build.arch=AVR + + atmega328p + 16000000L + arduino + arduino + 115200 + 32256 + arduino10x + arduino + avr @@ -259,10 +381,11 @@ + - + @@ -274,6 +397,14 @@ compile src\sketch-api-readonly\libraries\DS3231\DS3231.h + + compile + src\sketch-api-readonly\libraries\Low-Power-master\LowPower.cpp + + + compile + src\sketch-api-readonly\libraries\Low-Power-master\LowPower.h + compile src\sketch-api-readonly\core\Arduino.h @@ -434,9 +565,9 @@ compile src\sketch-api-readonly\core\WString.h - + compile - src\sketch-api-readonly\variants\leonardo\pins_arduino.h + src\sketch-api-readonly\variants\standard\pins_arduino.h compile diff --git a/HorlogeBodet.ino b/HorlogeBodet.ino index fa0234c..08d0515 100644 --- a/HorlogeBodet.ino +++ b/HorlogeBodet.ino @@ -9,7 +9,7 @@ #include #include -#define DEBUG_SERIAL +#define DEBUG_SERIAL 1 #if defined(__AVR_ATmega32U4__) #define PIN_INTERRUPT 0 @@ -29,18 +29,49 @@ #define OFFSET_WINTER 3600 #define OFFSET_SUMMER 7200 #define OFFSET_ADDRESS 0 +#define FAST_FORWARD_DELAY 400 //positive if clock is disabled (for specified number of cycles) //used to disable clock for 1h during winter time change uint8_t disabled = 0; RTClib RTC; DS3231 clock; +volatile uint8_t tickCounter=0; +//true if a tick interrupt has been received +volatile uint8_t tickReceived=0; +#ifdef DEBUG_SERIAL +void dumpTimestamp(char* msg){ + DateTime now = RTC.now(); + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), 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(msg); +} +#endif /************************************************************************/ /* Wake-up interrupt routine */ /************************************************************************/ void tick(){ + if(tickCounter == 0){ + tickReceived = true; + }else{ + tickReceived = false; + } + tickCounter++; + if(tickCounter == 30){ + tickCounter = 0; + } } void setup() { @@ -52,7 +83,7 @@ void setup() { digitalWrite(PIN_1,LOW); digitalWrite(PIN_2,LOW); #ifdef DEBUG_SERIAL - Serial.begin(57600); + Serial.begin(9600); #endif //init RTC clock.enableOscillator(true,false,0); //enable 1Hz on SQW output @@ -73,8 +104,20 @@ void setup() { } attachInterrupt(ID_INTERRUPT, tick, RISING); + + //TODO supprimer après tests + pinMode(13,OUTPUT); + digitalWrite(13,HIGH); + delay(5000); + digitalWrite(13,LOW); + #ifdef DEBUG_SERIAL + dumpTimestamp("starting loop"); + #endif } +/************************************************************************/ +/* Send pulse to clock motor - pulse polarity is automatically inverted on each call */ +/************************************************************************/ void pulse(uint16_t pulseWidth) { static uint8_t step = 0; @@ -106,6 +149,7 @@ void recordOffset(uint16_t offset) uint16_t readOffset() { uint16_t offset = EEPROM.read(OFFSET_ADDRESS) | (EEPROM.read(OFFSET_ADDRESS+1) << 8); + return offset; } /************************************************************************/ @@ -180,50 +224,84 @@ uint32_t getCurrentTimeOffset() return offset; } +/*********************************************************************************************/ +/* add 1h to the displayed time, and compensates for the time taken to move the clock hands */ +/*********************************************************************************************/ +void fastForwardToSummerTime(){ + for(int p=0;p<121;p++){ + pulse(PULSE_WIDTH); + delay(FAST_FORWARD_DELAY); + } +} void loop() { - unsigned long t1,t2; - //fast-forward mode - if(!digitalRead(PIN_FF)){ - do{ - pulse(PULSE_WIDTH); - delay(400); - }while(!digitalRead(PIN_FF)); - } - //check if DTS time change is required - //TODO implement - //if -1 -> disabled = 3600 - //if 1 -> fast-forward for 1h + delta secs (to be measured) + unsigned long t1,t2; + //fast-forward mode + if(!digitalRead(PIN_FF)){ + do{ + pulse(PULSE_WIDTH); + delay(FAST_FORWARD_DELAY); + }while(!digitalRead(PIN_FF)); + } + if(tickReceived){ + #ifdef DEBUG_SERIAL + dumpTimestamp("tickReceived"); + #endif + uint8_t changeRequired = calcDSTChange(); + #ifdef DEBUG_SERIAL + Serial.print("changeRequired: "); + Serial.println(changeRequired); + #endif + if(changeRequired == -1){ + disabled = 3600; + }else{ + if(changeRequired == 1){ + fastForwardToSummerTime(); + } + } + + //check if DTS time change is required + //TODO implement + //if -1 -> disabled = 3600 + //if 1 -> fast-forward for 1h + delta secs (to be measured) - //main loop - if(disabled == 0){ - t1 = millis(); - pulse(PULSE_WIDTH); - t2 = millis(); - }else{ - //updates are disabled - disabled--; - } + //main loop + if(disabled == 0){ + t1 = millis(); + pulse(PULSE_WIDTH); + t2 = millis(); + }else{ + //updates are disabled + disabled--; + } -#ifdef DEBUG_SERIAL - DateTime now = RTC.now(); - Serial.print(now.year(), DEC); - Serial.print('/'); - Serial.print(now.month(), DEC); - Serial.print('/'); - Serial.print(now.day(), DEC); - Serial.print(' '); - Serial.print(now.hour(), DEC); - Serial.print(':'); - Serial.print(now.minute(), DEC); - Serial.print(':'); - Serial.print(now.second(), DEC); - Serial.println(); -#endif + #ifdef DEBUG_SERIAL + DateTime now = RTC.now(); + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + #endif + } //delay(PERIOD-((t2-t1))); // Enter power down state with ADC and BOD module disabled. // Wake up when wake up pin is rising //TODO set BOD_OFF after tests LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON); + //LowPower.powerSave(SLEEP_FOREVER, ADC_OFF, BOD_ON,TIMER2_ON); + //LowPower.idle(SLEEP_FOREVER, ADC_OFF,TIMER4_ON,TIMER3_ON, TIMER1_ON, TIMER0_ON,SPI_ON,USART1_ON,TWI_ON,USB_ON); + //TODO supprimer après tests + pinMode(13,OUTPUT); + digitalWrite(13,HIGH); + delay(25); + digitalWrite(13,LOW); } diff --git a/Visual Micro/.HorlogeBodet.vsarduino.h b/Visual Micro/.HorlogeBodet.vsarduino.h index f2900c0..a1ec303 100644 --- a/Visual Micro/.HorlogeBodet.vsarduino.h +++ b/Visual Micro/.HorlogeBodet.vsarduino.h @@ -5,17 +5,18 @@ all non-arduino files created by visual micro and all visual studio project or solution files can be freely deleted and are not required to compile a sketch (do not delete your own code!). note: debugger breakpoints are stored in '.sln' or '.asln' files, knowledge of last uploaded breakpoints is stored in the upload.vmps.xml file. Both files are required to continue a previous debug session without needing to compile and upload again - Hardware: Arduino Leonardo, Platform=avr, Package=arduino + Hardware: Arduino Duemilanove w/ ATmega328, Platform=avr, Package=arduino */ -#define __AVR_ATmega32u4__ -#define __AVR_ATmega32U4__ +#define __AVR_ATmega328p__ +#define __AVR_ATmega328P__ #define ARDUINO 105 #define ARDUINO_MAIN #define F_CPU 16000000L #define __AVR__ extern "C" void __cxa_pure_virtual() {;} +void dumpTimestamp(char* msg); void tick(); // void pulse(uint16_t pulseWidth); @@ -24,8 +25,9 @@ uint16_t readOffset(); int8_t calcDSTChange(); uint16_t adjustDstEurope(DateTime t); uint32_t getCurrentTimeOffset(); +void fastForwardToSummerTime(); // -#include "D:\arduino\arduino-1.0.5\hardware\arduino\variants\leonardo\pins_arduino.h" +#include "D:\arduino\arduino-1.0.5\hardware\arduino\variants\standard\pins_arduino.h" #include "D:\arduino\arduino-1.0.5\hardware\arduino\cores\arduino\arduino.h" #include "C:\Users\xnrq8224\Documents\Arduino\HorlogeBodet\HorlogeBodet.ino" diff --git a/Visual Micro/Compile.vmps.xml b/Visual Micro/Compile.vmps.xml index 041f0d4..047c04a 100644 --- a/Visual Micro/Compile.vmps.xml +++ b/Visual Micro/Compile.vmps.xml @@ -1,9 +1,9 @@ - + - + diff --git a/Visual Micro/Configuration.Debug.vmps.xml b/Visual Micro/Configuration.Debug.vmps.xml index 16fce6c..27b7efa 100644 --- a/Visual Micro/Configuration.Debug.vmps.xml +++ b/Visual Micro/Configuration.Debug.vmps.xml @@ -1,9 +1,9 @@ - + - + \ No newline at end of file diff --git a/Visual Micro/Upload.vmps.xml b/Visual Micro/Upload.vmps.xml index 041f0d4..047c04a 100644 --- a/Visual Micro/Upload.vmps.xml +++ b/Visual Micro/Upload.vmps.xml @@ -1,9 +1,9 @@ - + - +