diff --git a/arduino_mcu/libraries/DS3232RTC/.gitignore b/arduino_mcu/libraries/DS3232RTC/.gitignore new file mode 100644 index 00000000..b03f7f6f --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/.gitignore @@ -0,0 +1,2 @@ +*.zip +*.7z diff --git a/arduino_mcu/libraries/DS3232RTC/DS3232RTC.cpp b/arduino_mcu/libraries/DS3232RTC/DS3232RTC.cpp new file mode 100644 index 00000000..a3fe8c5b --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/DS3232RTC.cpp @@ -0,0 +1,335 @@ +/*----------------------------------------------------------------------* + * 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. * + * * + * 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 * + * 28Aug2013 Changed the lower level methods to return the status of * + * the I2C communication with the RTC. Thanks to * + * Rob Tillaart for the suggestion. (Fixes issue #1.) * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 444 Castro Street, Suite 900, * + * Mountain View, CA 94041. * + *----------------------------------------------------------------------*/ + +#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(); +} + +/*----------------------------------------------------------------------* + * Read the current time from the RTC and return 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) ); +} + +/*----------------------------------------------------------------------* + * Set the RTC to the given time_t value. * + * Returns the I2C status (zero if successful). * + *----------------------------------------------------------------------*/ +byte DS3232RTC::set(time_t t) +{ + tmElements_t tm; + + breakTime(t, tm); + return ( write(tm) ); +} + +/*----------------------------------------------------------------------* + * Read the current time from the RTC and return 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; +} + +/*----------------------------------------------------------------------* + * Set the RTC's time from a tmElements_t structure. * + * 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))); + return i2cEndTransmission(); +} + +/*----------------------------------------------------------------------* + * 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); +} + +/*----------------------------------------------------------------------* + * Checks the OSF bit in the status register which indicates that the * + * oscillator is or was stopped. * + *----------------------------------------------------------------------*/ +boolean DS3232RTC::oscStopped(void) +{ + return ( readRTC(RTC_STATUS) & _BV(OSF) ); +} + +/*----------------------------------------------------------------------* + * 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 diff --git a/arduino_mcu/libraries/DS3232RTC/DS3232RTC.h b/arduino_mcu/libraries/DS3232RTC/DS3232RTC.h new file mode 100644 index 00000000..673217ef --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/DS3232RTC.h @@ -0,0 +1,157 @@ +/*----------------------------------------------------------------------* + * DS3232RTC.h - 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. * + * * + * 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 * + * 28Aug2013 Changed the lower level methods to return the status of * + * the I2C communication with the RTC. Thanks to * + * Rob Tillaart for the suggestion. (Fixes issue #1.) * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 444 Castro Street, Suite 900, * + * Mountain View, CA 94041. * + *----------------------------------------------------------------------*/ + +#ifndef DS3232RTC_h +#define DS3232RTC_h +#include + +#if defined(ARDUINO) && ARDUINO >= 100 +#include +#else +#include +#endif + +//DS3232 I2C Address +#define RTC_ADDR 0x68 + +//DS3232 Register Addresses +#define RTC_SECONDS 0x00 +#define RTC_MINUTES 0x01 +#define RTC_HOURS 0x02 +#define RTC_DAY 0x03 +#define RTC_DATE 0x04 +#define RTC_MONTH 0x05 +#define RTC_YEAR 0x06 +#define ALM1_SECONDS 0x07 +#define ALM1_MINUTES 0x08 +#define ALM1_HOURS 0x09 +#define ALM1_DAYDATE 0x0A +#define ALM2_MINUTES 0x0B +#define ALM2_HOURS 0x0C +#define ALM2_DAYDATE 0x0D +#define RTC_CONTROL 0x0E +#define RTC_STATUS 0x0F +#define RTC_AGING 0x10 +#define TEMP_MSB 0x11 +#define TEMP_LSB 0x12 +#define SRAM_START_ADDR 0x14 //first SRAM address +#define SRAM_SIZE 236 //number of bytes of SRAM + +//Alarm mask bits +#define A1M1 7 +#define A1M2 7 +#define A1M3 7 +#define A1M4 7 +#define A2M2 7 +#define A2M3 7 +#define A2M4 7 + +//Control register bits +#define EOSC 7 +#define BBSQW 6 +#define CONV 5 +#define RS2 4 +#define RS1 3 +#define INTCN 2 +#define A2IE 1 +#define A1IE 0 + +//Status register bits +#define OSF 7 +#define BB32KHZ 6 +#define CRATE1 5 +#define CRATE0 4 +#define EN32KHZ 3 +#define BSY 2 +#define A2F 1 +#define A1F 0 + +//Square-wave output frequency (TS2, RS1 bits) +enum SQWAVE_FREQS_t {SQWAVE_1_HZ, SQWAVE_1024_HZ, SQWAVE_4096_HZ, SQWAVE_8192_HZ, SQWAVE_NONE}; + +//Alarm masks +enum ALARM_TYPES_t { + ALM1_EVERY_SECOND = 0x0F, + ALM1_MATCH_SECONDS = 0x0E, + ALM1_MATCH_MINUTES = 0x0C, //match minutes *and* seconds + ALM1_MATCH_HOURS = 0x08, //match hours *and* minutes, seconds + ALM1_MATCH_DATE = 0x00, //match date *and* hours, minutes, seconds + ALM1_MATCH_DAY = 0x10, //match day *and* hours, minutes, seconds + ALM2_EVERY_MINUTE = 0x8E, + ALM2_MATCH_MINUTES = 0x8C, //match minutes + ALM2_MATCH_HOURS = 0x88, //match hours *and* minutes + ALM2_MATCH_DATE = 0x80, //match date *and* hours, minutes + ALM2_MATCH_DAY = 0x90, //match day *and* hours, minutes +}; + +#define ALARM_1 1 //constants for calling functions +#define ALARM_2 2 + +//Other +#define DS1307_CH 7 //for DS1307 compatibility, Clock Halt bit in Seconds register +#define HR1224 6 //Hours register 12 or 24 hour mode (24 hour mode==0) +#define CENTURY 7 //Century bit in Month register +#define DYDT 6 //Day/Date flag bit in alarm Day/Date registers + +class DS3232RTC +{ + public: + DS3232RTC(); + static time_t get(void); + static byte set(time_t t); + static byte read(tmElements_t &tm); + static byte write(tmElements_t &tm); + byte writeRTC(byte addr, byte *values, byte nBytes); + byte writeRTC(byte addr, byte value); + byte readRTC(byte addr, byte *values, byte nBytes); + byte readRTC(byte addr); + void setAlarm(ALARM_TYPES_t alarmType, byte seconds, byte minutes, byte hours, byte daydate); + void setAlarm(ALARM_TYPES_t alarmType, byte minutes, byte hours, byte daydate); + void alarmInterrupt(byte alarmNumber, boolean alarmEnabled); + boolean alarm(byte alarmNumber); + void squareWave(SQWAVE_FREQS_t freq); + boolean oscStopped(void); + int temperature(void); + + private: + static uint8_t dec2bcd(uint8_t n); + static uint8_t bcd2dec(uint8_t n); +}; + +extern DS3232RTC RTC; + +#endif diff --git a/arduino_mcu/libraries/DS3232RTC/LICENSE.md b/arduino_mcu/libraries/DS3232RTC/LICENSE.md new file mode 100644 index 00000000..f8754942 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/LICENSE.md @@ -0,0 +1,8 @@ +# Arduino DS3232RTC Library v1.0 # +https://github.com/JChristensen/DS3232RTC +LICENSE file +Jack Christensen Mar 2013 + +![CC BY-SA](http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-sa.png) +## CC BY-SA ## +"Arduino DS3232RTC Library" by Jack Christensen is licensed under [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/). \ No newline at end of file diff --git a/arduino_mcu/libraries/DS3232RTC/ReadMe.md b/arduino_mcu/libraries/DS3232RTC/ReadMe.md new file mode 100644 index 00000000..3e13c6d9 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/ReadMe.md @@ -0,0 +1,345 @@ +# Arduino DS3232RTC Library v1.0 # +https://github.com/JChristensen/DS3232RTC +ReadMe file +Jack Christensen Mar 2013 + +![CC BY-SA](http://mirrors.creativecommons.org/presskit/buttons/80x15/png/by-sa.png) + +## Introduction ## +**DS3232RTC** is an Arduino library that supports the Maxim Integrated DS3232 and DS3231 Real-Time Clocks. This library is intended to be used with the [Arduino Time library](http://www.arduino.cc/playground/Code/Time). + +The **DS3232RTC** 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 DS323x RTC, it is only necessary to use `#include ` instead of `#include `. + +**DS3232RTC** also implements functions to support the additional features of the DS3232 and DS3231. The DS3231 has the same features as 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). + +"Arduino DS3232RTC Library" by Jack Christensen is licensed under CC BY-SA 4.0. + +## Installation ## +To use the **DS3232RTC** library: +- Go to https://github.com/JChristensen/DS3232RTC, click the **Download ZIP** button and save the ZIP file to a convenient location on your PC. +- Uncompress the downloaded file. This will result in a folder containing all the files for the library, that has a name that includes the branch name, usually **DS3232RTC-master**. +- Rename the folder to just **DS3232RTC**. +- Copy the renamed folder to the Arduino sketchbook\libraries folder. + +## Examples ## +The following example sketches are included with the **DS3232RTC** library: +- **SetSerial:** Set the RTC's date and time from the Arduino serial monitor. Displays date, time and temperature. +- **TimeRTC:** Same as the example of the same name provided with the **Time** library, demonstrating the interchangeability of the **DS3232RTC** library with the **DS1307RTC** library. +- **tiny3232_KnockBang:** Demonstrates interfacing an ATtiny45/85 to a DS3231 or DS3232 RTC. + +## Usage notes ## + +When using the **DS3232RTC** library, the user is responsible for ensuring that 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 the library. + +Similar to the **DS1307RTC** library, the **DS3232RTC** library instantiates an RTC object; the user does not need to do this. + +To use the **DS3232RTC** library, the Time and Wire libraries must also be included. For brevity, these includes are not repeated in the examples below: +```c++ +#include //http://github.com/JChristensen/DS3232RTC +#include //http://www.arduino.cc/playground/Code/Time +#include //http://arduino.cc/en/Reference/Wire (included with Arduino IDE) +``` + +## Enumerations ## +### SQWAVE_FREQS_t +##### Description +Symbolic names used with the squareWave() method (described below). +##### Values +- SQWAVE_NONE +- SQWAVE_1_HZ +- SQWAVE_1024_HZ +- SQWAVE_4096_HZ +- SQWAVE_8192_HZ + +### ALARM_TYPES_t +##### Description +Symbolic names used with the setAlarm() method (described below). +##### Values for Alarm 1 +- ALM1_EVERY_SECOND -- causes an alarm once per second. +- ALM1_MATCH_SECONDS -- causes an alarm when the seconds match (i.e. once per minute). +- ALM1_MATCH_MINUTES -- causes an alarm when the minutes *and* seconds match. +- ALM1_MATCH_HOURS -- causes an alarm when the hours *and* minutes *and* seconds match. +- ALM1_MATCH_DATE -- causes an alarm when the date of the month *and* hours *and* minutes *and* seconds match. +- ALM1_MATCH_DAY -- causes an alarm when the day of the week *and* hours *and* minutes *and* seconds match. + +##### Values for Alarm 2 +- ALM2_EVERY_MINUTE -- causes an alarm once per minute. +- ALM2_MATCH_MINUTES -- causes an alarm when the minutes match (i.e. once per hour). +- ALM2_MATCH_HOURS -- causes an alarm when the hours *and* minutes match. +- ALM2_MATCH_DATE -- causes an alarm when the date of the month *and* hours *and* minutes match. +- ALM2_MATCH_DAY -- causes an alarm when the day of the week *and* hours *and* minutes match. + + +## Methods for setting and reading the time ## + +###get(void) +#####Description +Reads the current date and time from the RTC and returns it as a *time_t* value. Returns zero if an I2C error occurs (RTC not present, etc.). +#####Syntax +`RTC.get();` +#####Parameters +None. +#####Returns +Current date and time *(time_t)* +#####Example +```c++ +time_t myTime; +myTime = RTC.get(); +``` + +###set(time_t t) +#####Description +Sets the RTC date and time to the given *time_t* value. +#####Syntax +`RTC.set(t);` +#####Parameters +**t:** The date and time to set the RTC to *(time_t)* +#####Returns +I2C status *(byte)*. Returns zero if successful. +#####Example +```c++ +//this example first sets the system time (maintained by the Time library) to +//a hard-coded date and time, and then sets the RTC from the system time. +//the setTime() function is part of the Time library. +setTime(23, 31, 30, 13, 2, 2009); //set the system time to 23h31m30s on 13Feb2009 +RTC.set(now()); //set the RTC from the system time +``` + +###read(tmElements_t &tm) +#####Description +Reads the current date and time from the RTC and returns it as a *tmElements_t* structure. See the [Arduino Time library](http://www.arduino.cc/playground/Code/Time) for details on the *tmElements_t* structure. +#####Syntax +`RTC.read(tm);` +#####Parameters +**tm:** Address of a *tmElements_t* structure to which the date and time are returned. +#####Returns +I2C status *(byte)*. Returns zero if successful. The date and time read from the RTC are returned to the **tm** parameter. +#####Example +```c++ +tmElements_t tm; +RTC.read(tm); +Serial.print(tm.Hour, DEC); +Serial.print(':'); +Serial.print(tm.Minute,DEC); +Serial.print(':'); +Serial.println(tm.Second,DEC); +``` + +###write(tmElements_t &tm) +#####Description +Sets the RTC to the date and time given by a *tmElements_t* structure. +#####Syntax +`RTC.write(tm);` +#####Parameters +**tm:** Address of a *tmElements_t* structure used to set the date and time. +#####Returns +I2C status *(byte)*. Returns zero if successful. +#####Example +```c++ +tmElements_t tm; +tm.Hour = 23; //set the tm structure to 23h31m30s on 13Feb2009 +tm.Minute = 31; +tm.Minute = 30; +tm.Day = 13; +tm.Month = 2; +tm.Year = 2009 - 1970; //tmElements_t.Year is the offset from 1970 +RTC.write(tm); //set the RTC from the tm structure +``` + +## Methods for reading and writing RTC registers or static RAM (SRAM) for the DS3232 ## +The DS3232RTC.h file defines symbolic names for the timekeeping, alarm, status and control registers. These can be used for the addr argument in the functions below. + +###writeRTC(byte addr, byte *values, byte nBytes) +#####Description +Write one or more bytes to RTC memory. +#####Syntax +`RTC.writeRTC(addr, values, nbytes);` +#####Parameters +**addr:** First SRAM address to write *(byte)*. The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library. +**values:** An array of values to write _(*byte)_ +**nBytes:** Number of bytes to write *(byte)*. Must be between 1 and 31 (Wire library limitation) but is not checked by the library. +#####Returns +I2C status *(byte)*. Returns zero if successful. +#####Example +```c++ +//write 1, 2, ..., 8 to the first eight DS3232 SRAM locations +byte buf[8] = {1, 2, 3, 4, 5, 6, 7, 8}; +RTC.sramWrite(0x14, buf, 8); +``` + +###writeRTC(byte addr, byte value) +#####Description +Write a single byte to RTC memory. +#####Syntax +`RTC.writeRTC(addr, value);` +#####Parameters +**addr:** SRAM address to write *(byte)*. The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library. +**value:** Value to write _(byte)_ +#####Returns +I2C status *(byte)*. Returns zero if successful. +#####Example +```c++ +RTC.writeRTC(3, 14); //write the value 14 to SRAM address 3 +``` + +###readRTC(byte addr, byte *values, byte nBytes) +#####Description +Read one or more bytes from RTC RAM. +#####Syntax +`RTC.readRTC(addr, values, nbytes);` +#####Parameters +**addr:** First SRAM address to read *(byte)*. The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library. +**values:** An array to receive the values read _(*byte)_ +**nBytes:** Number of bytes to read *(byte)*. Must be between 1 and 32 (Wire library limitation) but is not checked by the library. +#####Returns +I2C status *(byte)*. Returns zero if successful. +#####Example +```c++ +//read the last eight locations of SRAM into buf +byte buf[8]; +RTC.sramRead(248, buf, 8); +``` + +###readRTC(byte addr) +#####Description +Reads a single byte from RTC RAM. +#####Syntax +`RTC.readRTC(addr);` +#####Parameters +**addr:** SRAM address to read *(byte)*. The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library. +#####Returns +Value read from the RTC *(byte)* +#####Example +```c++ +byte val; +val = RTC.readRTC(3); //read the value from SRAM location 3 +``` + +## Alarm methods ## +The DS3232 and DS3231 have two alarms. Alarm1 can be set to seconds precision; Alarm2 can only be set to minutes precision. + +###setAlarm(ALARM_TYPES_t alarmType, byte seconds, byte minutes, byte hours, byte daydate) +#####Description +Set an alarm time. Sets the alarm registers only. To cause the INT pin to be asserted on alarm match, use alarmInterrupt(). This method can set either Alarm 1 or Alarm 2, depending on the value of alarmType (use the ALARM_TYPES_t enumeration above). When setting Alarm 2, the seconds value must be supplied but is ignored, recommend using zero. (Alarm 2 has no seconds register.) + +#####Syntax +`RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate);` +#####Parameters +**alarmType:** A value from the ALARM_TYPES_t enumeration, above. *(ALARM_TYPES_t)* +**seconds:** The seconds value to set the alarm to. *(byte)* +**minutes:** The minutes value to set the alarm to. *(byte)* +**hours:** The hours value to set the alarm to. *(byte)* +**dayOrDate:** The day of the week or the date of the month. For day of the week, use a value from the Time library timeDayOfWeek_t enumeration, i.e. dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday. *(byte)* +#####Returns +None. +#####Example +```c++ +//Set Alarm1 for 12:34:56 on Sunday +RTC.setAlarm(ALM1_MATCH_DAY, 56, 34, 12, dowSunday); +``` + +###setAlarm(ALARM_TYPES_t alarmType, byte minutes, byte hours, byte daydate) +#####Description +Set an alarm time. Sets the alarm registers only. To cause the INT pin to be asserted on alarm match, use alarmInterrupt(). This method can set either Alarm 1 or Alarm 2, depending on the value of alarmType (use the ALARM_TYPES_t enumeration above). However, when using this method to set Alarm 1, the seconds value is set to zero. (Alarm 2 has no seconds register.) + +#####Syntax +`RTC.setAlarm(alarmType, minutes, hours, dayOrDate);` +#####Parameters +**alarmType:** A value from the ALARM_TYPES_t enumeration, above. *(ALARM_TYPES_t)* +**minutes:** The minutes value to set the alarm to. *(byte)* +**hours:** The hours value to set the alarm to. *(byte)* +**dayOrDate:** The day of the week or the date of the month. For day of the week, use a value from the Time library timeDayOfWeek_t enumeration, i.e. dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday. *(byte)* +#####Returns +None. +#####Example +```c++ +//Set Alarm2 for 12:34 on the 4th day of the month +RTC.setAlarm(ALM1_MATCH_DATE, 34, 12, 4); +``` + +###alarmInterrupt(byte alarmNumber, boolean alarmEnabled) +#####Description +Enable or disable an alarm "interrupt". Note that this "interrupt" causes the RTC's INT pin to be asserted. To use this signal as an actual interrupt to a microcontroller, it will need to be connected properly and programmed in the application firmware. +on the RTC. +#####Syntax +`RTC.alarmInterrupt(alarmNumber, enable);` +#####Parameters +**alarmNumber:** The number of the alarm to enable or disable, ALARM_1 or ALARM_2 *(byte)* +**alarmEnabled:** true or false *(boolean)* +#####Returns +None. +#####Example +```c++ +RTC.alarmInterrupt(ALARM_1, true); //assert the INT pin when Alarm1 occurs. +RTC.alarmInterrupt(ALARM_2, false); //disable Alarm2 +``` + +###alarm(byte alarmNumber) +#####Description +Tests whether an alarm has been triggered. If the alarm was triggered, returns true and resets the alarm flag in the RTC, else returns false. +#####Syntax +`RTC.alarm(alarmNumber);` +#####Parameters +**alarmNumber:** The number of the alarm to test, ALARM_1 or ALARM_2 *(byte)* +#####Returns +Description *(type)* +#####Example +```c++ +if ( RTC.alarm(ALARM_1) ) { //has Alarm1 triggered? + //yes, act on the alarm +} +else { + //no alarm +} +``` + +## Other methods ## +###temperature(void) +#####Description +Returns the RTC temperature. +#####Syntax +`RTC.temperature();` +#####Parameters +None. +#####Returns +RTC temperature as degrees Celsius times four. *(int)* +#####Example +```c++ +int t = RTC.temperature(); +float celsius = t / 4.0; +float fahrenheit = celsius * 9.0 / 5.0 + 32.0; +``` + +###squareWave(SQWAVE_FREQS_t freq) +#####Description +Enables or disables the square wave output. +#####Syntax +`RTC.squareWave(freq);` +#####Parameters +**freq:** a value from the SQWAVE_FREQS_t enumeration above. *(SQWAVE_FREQS_t)* +#####Returns +None. +#####Example +```c++ +RTC.squareWave(SQWAVE_1_HZ); //1 Hz square wave +RTC.squareWave(SQWAVE_NONE); //no square wave +``` + +###oscStopped(void) +#####Description +Check whether the RTC oscillator is or was stopped. This may indicate that the RTC's time is not accurate. +#####Syntax +`RTC.oscStopped();` +#####Parameters +None. +#####Returns +True or false *(boolean)* +#####Example +```c++ +if ( RTC.oscStopped() ) { //check the oscillator + //may be trouble +} +else { + //all is well +} +``` \ No newline at end of file diff --git a/arduino_mcu/libraries/DS3232RTC/examples/SetSerial/SetSerial.ino b/arduino_mcu/libraries/DS3232RTC/examples/SetSerial/SetSerial.ino new file mode 100644 index 00000000..af03b528 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/examples/SetSerial/SetSerial.ino @@ -0,0 +1,132 @@ +/*----------------------------------------------------------------------* + * Display the date and time from a DS3231 or DS3232 RTC every second. * + * Display the temperature once per minute. (The DS3231 does a * + * temperature conversion once every 64 seconds. This is also the * + * default for the DS3232.) * + * * + * Set the date and time by entering the following on the Arduino * + * serial monitor: * + * year,month,day,hour,minute,second, * + * * + * Where * + * year can be two or four digits, * + * month is 1-12, * + * day is 1-31, * + * hour is 0-23, and * + * minute and second are 0-59. * + * * + * Entering the final comma delimiter (after "second") will avoid a * + * one-second timeout and will allow the RTC to be set more accurately. * + * * + * No validity checking is done, invalid values or incomplete syntax * + * in the input will result in an incorrect RTC setting. * + * * + * Jack Christensen 08Aug2013 * + * * + * Tested with Arduino 1.0.5, Arduino Uno, DS3231/Chronodot, DS3232. * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 171 Second Street, Suite 300, * + * San Francisco, California, 94105, USA. * + *----------------------------------------------------------------------*/ + +#include //http://github.com/JChristensen/DS3232RTC +#include //http://arduiniana.org/libraries/streaming/ +#include //http://playground.arduino.cc/Code/Time +#include //http://arduino.cc/en/Reference/Wire + +void setup(void) +{ + Serial.begin(115200); + + //setSyncProvider() causes the Time library to synchronize with the + //external RTC by calling RTC.get() every five minutes by default. + setSyncProvider(RTC.get); + Serial << F("RTC Sync"); + if (timeStatus() != timeSet) Serial << F(" FAIL!"); + Serial << endl; +} + +void loop(void) +{ + static time_t tLast; + time_t t; + tmElements_t tm; + + //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s + if (Serial.available() >= 12) { + //note that the tmElements_t Year member is an offset from 1970, + //but the RTC wants the last two digits of the calendar year. + //use the convenience macros from Time.h to do the conversions. + int y = Serial.parseInt(); + if (y >= 100 && y < 1000) + Serial << F("Error: Year must be two digits or four digits!") << endl; + else { + if (y >= 1000) + tm.Year = CalendarYrToTm(y); + else //(y < 100) + tm.Year = y2kYearToTm(y); + tm.Month = Serial.parseInt(); + tm.Day = Serial.parseInt(); + tm.Hour = Serial.parseInt(); + tm.Minute = Serial.parseInt(); + tm.Second = Serial.parseInt(); + t = makeTime(tm); + RTC.set(t); //use the time_t value to ensure correct weekday is set + setTime(t); + Serial << F("RTC set to: "); + printDateTime(t); + Serial << endl; + //dump any extraneous input + while (Serial.available() > 0) Serial.read(); + } + } + + t = now(); + if (t != tLast) { + tLast = t; + printDateTime(t); + if (second(t) == 0) { + float c = RTC.temperature() / 4.; + float f = c * 9. / 5. + 32.; + Serial << F(" ") << c << F(" C ") << f << F(" F"); + } + Serial << endl; + } +} + +//print date and time to Serial +void printDateTime(time_t t) +{ + printDate(t); + Serial << ' '; + printTime(t); +} + +//print time to Serial +void printTime(time_t t) +{ + printI00(hour(t), ':'); + printI00(minute(t), ':'); + printI00(second(t), ' '); +} + +//print date to Serial +void printDate(time_t t) +{ + printI00(day(t), 0); + Serial << monthShortStr(month(t)) << _DEC(year(t)); +} + +//Print an integer in "00" format (with leading zero), +//followed by a delimiter character to Serial. +//Input value assumed to be between 0 and 99. +void printI00(int val, char delim) +{ + if (val < 10) Serial << '0'; + Serial << _DEC(val); + if (delim > 0) Serial << delim; + return; +} \ No newline at end of file diff --git a/arduino_mcu/libraries/DS3232RTC/examples/TimeRTC/TimeRTC.ino b/arduino_mcu/libraries/DS3232RTC/examples/TimeRTC/TimeRTC.ino new file mode 100644 index 00000000..1145bf29 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/examples/TimeRTC/TimeRTC.ino @@ -0,0 +1,50 @@ +/* + * TimeRTC.pde + * Example code illustrating Time library with Real Time Clock. + * This example is identical to the example provided with the Time Library, + * only the #include statement has been changed to include the DS3232RTC library. + */ + +#include //http://github.com/JChristensen/DS3232RTC +#include //http://www.arduino.cc/playground/Code/Time +#include //http://arduino.cc/en/Reference/Wire (included with Arduino IDE) + +void setup(void) +{ + Serial.begin(9600); + setSyncProvider(RTC.get); // the function to get the time from the RTC + if(timeStatus() != timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +void loop(void) +{ + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay(void) +{ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(' '); + Serial.print(day()); + Serial.print(' '); + Serial.print(month()); + Serial.print(' '); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits) +{ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(':'); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} diff --git a/arduino_mcu/libraries/DS3232RTC/examples/tiny3232_KnockBang/tiny3232_KnockBang.ino b/arduino_mcu/libraries/DS3232RTC/examples/tiny3232_KnockBang/tiny3232_KnockBang.ino new file mode 100644 index 00000000..e54924e2 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/examples/tiny3232_KnockBang/tiny3232_KnockBang.ino @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------* + * Digital clock display using a DS3231/32 Real-Time Clock * + * and an ATtiny45/85 with a 1MHz system clock. * + * Also seems to work with a DS1307 which is fairly similar but the * + * DS3232RTC library doesn't officially support it. * + * * + * Tested with Arduino 1.0.5. Also Arduino-Tiny Core, TinyISP, and * + * TinyDebugKnockBang from http://code.google.com/p/arduino-tiny/ * + * * + * Run TinyISP on an ATmega microcontroller that does not have an LED * + * connected to pin 13 (SCK). The LED causes problems because the SPI * + * pins are also the I2C pins on the ATtiny. Connect MISO, MOSI, SCK * + * on the ATmega to the corresponding pins on the ATtiny through 220Ω * + * resistors for safety. Use 4.7K pullup resistors on the ATtiny * + * I2C bus. * + * * + * Jack Christensen 21Aug2013 * + * * + * This work is licensed under the Creative Commons Attribution- * + * ShareAlike 3.0 Unported License. To view a copy of this license, * + * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * + * letter to Creative Commons, 171 Second Street, Suite 300, * + * San Francisco, California, 94105, USA. * + *----------------------------------------------------------------------*/ + +#include //http://github.com/JChristensen/DS3232RTC +#include //http://playground.arduino.cc/Code/Time +#include //http://code.google.com/p/arduino-tiny/ +#include //http://playground.arduino.cc/Code/USIi2c + +void setup(void) +{ + Debug.begin(250000); + + //setSyncProvider() causes the Time library to synchronize with the + //external RTC by calling RTC.get() every five minutes by default. + setSyncProvider(RTC.get); + Debug.print(F("RTC Sync")); + if (timeStatus() != timeSet) Debug.print(F(" FAIL!")); + Debug.println(); +} + +void loop(void) +{ + static time_t tLast; + + time_t t = now(); + if (t != tLast) { + tLast = t; + printDateTime(t); + Debug.println(); + } +} + +//print date and time to Serial +void printDateTime(time_t t) +{ + printDate(t); + Debug.print(' '); + printTime(t); +} + +//print time to Serial +void printTime(time_t t) +{ + printI00(hour(t), ':'); + printI00(minute(t), ':'); + printI00(second(t), ' '); +} + +//print date to Serial +void printDate(time_t t) +{ + printI00(day(t), 0); + Debug.print(monthShortStr(month(t))); + Debug.print(year(t), DEC); +} + +//Print an integer in "00" format (with leading zero), +//followed by a delimiter character to Serial. +//Input value assumed to be between 0 and 99. +void printI00(int val, char delim) +{ + if (val < 10) Debug.print('0'); + Debug.print(val, DEC);; + if (delim > 0) Debug.print(delim); + return; +} diff --git a/arduino_mcu/libraries/DS3232RTC/keywords.txt b/arduino_mcu/libraries/DS3232RTC/keywords.txt new file mode 100644 index 00000000..22e5dd73 --- /dev/null +++ b/arduino_mcu/libraries/DS3232RTC/keywords.txt @@ -0,0 +1,13 @@ +DS3232RTC KEYWORD1 +get KEYWORD2 +set KEYWORD2 +read KEYWORD2 +write KEYWORD2 +writeRTC KEYWORD2 +readRTC KEYWORD2 +setAlarm KEYWORD2 +alarmInterrupt KEYWORD2 +alarm KEYWORD2 +squareWave KEYWORD2 +oscStopped KEYWORD2 +temperature KEYWORD2 diff --git a/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.cpp b/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.cpp new file mode 100644 index 00000000..dd9b64b0 --- /dev/null +++ b/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.cpp @@ -0,0 +1,212 @@ +// +// FILE: I2C_eeprom.cpp +// AUTHOR: Rob Tillaart +// VERSION: 1.0.05 +// PURPOSE: Simple I2C_eeprom library for Arduino with EEPROM 24LC256 et al. +// +// HISTORY: +// 0.1.00 - 2011-01-21 initial version +// 0.1.01 - 2011-02-07 added setBlock function +// 0.2.00 - 2011-02-11 fixed 64 bit boundary bug +// 0.2.01 - 2011-08-13 _readBlock made more robust + return value +// 1.0.00 - 2013-06-09 support for Arduino 1.0.x +// 1.0.01 - 2013-11-01 fixed writeBlock bug, refactor +// 1.0.02 - 2013-11-03 optimize internal buffers, refactor +// 1.0.03 - 2013-11-03 refactor 5 millis() write-latency +// 1.0.04 - 2013-11-03 fix bug in readBlock, moved waitEEReady() -> more efficient. +// 1.0.05 - 2013-11-06 improved waitEEReady(), added determineSize() +// +// Released to the public domain +// + +#include + +I2C_eeprom::I2C_eeprom(uint8_t device) +{ + _deviceAddress = device; + Wire.begin(); + _lastWrite = 0; + TWBR = 12; // 12=400Khz 32=200 72=100 152=50 F_CPU/16+(2*TWBR) +} + +int I2C_eeprom::writeByte(uint16_t address, uint8_t data) +{ + int rv = _WriteBlock(address, &data, 1); + return rv; +} + +int I2C_eeprom::setBlock(uint16_t address, uint8_t data, uint16_t length) +{ + uint8_t buffer[I2C_TWIBUFFERSIZE]; + for (uint8_t i =0; i< I2C_TWIBUFFERSIZE; i++) buffer[i] = data; + + int rv = _pageBlock(address, buffer, length, false); // todo check return value.. + return rv; +} + +int I2C_eeprom::writeBlock(uint16_t address, uint8_t* buffer, uint16_t length) +{ + int rv = _pageBlock(address, buffer, length, true); // todo check return value.. + return rv; +} + +uint8_t I2C_eeprom::readByte(uint16_t address) +{ + uint8_t rdata; + _ReadBlock(address, &rdata, 1); + return rdata; +} + +uint16_t I2C_eeprom::readBlock(uint16_t address, uint8_t* buffer, uint16_t length) +{ + uint16_t rv = 0; + while (length > 0) + { + uint8_t cnt = min(length, I2C_TWIBUFFERSIZE); + rv += _ReadBlock(address, buffer, cnt); + address += cnt; + buffer += cnt; + length -= cnt; + } + return rv; +} + +#ifdef I2C_EEPROM_EXTENDED +// returns 64, 32, 16, 8, 4, 2, 1, 0 +// 0 is smaller than 1K +uint8_t I2C_eeprom::determineSize() +{ + uint8_t rv = 0; // unknown + uint8_t orgValues[8]; + uint16_t addr; + + // remember old values, non destructive + for (uint8_t i=0; i<8; i++) + { + addr = (512 << i) + 1; + orgValues[i] = readByte(addr); + } + + // scan page folding + for (uint8_t i=0; i<8; i++) + { + rv = i; + uint16_t addr1 = (512 << i) + 1; + uint16_t addr2 = (512 << (i+1)) + 1; + writeByte(addr1, 0xAA); + writeByte(addr2, 0x55); + if (readByte(addr1) == 0x55) // folded! + { + break; + } + } + + // restore original values + for (uint8_t i=0; i<8; i++) + { + uint16_t addr = (512 << i) + 1; + writeByte(addr, orgValues[i]); + } + return 0x01 << (rv-1); +} +#endif + +//////////////////////////////////////////////////////////////////// +// +// PRIVATE +// + +// _pageBlock aligns buffer to page boundaries for writing. +// and to TWI buffer size +// returns 0 = OK otherwise error +int I2C_eeprom::_pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer) +{ + int rv = 0; + while (length > 0) + { + uint8_t bytesUntilPageBoundary = I2C_EEPROM_PAGESIZE - address%I2C_EEPROM_PAGESIZE; + uint8_t cnt = min(length, bytesUntilPageBoundary); + cnt = min(cnt, I2C_TWIBUFFERSIZE); + + int rv = _WriteBlock(address, buffer, cnt); // todo check return value.. + if (rv != 0) return rv; + + address += cnt; + if (incrBuffer) buffer += cnt; + length -= cnt; + } + return rv; +} + +// pre: length <= I2C_EEPROM_PAGESIZE && length <= I2C_TWIBUFFERSIZE; +// returns 0 = OK otherwise error +int I2C_eeprom::_WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length) +{ + waitEEReady(); + + Wire.beginTransmission(_deviceAddress); +#if defined(ARDUINO) && ARDUINO >= 100 + Wire.write((int)(address >> 8)); + Wire.write((int)(address & 0xFF)); + for (uint8_t cnt = 0; cnt < length; cnt++) + Wire.write(buffer[cnt]); +#else + Wire.send((int)(address >> 8)); + Wire.send((int)(address & 0xFF)); + for (uint8_t cnt = 0; cnt < length; cnt++) + Wire.send(buffer[cnt]); +#endif + int rv = Wire.endTransmission(); + _lastWrite = micros(); + return rv; +} + +// pre: buffer is large enough to hold length bytes +// returns bytes written +uint8_t I2C_eeprom::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length) +{ + waitEEReady(); + + Wire.beginTransmission(_deviceAddress); +#if defined(ARDUINO) && ARDUINO >= 100 + Wire.write((int)(address >> 8)); + Wire.write((int)(address & 0xFF)); +#else + Wire.send((int)(address >> 8)); + Wire.send((int)(address & 0xFF)); +#endif + int rv = Wire.endTransmission(); + if (rv != 0) return 0; // error + + Wire.requestFrom(_deviceAddress, length); + uint8_t cnt = 0; + uint32_t before = millis(); + while ((cnt < length) && ((millis() - before) < I2C_EEPROM_TIMEOUT)) + { +#if defined(ARDUINO) && ARDUINO >= 100 + if (Wire.available()) buffer[cnt++] = Wire.read(); +#else + if (Wire.available()) buffer[cnt++] = Wire.receive(); +#endif + } + return cnt; +} + +void I2C_eeprom::waitEEReady() +{ +#define I2C_WRITEDELAY 5000 + + // Wait until EEPROM gives ACK again. + // this is a bit faster than the hardcoded 5 milli + while ((micros() - _lastWrite) <= I2C_WRITEDELAY) + { + Wire.beginTransmission(_deviceAddress); + int x = Wire.endTransmission(); + if (x == 0) break; + } +} + +// +// END OF FILE +// + diff --git a/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.h b/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.h new file mode 100644 index 00000000..d247c7c7 --- /dev/null +++ b/arduino_mcu/libraries/I2C_eeprom/I2C_eeprom.h @@ -0,0 +1,67 @@ +#ifndef I2C_EEPROM_H +#define I2C_EEPROM_H +// +// FILE: I2C_eeprom.h +// AUTHOR: Rob Tillaart +// PURPOSE: Simple I2C_eeprom library for Arduino with EEPROM 24LC256 et al. +// VERSION: 1.0.05 +// HISTORY: See I2C_eeprom.cpp +// URL: http://arduino.cc/playground/Main/LibraryForI2CEEPROM +// +// Released to the public domain +// + +#include + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#include "Wstring.h" +#include "Wiring.h" +#endif + +#define I2C_EEPROM_VERSION "1.0.05" + +// I2C_EEPROM_PAGESIZE must be multiple of 2 e.g. 16, 32 or 64 +// 24LC256 -> 64 bytes +#define I2C_EEPROM_PAGESIZE 64 + +// TWI buffer needs max 2 bytes for address +#define I2C_TWIBUFFERSIZE 30 + +// to break blocking read/write +#define I2C_EEPROM_TIMEOUT 1000 + +// comment next line to keep lib small +#define I2C_EEPROM_EXTENDED + +class I2C_eeprom +{ +public: + I2C_eeprom(uint8_t deviceAddress); + + int writeByte(uint16_t address, uint8_t value); + int writeBlock(uint16_t address, uint8_t* buffer, uint16_t length); + int setBlock(uint16_t address, uint8_t value, uint16_t length); + + uint8_t readByte(uint16_t address); + uint16_t readBlock(uint16_t address, uint8_t* buffer, uint16_t length); + +#ifdef I2C_EEPROM_EXTENDED + uint8_t determineSize(); +#endif + +private: + uint8_t _deviceAddress; + uint32_t _lastWrite; // for waitEEReady + + int _pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer); + int _WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length); + uint8_t _ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length); + + void waitEEReady(); +}; + +#endif +// END OF FILE diff --git a/arduino_mcu/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino b/arduino_mcu/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino new file mode 100644 index 00000000..e93072d5 --- /dev/null +++ b/arduino_mcu/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino @@ -0,0 +1,31 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +void setup() +{ + // No setup is required for this library +} + +void loop() +{ + // Enter idle state for 8 s with the rest of peripherals turned off + // Each microcontroller comes with different number of peripherals + // Comment off line of code where necessary + + // ATmega328P, ATmega168 + LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, + SPI_OFF, USART0_OFF, TWI_OFF); + + // ATmega32U4 + //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER4_OFF, TIMER3_OFF, TIMER1_OFF, + // TIMER0_OFF, SPI_OFF, USART1_OFF, TWI_OFF, USB_OFF); + + // ATmega2560 + //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF, + // TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART3_OFF, + // USART2_OFF, USART1_OFF, USART0_OFF, TWI_OFF); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} + diff --git a/arduino_mcu/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino b/arduino_mcu/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino new file mode 100644 index 00000000..f914bd69 --- /dev/null +++ b/arduino_mcu/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino @@ -0,0 +1,33 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +// Use pin 2 as wake up pin +const int wakeUpPin = 2; + +void wakeUp() +{ + // Just a handler for the pin interrupt. +} + +void setup() +{ + // Configure wake up pin as input. + // This will consumes few uA of current. + pinMode(wakeUpPin, INPUT); +} + +void loop() +{ + // Allow wake up pin to trigger interrupt on low. + attachInterrupt(0, wakeUp, LOW); + + // Enter power down state with ADC and BOD module disabled. + // Wake up when wake up pin is low. + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + + // Disable external pin interrupt on wake up pin. + detachInterrupt(0); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} diff --git a/arduino_mcu/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino b/arduino_mcu/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino new file mode 100644 index 00000000..bce822ad --- /dev/null +++ b/arduino_mcu/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino @@ -0,0 +1,16 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +void setup() +{ + // No setup is required for this library +} + +void loop() +{ + // Enter power down state for 8 s with ADC and BOD module disabled + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} diff --git a/arduino_mcu/libraries/LowPower/LowPower.cpp b/arduino_mcu/libraries/LowPower/LowPower.cpp new file mode 100644 index 00000000..a72cc310 --- /dev/null +++ b/arduino_mcu/libraries/LowPower/LowPower.cpp @@ -0,0 +1,856 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.30 +* Date: 22-05-2013 +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. Please check our wiki +* (www.rocketscream.com/wiki) for more information on using this piece of +* library. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#include +#include +#include +#include +#include "LowPower.h" + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 +* is replaced with USART1 on ATmega32U4. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::idle(period_t period, adc_t adc, + timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart1_t usart1, twi_t twi, usb_t usb) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #endif +} + +/******************************************************************************* +* Name: powerDown +* Description: Putting microcontroller into power down state. This is +* the lowest current consumption state. Use this together with +* external pin interrupt to wake up through external event +* triggering (example: RTC clockout pin, SD card detect pin). +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_DOWN); + #else + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerSave +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerStandby(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +LowPowerClass LowPower; \ No newline at end of file diff --git a/arduino_mcu/libraries/LowPower/LowPower.h b/arduino_mcu/libraries/LowPower/LowPower.h new file mode 100644 index 00000000..ef059012 --- /dev/null +++ b/arduino_mcu/libraries/LowPower/LowPower.h @@ -0,0 +1,137 @@ +#ifndef LowPower_h +#define LowPower_h + +enum period_t +{ + SLEEP_15Ms, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +class LowPowerClass +{ + public: + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + void idle(period_t period, adc_t adc, timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, twi_t twi, usb_t usb); + #else + #error "Please ensure chosen MCU is either 328P, 32U4 or 2560." + #endif + void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2); + void powerDown(period_t period, adc_t adc, bod_t bod); + void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2); + void powerStandby(period_t period, adc_t adc, bod_t bod); + void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2); +}; + +extern LowPowerClass LowPower; +#endif \ No newline at end of file diff --git a/arduino_mcu/libraries/LowPower/keywords.txt b/arduino_mcu/libraries/LowPower/keywords.txt new file mode 100644 index 00000000..ef2461c6 --- /dev/null +++ b/arduino_mcu/libraries/LowPower/keywords.txt @@ -0,0 +1,68 @@ +####################################### +# Syntax Coloring Map LowPower +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +idle KEYWORD2 +adcNoiseReduction KEYWORD2 +powerDown KEYWORD2 +powerSave KEYWORD2 +powerStandby KEYWORD2 +powerExtStandby KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +LowPower KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +SLEEP_15MS LITERAL1 +SLEEP_30MS LITERAL1 +SLEEP_60MS LITERAL1 +SLEEP_120MS LITERAL1 +SLEEP_250MS LITERAL1 +SLEEP_500MS LITERAL1 +SLEEP_1S LITERAL1 +SLEEP_2S LITERAL1 +SLEEP_4S LITERAL1 +SLEEP_8S LITERAL1 +SLEEP_FOREVER LITERAL1 +ADC_OFF LITERAL1 +ADC_ON LITERAL1 +BOD_OFF LITERAL1 +BOD_ON LITERAL1 +TIMER4_OFF LITERAL1 +TIMER4_ON LITERAL1 +TIMER3_OFF LITERAL1 +TIMER3_ON LITERAL1 +TIMER2_OFF LITERAL1 +TIMER2_ON LITERAL1 +TIMER1_OFF LITERAL1 +TIMER1_ON LITERAL1 +TIMER0_OFF LITERAL1 +TIMER0_ON LITERAL1 +USART3_OFF LITERAL1 +USART3_ON LITERAL1 +USART2_OFF LITERAL1 +USART2_ON LITERAL1 +USART1_OFF LITERAL1 +USART1_ON LITERAL1 +USART0_OFF LITERAL1 +USART0_ON LITERAL1 +SPI_OFF LITERAL1 +SPI_ON LITERAL1 +TWI_OFF LITERAL1 +TWI_ON LITERAL1 +USB_OFF LITERAL1 +USB_ON LITERAL1 \ No newline at end of file diff --git a/arduino_mcu/libraries/RunningMedian/RunningMedian.h b/arduino_mcu/libraries/RunningMedian/RunningMedian.h new file mode 100644 index 00000000..0f944fd7 --- /dev/null +++ b/arduino_mcu/libraries/RunningMedian/RunningMedian.h @@ -0,0 +1,129 @@ +#ifndef RunningMedian_h +#define RunningMedian_h +// +// FILE: RunningMedian.h +// AUTHOR: Rob dot Tillaart at gmail dot com +// PURPOSE: RunningMedian library for Arduino +// VERSION: 0.2.00 - template edition +// URL: http://arduino.cc/playground/Main/RunningMedian +// HISTORY: 0.2.00 first template version by Ronny +// 0.2.01 added getAverage(uint8_t nMedians, float val) +// +// Released to the public domain +// + +#include + +template class RunningMedian { + +public: + + enum STATUS {OK = 0, NOK = 1}; + + RunningMedian() { + _size = N; + clear(); + }; + + void clear() { + _cnt = 0; + _idx = 0; + }; + + void add(T value) { + _ar[_idx++] = value; + if (_idx >= _size) _idx = 0; // wrap around + if (_cnt < _size) _cnt++; + }; + + STATUS getMedian(T& value) { + if (_cnt > 0) { + sort(); + value = _as[_cnt/2]; + return OK; + } + return NOK; + }; + + STATUS getAverage(float &value) { + if (_cnt > 0) { + float sum = 0; + for (uint8_t i=0; i< _cnt; i++) sum += _ar[i]; + value = sum / _cnt; + return OK; + } + return NOK; + }; + + STATUS getAverage(uint8_t nMedians, float &value) { + if ((_cnt > 0) && (nMedians > 0)) + { + if (_cnt < nMedians) nMedians = _cnt; // when filling the array for first time + uint8_t start = ((_cnt - nMedians)/2); + uint8_t stop = start + nMedians; + sort(); + float sum = 0; + for (uint8_t i = start; i < stop; i++) sum += _as[i]; + value = sum / nMedians; + return OK; + } + return NOK; + } + + STATUS getHighest(T& value) { + if (_cnt > 0) { + sort(); + value = _as[_cnt-1]; + return OK; + } + return NOK; + }; + + STATUS getLowest(T& value) { + if (_cnt > 0) { + sort(); + value = _as[0]; + return OK; + } + return NOK; + }; + + unsigned getSize() { + return _size; + }; + + unsigned getCount() { + return _cnt; + } + + STATUS getStatus() { + return (_cnt > 0 ? OK : NOK); + }; + +private: + uint8_t _size; + uint8_t _cnt; + uint8_t _idx; + T _ar[N]; + T _as[N]; + void sort() { + // copy + for (uint8_t i=0; i< _cnt; i++) _as[i] = _ar[i]; + + // sort all + for (uint8_t i=0; i< _cnt-1; i++) { + uint8_t m = i; + for (uint8_t j=i+1; j< _cnt; j++) { + if (_as[j] < _as[m]) m = j; + } + if (m != i) { + T t = _as[m]; + _as[m] = _as[i]; + _as[i] = t; + } + } + }; +}; + +#endif +// --- END OF FILE --- diff --git a/arduino_mcu/libraries/Time/DateStrings.cpp b/arduino_mcu/libraries/Time/DateStrings.cpp new file mode 100644 index 00000000..48d55cf9 --- /dev/null +++ b/arduino_mcu/libraries/Time/DateStrings.cpp @@ -0,0 +1,97 @@ +/* DateStrings.cpp + * Definitions for date strings for use with the Time library + * + * Updated for Arduino 1.5.7 18 July 2014 + * + * No memory is consumed in the sketch if your code does not call any of the string methods + * You can change the text of the strings, make sure the short strings are each exactly 3 characters + * the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in Time.h + * + */ + +#if defined(__AVR__) +#include +#else +// for compatiblity with Arduino Due and Teensy 3.0 and maybe others? +#define PROGMEM +#define PGM_P const char * +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#define pgm_read_word(addr) (*(const unsigned char **)(addr)) +#define strcpy_P(dest, src) strcpy((dest), (src)) +#endif +#include // for strcpy_P or strcpy +#include "Time.h" + +// the short strings for each day or month must be exactly dt_SHORT_STR_LEN +#define dt_SHORT_STR_LEN 3 // the length of short strings + +static char buffer[dt_MAX_STRING_LEN+1]; // must be big enough for longest string and the terminating null + +const char monthStr0[] PROGMEM = ""; +const char monthStr1[] PROGMEM = "January"; +const char monthStr2[] PROGMEM = "February"; +const char monthStr3[] PROGMEM = "March"; +const char monthStr4[] PROGMEM = "April"; +const char monthStr5[] PROGMEM = "May"; +const char monthStr6[] PROGMEM = "June"; +const char monthStr7[] PROGMEM = "July"; +const char monthStr8[] PROGMEM = "August"; +const char monthStr9[] PROGMEM = "September"; +const char monthStr10[] PROGMEM = "October"; +const char monthStr11[] PROGMEM = "November"; +const char monthStr12[] PROGMEM = "December"; + +const PROGMEM char * const PROGMEM monthNames_P[] = +{ + monthStr0,monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6, + monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12 +}; + +const char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec"; + +const char dayStr0[] PROGMEM = "Err"; +const char dayStr1[] PROGMEM = "Sunday"; +const char dayStr2[] PROGMEM = "Monday"; +const char dayStr3[] PROGMEM = "Tuesday"; +const char dayStr4[] PROGMEM = "Wednesday"; +const char dayStr5[] PROGMEM = "Thursday"; +const char dayStr6[] PROGMEM = "Friday"; +const char dayStr7[] PROGMEM = "Saturday"; + +const PROGMEM char * const PROGMEM dayNames_P[] = +{ + dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7 +}; + +const char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat"; + +/* functions to return date strings */ + +char* monthStr(uint8_t month) +{ + strcpy_P(buffer, (PGM_P)pgm_read_word(&(monthNames_P[month]))); + return buffer; +} + +char* monthShortStr(uint8_t month) +{ + for (int i=0; i < dt_SHORT_STR_LEN; i++) + buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)])); + buffer[dt_SHORT_STR_LEN] = 0; + return buffer; +} + +char* dayStr(uint8_t day) +{ + strcpy_P(buffer, (PGM_P)pgm_read_word(&(dayNames_P[day]))); + return buffer; +} + +char* dayShortStr(uint8_t day) +{ + uint8_t index = day*dt_SHORT_STR_LEN; + for (int i=0; i < dt_SHORT_STR_LEN; i++) + buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i])); + buffer[dt_SHORT_STR_LEN] = 0; + return buffer; +} diff --git a/arduino_mcu/libraries/Time/Readme.txt b/arduino_mcu/libraries/Time/Readme.txt new file mode 100644 index 00000000..67b148ec --- /dev/null +++ b/arduino_mcu/libraries/Time/Readme.txt @@ -0,0 +1,131 @@ +Readme file for Arduino Time Library + +Time is a library that provides timekeeping functionality for Arduino. + +The code is derived from the Playground DateTime library but is updated +to provide an API that is more flexable and easier to use. + +A primary goal was to enable date and time functionality that can be used with +a variety of external time sources with minimum differences required in sketch logic. + +Example sketches illustrate how similar sketch code can be used with: a Real Time Clock, +internet NTP time service, GPS time data, and Serial time messages from a computer +for time synchronization. + +The functions available in the library include: + +hour(); // the hour now (0-23) +minute(); // the minute now (0-59) +second(); // the second now (0-59) +day(); // the day now (1-31) +weekday(); // day of the week, Sunday is day 0 +month(); // the month now (1-12) +year(); // the full four digit year: (2009, 2010 etc) + +there are also functions to return the hour in 12 hour format +hourFormat12(); // the hour now in 12 hour format +isAM(); // returns true if time now is AM +isPM(); // returns true if time now is PM + +now(); // returns the current time as seconds since Jan 1 1970 + +The time and date functions can take an optional parameter for the time. This prevents +errors if the time rolls over between elements. For example, if a new minute begins +between getting the minute and second, the values will be inconsistent. Using the +following functions eliminates this probglem + time_t t = now(); // store the current time in time variable t + hour(t); // returns the hour for the given time t + minute(t); // returns the minute for the given time t + second(t); // returns the second for the given time t + day(t); // the day for the given time t + weekday(t); // day of the week for the given time t + month(t); // the month for the given time t + year(t); // the year for the given time t + + +Functions for managing the timer services are: +setTime(t); // set the system time to the give time t +setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr (2010 or 10 sets year to 2010) +adjustTime(adjustment); // adjust system time by adding the adjustment value + +timeStatus(); // indicates if time has been set and recently synchronized + // returns one of the following enumerations: + timeNotSet // the time has never been set, the clock started at Jan 1 1970 + timeNeedsSync // the time had been set but a sync attempt did not succeed + timeSet // the time is set and is synced +Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but +the returned time may have drifted if the status is timeNeedsSync. + +setSyncProvider(getTimeFunction); // set the external time provider +setSyncInterval(interval); // set the number of seconds between re-sync + + +There are many convenience macros in the time.h file for time constants and conversion of time units. + +To use the library, copy the download to the Library directory. + +The Time directory contains the Time library and some example sketches +illustrating how the library can be used with various time sources: + +- TimeSerial.pde shows Arduino as a clock without external hardware. + It is synchronized by time messages sent over the serial port. + A companion Processing sketch will automatically provide these messages + if it is running and connected to the Arduino serial port. + +- TimeSerialDateStrings.pde adds day and month name strings to the sketch above + Short (3 character) and long strings are available to print the days of + the week and names of the months. + +- TimeRTC uses a DS1307 real time clock to provide time synchronization. + A basic RTC library named DS1307RTC is included in the download. + To run this sketch the DS1307RTC library must be installed. + +- TimeRTCSet is similar to the above and adds the ability to set the Real Time Clock + +- TimeRTCLog demonstrates how to calculate the difference between times. + It is a vary simple logger application that monitors events on digtial pins + and prints (to the serial port) the time of an event and the time period since the previous event. + +- TimeNTP uses the Arduino Ethernet shield to access time using the internet NTP time service. + The NTP protocol uses UDP and the UdpBytewise library is required, see: + http://bitbucket.org/bjoern/arduino_osc/src/14667490521f/libraries/Ethernet/ + +- TimeGPS gets time from a GPS + This requires the TinyGPS library from Mikal Hart: + http://arduiniana.org/libraries/TinyGPS + +Differences between this code and the playground DateTime library +although the Time library is based on the DateTime codebase, the API has changed. +Changes in the Time library API: +- time elements are functions returning int (they are variables in DateTime) +- Years start from 1970 +- days of the week and months start from 1 (they start from 0 in DateTime) +- DateStrings do not require a seperate library +- time elements can be accessed non-atomically (in DateTime they are always atomic) +- function added to automatically sync time with extrnal source +- localTime and maketime parameters changed, localTime renamed to breakTime + +Technical notes: + +Internal system time is based on the standard Unix time_t. +The value is the number of seconds since Jan 1 1970. +System time begins at zero when the sketch starts. + +The internal time can be automatically synchronized at regular intervals to an external time source. +This is enabled by calling the setSyncProvider(provider) function - the provider argument is +the address of a function that returns the current time as a time_t. +See the sketches in the examples directory for usage. + +The default interval for re-syncing the time is 5 minutes but can be changed by calling the +setSyncInterval( interval) method to set the number of seconds between re-sync attempts. + +The Time library defines a structure for holding time elements that is a compact version of the C tm structure. +All the members of the Arduino tm structure are bytes and the year is offset from 1970. +Convenience macros provide conversion to and from the Arduino format. + +Low level functions to convert between system time and individual time elements are provided: + breakTime( time, &tm); // break time_t into elements stored in tm struct + makeTime( &tm); // return time_t from elements stored in tm struct + +The DS1307RTC library included in the download provides an example of how a time provider +can use the low level functions to interface with the Time library. diff --git a/arduino_mcu/libraries/Time/Time.cpp b/arduino_mcu/libraries/Time/Time.cpp new file mode 100644 index 00000000..4cb01e78 --- /dev/null +++ b/arduino_mcu/libraries/Time/Time.cpp @@ -0,0 +1,319 @@ +/* + time.c - low level time and date functions + Copyright (c) Michael Margolis 2009-2014 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + 1.0 6 Jan 2010 - initial release + 1.1 12 Feb 2010 - fixed leap year calculation error + 1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) + 1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update + status, updated examples for Arduino 1.0, fixed ARM + compatibility issues, added TimeArduinoDue and TimeTeensy3 + examples, add error checking and messages to RTC examples, + add examples to DS1307RTC library. + 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 +*/ + +#if ARDUINO >= 100 +#include +#else +#include +#endif + +#include "Time.h" + +static tmElements_t tm; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds + +void refreshCache(time_t t) { + if (t != cacheTime) { + breakTime(t, tm); + cacheTime = t; + } +} + +int hour() { // the hour now + return hour(now()); +} + +int hour(time_t t) { // the hour for the given time + refreshCache(t); + return tm.Hour; +} + +int hourFormat12() { // the hour now in 12 hour format + return hourFormat12(now()); +} + +int hourFormat12(time_t t) { // the hour for the given time in 12 hour format + refreshCache(t); + if( tm.Hour == 0 ) + return 12; // 12 midnight + else if( tm.Hour > 12) + return tm.Hour - 12 ; + else + return tm.Hour ; +} + +uint8_t isAM() { // returns true if time now is AM + return !isPM(now()); +} + +uint8_t isAM(time_t t) { // returns true if given time is AM + return !isPM(t); +} + +uint8_t isPM() { // returns true if PM + return isPM(now()); +} + +uint8_t isPM(time_t t) { // returns true if PM + return (hour(t) >= 12); +} + +int minute() { + return minute(now()); +} + +int minute(time_t t) { // the minute for the given time + refreshCache(t); + return tm.Minute; +} + +int second() { + return second(now()); +} + +int second(time_t t) { // the second for the given time + refreshCache(t); + return tm.Second; +} + +int day(){ + return(day(now())); +} + +int day(time_t t) { // the day for the given time (0-6) + refreshCache(t); + return tm.Day; +} + +int weekday() { // Sunday is day 1 + return weekday(now()); +} + +int weekday(time_t t) { + refreshCache(t); + return tm.Wday; +} + +int month(){ + return month(now()); +} + +int month(time_t t) { // the month for the given time + refreshCache(t); + return tm.Month; +} + +int year() { // as in Processing, the full four digit year: (2009, 2010 etc) + return year(now()); +} + +int year(time_t t) { // the year for the given time + refreshCache(t); + return tmYearToCalendar(tm.Year); +} + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time serivces and are not normally needed in a sketch */ + +// leap year calulator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + +static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 + +void breakTime(time_t timeInput, tmElements_t &tm){ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + unsigned long days; + + time = (uint32_t)timeInput; + tm.Second = time % 60; + time /= 60; // now it is minutes + tm.Minute = time % 60; + time /= 60; // now it is hours + tm.Hour = time % 24; + time /= 24; // now it is days + tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.Year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days=0; + month=0; + monthLength=0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } + } + tm.Month = month + 1; // jan is month 1 + tm.Day = time + 1; // day of month +} + +time_t makeTime(tmElements_t &tm){ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds= tm.Year*(SECS_PER_DAY * 365); + for (i = 0; i < tm.Year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.Month; i++) { + if ( (i == 2) && LEAP_YEAR(tm.Year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tm.Day-1) * SECS_PER_DAY; + seconds+= tm.Hour * SECS_PER_HOUR; + seconds+= tm.Minute * SECS_PER_MIN; + seconds+= tm.Second; + return (time_t)seconds; +} +/*=====================================================*/ +/* Low level system time functions */ + +static uint32_t sysTime = 0; +static uint32_t prevMillis = 0; +static uint32_t nextSyncTime = 0; +static timeStatus_t Status = timeNotSet; + +getExternalTime getTimePtr; // pointer to external sync function +//setExternalTime setTimePtr; // not used in this version + +#ifdef TIME_DRIFT_INFO // define this to get drift data +time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync +#endif + + +time_t now() { + while (millis() - prevMillis >= 1000){ + sysTime++; + prevMillis += 1000; +#ifdef TIME_DRIFT_INFO + sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift +#endif + } + if (nextSyncTime <= sysTime) { + if (getTimePtr != 0) { + time_t t = getTimePtr(); + if (t != 0) { + setTime(t); + } else { + nextSyncTime = sysTime + syncInterval; + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + } + } + } + return (time_t)sysTime; +} + +void setTime(time_t t) { +#ifdef TIME_DRIFT_INFO + if(sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time +#endif + + sysTime = (uint32_t)t; + nextSyncTime = (uint32_t)t + syncInterval; + Status = timeSet; + prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) +} + +void setTime(int hr,int min,int sec,int dy, int mnth, int yr){ + // year can be given as full four digit year or two digts (2010 or 10 for 2010); + //it is converted to years since 1970 + if( yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = mnth; + tm.Day = dy; + tm.Hour = hr; + tm.Minute = min; + tm.Second = sec; + setTime(makeTime(tm)); +} + +void adjustTime(long adjustment) { + sysTime += adjustment; +} + +// indicates if time has been set and recently synchronized +timeStatus_t timeStatus() { + now(); // required to actually update the status + return Status; +} + +void setSyncProvider( getExternalTime getTimeFunction){ + getTimePtr = getTimeFunction; + nextSyncTime = sysTime; + now(); // this will sync the clock +} + +void setSyncInterval(time_t interval){ // set the number of seconds between re-sync + syncInterval = (uint32_t)interval; + nextSyncTime = sysTime + syncInterval; +} diff --git a/arduino_mcu/libraries/Time/Time.h b/arduino_mcu/libraries/Time/Time.h new file mode 100644 index 00000000..61519f7d --- /dev/null +++ b/arduino_mcu/libraries/Time/Time.h @@ -0,0 +1,144 @@ +/* + time.h - low level time and date functions +*/ + +/* + July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) + - fixed daysToTime_t macro (thanks maniacbug) +*/ + +#ifndef _Time_h +#ifdef __cplusplus +#define _Time_h + +#include +#ifndef __AVR__ +#include // for __time_t_defined, but avr libc lacks sys/types.h +#endif + + +#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc +typedef unsigned long time_t; +#endif + + +// This ugly hack allows us to define C++ overloaded functions, when included +// from within an extern "C", as newlib's sys/stat.h does. Actually it is +// intended to include "time.h" from the C library (on ARM, but AVR does not +// have that file at all). On Mac and Windows, the compiler will find this +// "Time.h" instead of the C library "time.h", so we may cause other weird +// and unpredictable effects by conflicting with the C library header "time.h", +// but at least this hack lets us define C++ functions as intended. Hopefully +// nothing too terrible will result from overriding the C library header?! +extern "C++" { +typedef enum {timeNotSet, timeNeedsSync, timeSet +} timeStatus_t ; + +typedef enum { + dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday +} timeDayOfWeek_t; + +typedef enum { + tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields +} tmByteFields; + +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 + uint8_t Day; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; + +//convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) + +typedef time_t(*getExternalTime)(); +//typedef void (*setExternalTime)(const time_t); // not used in this version + + +/*==============================================================================*/ +/* Useful Constants */ +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) +#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) +#define DAYS_PER_WEEK (7UL) +#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) +#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) +#define SECS_YR_2000 (946684800UL) // the time at the start of y2k + +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) +#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday +#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970 +#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight +// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 +// Always set the correct time before settting alarms +#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day +#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day +#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // note that week starts on day 1 +#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time +#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time + + +/* Useful Macros for converting elapsed time to a time_t */ +#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) +#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) +#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) + +/*============================================================================*/ +/* time and date functions */ +int hour(); // the hour now +int hour(time_t t); // the hour for the given time +int hourFormat12(); // the hour now in 12 hour format +int hourFormat12(time_t t); // the hour for the given time in 12 hour format +uint8_t isAM(); // returns true if time now is AM +uint8_t isAM(time_t t); // returns true the given time is AM +uint8_t isPM(); // returns true if time now is PM +uint8_t isPM(time_t t); // returns true the given time is PM +int minute(); // the minute now +int minute(time_t t); // the minute for the given time +int second(); // the second now +int second(time_t t); // the second for the given time +int day(); // the day now +int day(time_t t); // the day for the given time +int weekday(); // the weekday now (Sunday is day 1) +int weekday(time_t t); // the weekday for the given time +int month(); // the month now (Jan is month 1) +int month(time_t t); // the month for the given time +int year(); // the full four digit year: (2009, 2010 etc) +int year(time_t t); // the year for the given time + +time_t now(); // return the current time as seconds since Jan 1 1970 +void setTime(time_t t); +void setTime(int hr,int min,int sec,int day, int month, int yr); +void adjustTime(long adjustment); + +/* date strings */ +#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) +char* monthStr(uint8_t month); +char* dayStr(uint8_t day); +char* monthShortStr(uint8_t month); +char* dayShortStr(uint8_t day); + +/* time sync functions */ +timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval(time_t interval); // set the number of seconds between re-sync + +/* low level functions to convert to and from system time */ +void breakTime(time_t time, tmElements_t &tm); // break time_t into elements +time_t makeTime(tmElements_t &tm); // convert time elements into time_t + +} // extern "C++" +#endif // __cplusplus +#endif /* _Time_h */ + diff --git a/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/SyncArduinoClock.pde b/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/SyncArduinoClock.pde new file mode 100644 index 00000000..4313be33 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/SyncArduinoClock.pde @@ -0,0 +1,78 @@ +/** + * SyncArduinoClock. + * + * portIndex must be set to the port connected to the Arduino + * + * The current time is sent in response to request message from Arduino + * or by clicking the display window + * + * The time message is 11 ASCII text characters; a header (the letter 'T') + * followed by the ten digit system time (unix time) + */ + + +import processing.serial.*; +import java.util.Date; +import java.util.Calendar; +import java.util.GregorianCalendar; + +public static final short portIndex = 0; // select the com port, 0 is the first port +public static final String TIME_HEADER = "T"; //header for arduino serial time message +public static final char TIME_REQUEST = 7; // ASCII bell character +public static final char LF = 10; // ASCII linefeed +public static final char CR = 13; // ASCII linefeed +Serial myPort; // Create object from Serial class + +void setup() { + size(200, 200); + println(Serial.list()); + println(" Connecting to -> " + Serial.list()[portIndex]); + myPort = new Serial(this,Serial.list()[portIndex], 9600); + println(getTimeNow()); +} + +void draw() +{ + textSize(20); + textAlign(CENTER); + fill(0); + text("Click to send\nTime Sync", 0, 75, 200, 175); + if ( myPort.available() > 0) { // If data is available, + char val = char(myPort.read()); // read it and store it in val + if(val == TIME_REQUEST){ + long t = getTimeNow(); + sendTimeMessage(TIME_HEADER, t); + } + else + { + if(val == LF) + ; //igonore + else if(val == CR) + println(); + else + print(val); // echo everying but time request + } + } +} + +void mousePressed() { + sendTimeMessage( TIME_HEADER, getTimeNow()); +} + + +void sendTimeMessage(String header, long time) { + String timeStr = String.valueOf(time); + myPort.write(header); // send header and time to arduino + myPort.write(timeStr); + myPort.write('\n'); +} + +long getTimeNow(){ + // java time is in ms, we want secs + Date d = new Date(); + Calendar cal = new GregorianCalendar(); + long current = d.getTime()/1000; + long timezone = cal.get(cal.ZONE_OFFSET)/1000; + long daylight = cal.get(cal.DST_OFFSET)/1000; + return current + timezone + daylight; +} diff --git a/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/readme.txt b/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/readme.txt new file mode 100644 index 00000000..da9721d7 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/Processing/SyncArduinoClock/readme.txt @@ -0,0 +1,9 @@ +SyncArduinoClock is a Processing sketch that responds to Arduino requests for +time synchronization messages. + +The portIndex must be set the Serial port connected to Arduino. + +Download TimeSerial.pde onto Arduino and you should see the time +message displayed when you run SyncArduinoClock in Processing. +The Arduino time is set from the time on your computer through the +Processing sketch. diff --git a/arduino_mcu/libraries/Time/examples/TimeArduinoDue/TimeArduinoDue.ino b/arduino_mcu/libraries/Time/examples/TimeArduinoDue/TimeArduinoDue.ino new file mode 100644 index 00000000..a19a2e07 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeArduinoDue/TimeArduinoDue.ino @@ -0,0 +1,71 @@ +/* + * TimeRTC.pde + * example code illustrating Time library with Real Time Clock. + * + * This example requires Markus Lange's Arduino Due RTC Library + * https://github.com/MarkusLange/Arduino-Due-RTC-Library + */ + +#include +#include + +// Select the Slowclock source +//RTC_clock rtc_clock(RC); +RTC_clock rtc_clock(XTAL); + +void setup() { + Serial.begin(9600); + rtc_clock.init(); + if (rtc_clock.date_already_set() == 0) { + // Unfortunately, the Arduino Due hardware does not seem to + // be designed to maintain the RTC clock state when the + // board resets. Markus described it thusly: "Uhh the Due + // does reset with the NRSTB pin. This resets the full chip + // with all backup regions including RTC, RTT and SC. Only + // if the reset is done with the NRST pin will these regions + // stay with their old values." + rtc_clock.set_time(__TIME__); + rtc_clock.set_date(__DATE__); + // However, this might work on other unofficial SAM3X boards + // with different reset circuitry than Arduino Due? + } + setSyncProvider(getArduinoDueTime); + if(timeStatus()!= timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +time_t getArduinoDueTime() +{ + return rtc_clock.unixtime(); +} + +void loop() +{ + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeGPS/TimeGPS.ino b/arduino_mcu/libraries/Time/examples/TimeGPS/TimeGPS.ino new file mode 100644 index 00000000..7a0213b8 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeGPS/TimeGPS.ino @@ -0,0 +1,87 @@ +/* + * TimeGPS.pde + * example code illustrating time synced from a GPS + * + */ + +#include +#include // http://arduiniana.org/libraries/TinyGPS/ +#include +// TinyGPS and SoftwareSerial libraries are the work of Mikal Hart + +SoftwareSerial SerialGPS = SoftwareSerial(10, 11); // receive on pin 10 +TinyGPS gps; + +// To use a hardware serial port, which is far more efficient than +// SoftwareSerial, uncomment this line and remove SoftwareSerial +//#define SerialGPS Serial1 + +// Offset hours from gps time (UTC) +const int offset = 1; // Central European Time +//const int offset = -5; // Eastern Standard Time (USA) +//const int offset = -4; // Eastern Daylight Time (USA) +//const int offset = -8; // Pacific Standard Time (USA) +//const int offset = -7; // Pacific Daylight Time (USA) + +// Ideally, it should be possible to learn the time zone +// based on the GPS position data. However, that would +// require a complex library, probably incorporating some +// sort of database using Eric Muller's time zone shape +// maps, at http://efele.net/maps/tz/ + +time_t prevDisplay = 0; // when the digital clock was displayed + +void setup() +{ + Serial.begin(9600); + while (!Serial) ; // Needed for Leonardo only + SerialGPS.begin(4800); + Serial.println("Waiting for GPS time ... "); +} + +void loop() +{ + while (SerialGPS.available()) { + if (gps.encode(SerialGPS.read())) { // process gps messages + // when TinyGPS reports new data... + unsigned long age; + int Year; + byte Month, Day, Hour, Minute, Second; + gps.crack_datetime(&Year, &Month, &Day, &Hour, &Minute, &Second, NULL, &age); + if (age < 500) { + // set the Time to the latest GPS reading + setTime(Hour, Minute, Second, Day, Month, Year); + adjustTime(offset * SECS_PER_HOUR); + } + } + } + if (timeStatus()!= timeNotSet) { + if (now() != prevDisplay) { //update the display only if the time has changed + prevDisplay = now(); + digitalClockDisplay(); + } + } +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits) { + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeNTP/TimeNTP.ino b/arduino_mcu/libraries/Time/examples/TimeNTP/TimeNTP.ino new file mode 100644 index 00000000..0d3820ec --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeNTP/TimeNTP.ino @@ -0,0 +1,135 @@ +/* + * Time_NTP.pde + * Example showing time sync to NTP time source + * + * This sketch uses the Ethernet library + */ + +#include +#include +#include +#include + +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +// NTP Servers: +IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov +// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov +// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov + + +const int timeZone = 1; // Central European Time +//const int timeZone = -5; // Eastern Standard Time (USA) +//const int timeZone = -4; // Eastern Daylight Time (USA) +//const int timeZone = -8; // Pacific Standard Time (USA) +//const int timeZone = -7; // Pacific Daylight Time (USA) + + +EthernetUDP Udp; +unsigned int localPort = 8888; // local port to listen for UDP packets + +void setup() +{ + Serial.begin(9600); + while (!Serial) ; // Needed for Leonardo only + delay(250); + Serial.println("TimeNTP Example"); + if (Ethernet.begin(mac) == 0) { + // no point in carrying on, so do nothing forevermore: + while (1) { + Serial.println("Failed to configure Ethernet using DHCP"); + delay(10000); + } + } + Serial.print("IP number assigned by DHCP is "); + Serial.println(Ethernet.localIP()); + Udp.begin(localPort); + Serial.println("waiting for sync"); + setSyncProvider(getNtpTime); +} + +time_t prevDisplay = 0; // when the digital clock was displayed + +void loop() +{ + if (timeStatus() != timeNotSet) { + if (now() != prevDisplay) { //update the display only if time has changed + prevDisplay = now(); + digitalClockDisplay(); + } + } +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +/*-------- NTP code ----------*/ + +const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message +byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets + +time_t getNtpTime() +{ + while (Udp.parsePacket() > 0) ; // discard any previously received packets + Serial.println("Transmit NTP Request"); + sendNTPpacket(timeServer); + uint32_t beginWait = millis(); + while (millis() - beginWait < 1500) { + int size = Udp.parsePacket(); + if (size >= NTP_PACKET_SIZE) { + Serial.println("Receive NTP Response"); + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer + unsigned long secsSince1900; + // convert four bytes starting at location 40 to a long integer + secsSince1900 = (unsigned long)packetBuffer[40] << 24; + secsSince1900 |= (unsigned long)packetBuffer[41] << 16; + secsSince1900 |= (unsigned long)packetBuffer[42] << 8; + secsSince1900 |= (unsigned long)packetBuffer[43]; + return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; + } + } + Serial.println("No NTP Response :-("); + return 0; // return 0 if unable to get the time +} + +// send an NTP request to the time server at the given address +void sendNTPpacket(IPAddress &address) +{ + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); //NTP requests are to port 123 + Udp.write(packetBuffer, NTP_PACKET_SIZE); + Udp.endPacket(); +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeRTC/TimeRTC.pde b/arduino_mcu/libraries/Time/examples/TimeRTC/TimeRTC.pde new file mode 100644 index 00000000..42e7e7fe --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeRTC/TimeRTC.pde @@ -0,0 +1,55 @@ +/* + * TimeRTC.pde + * example code illustrating Time library with Real Time Clock. + * + */ + +#include +#include +#include // a basic DS1307 library that returns time as a time_t + +void setup() { + Serial.begin(9600); + while (!Serial) ; // wait until Arduino Serial Monitor opens + setSyncProvider(RTC.get); // the function to get the time from the RTC + if(timeStatus()!= timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +void loop() +{ + if (timeStatus() == timeSet) { + digitalClockDisplay(); + } else { + Serial.println("The time has not been set. Please run the Time"); + Serial.println("TimeRTCSet example, or DS1307RTC SetTime example."); + Serial.println(); + delay(4000); + } + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeRTCLog/TimeRTCLog.pde b/arduino_mcu/libraries/Time/examples/TimeRTCLog/TimeRTCLog.pde new file mode 100644 index 00000000..5715eb02 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeRTCLog/TimeRTCLog.pde @@ -0,0 +1,107 @@ +/* + * TimeRTCLogger.pde + * example code illustrating adding and subtracting Time. + * + * this sketch logs pin state change events + * the time of the event and time since the previous event is calculated and sent to the serial port. + */ + +#include +#include +#include // a basic DS1307 library that returns time as a time_t + +const int nbrInputPins = 6; // monitor 6 digital pins +const int inputPins[nbrInputPins] = {2,3,4,5,6,7}; // pins to monitor +boolean state[nbrInputPins] ; // the state of the monitored pins +time_t prevEventTime[nbrInputPins] ; // the time of the previous event + +void setup() { + Serial.begin(9600); + setSyncProvider(RTC.get); // the function to sync the time from the RTC + for(int i=0; i < nbrInputPins; i++){ + pinMode( inputPins[i], INPUT); + // uncomment these lines if pull-up resistors are wanted + // pinMode( inputPins[i], INPUT_PULLUP); + // state[i] = HIGH; + } +} + +void loop() +{ + for(int i=0; i < nbrInputPins; i++) + { + boolean val = digitalRead(inputPins[i]); + if(val != state[i]) + { + time_t duration = 0; // the time since the previous event + state[i] = val; + time_t timeNow = now(); + if(prevEventTime[i] > 0) + // if this was not the first state change, calculate the time from the previous change + duration = duration = timeNow - prevEventTime[i]; + logEvent(inputPins[i], val, timeNow, duration ); // log the event + prevEventTime[i] = timeNow; // store the time for this event + } + } +} + +void logEvent( int pin, boolean state, time_t timeNow, time_t duration) +{ + Serial.print("Pin "); + Serial.print(pin); + if( state == HIGH) + Serial.print(" went High at "); + else + Serial.print(" went Low at "); + showTime(timeNow); + if(duration > 0){ + // only display duration if greater than 0 + Serial.print(", Duration was "); + showDuration(duration); + } + Serial.println(); +} + + +void showTime(time_t t){ + // display the given time + Serial.print(hour(t)); + printDigits(minute(t)); + printDigits(second(t)); + Serial.print(" "); + Serial.print(day(t)); + Serial.print(" "); + Serial.print(month(t)); + Serial.print(" "); + Serial.print(year(t)); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +void showDuration(time_t duration){ +// prints the duration in days, hours, minutes and seconds + if(duration >= SECS_PER_DAY){ + Serial.print(duration / SECS_PER_DAY); + Serial.print(" day(s) "); + duration = duration % SECS_PER_DAY; + } + if(duration >= SECS_PER_HOUR){ + Serial.print(duration / SECS_PER_HOUR); + Serial.print(" hour(s) "); + duration = duration % SECS_PER_HOUR; + } + if(duration >= SECS_PER_MIN){ + Serial.print(duration / SECS_PER_MIN); + Serial.print(" minute(s) "); + duration = duration % SECS_PER_MIN; + } + Serial.print(duration); + Serial.print(" second(s) "); +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeRTCSet/TimeRTCSet.ino b/arduino_mcu/libraries/Time/examples/TimeRTCSet/TimeRTCSet.ino new file mode 100644 index 00000000..b4e4854b --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeRTCSet/TimeRTCSet.ino @@ -0,0 +1,80 @@ +/* + * TimeRTCSet.pde + * example code illustrating Time library with Real Time Clock. + * + * RTC clock is set in response to serial port time message + * A Processing example sketch to set the time is included in the download + * On Linux, you can use "date +T%s > /dev/ttyACM0" (UTC time zone) + */ + +#include +#include +#include // a basic DS1307 library that returns time as a time_t + + +void setup() { + Serial.begin(9600); + while (!Serial) ; // Needed for Leonardo only + setSyncProvider(RTC.get); // the function to get the time from the RTC + if (timeStatus() != timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +void loop() +{ + if (Serial.available()) { + time_t t = processSyncMessage(); + if (t != 0) { + RTC.set(t); // set the RTC and the system time to the received value + setTime(t); + } + } + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +/* code to process time sync messages from the serial port */ +#define TIME_HEADER "T" // Header tag for serial time sync message + +unsigned long processSyncMessage() { + unsigned long pctime = 0L; + const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 + + if(Serial.find(TIME_HEADER)) { + pctime = Serial.parseInt(); + return pctime; + if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013) + pctime = 0L; // return 0 to indicate that the time is not valid + } + } + return pctime; +} + + + + + diff --git a/arduino_mcu/libraries/Time/examples/TimeSerial/TimeSerial.ino b/arduino_mcu/libraries/Time/examples/TimeSerial/TimeSerial.ino new file mode 100644 index 00000000..135db6fc --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeSerial/TimeSerial.ino @@ -0,0 +1,81 @@ +/* + * TimeSerial.pde + * example code illustrating Time library set through serial port messages. + * + * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970) + * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2013 + T1357041600 + * + * A Processing example sketch to automatically send the messages is inclided in the download + * On Linux, you can use "date +T%s\n > /dev/ttyACM0" (UTC time zone) + */ + +#include + +#define TIME_HEADER "T" // Header tag for serial time sync message +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +void setup() { + Serial.begin(9600); + while (!Serial) ; // Needed for Leonardo only + pinMode(13, OUTPUT); + setSyncProvider( requestSync); //set function to call when sync required + Serial.println("Waiting for sync message"); +} + +void loop(){ + if (Serial.available()) { + processSyncMessage(); + } + if (timeStatus()!= timeNotSet) { + digitalClockDisplay(); + } + if (timeStatus() == timeSet) { + digitalWrite(13, HIGH); // LED on if synced + } else { + digitalWrite(13, LOW); // LED off if needs refresh + } + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + + +void processSyncMessage() { + unsigned long pctime; + const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 + + if(Serial.find(TIME_HEADER)) { + pctime = Serial.parseInt(); + if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013) + setTime(pctime); // Sync Arduino clock to the time received on the serial port + } + } +} + +time_t requestSync() +{ + Serial.write(TIME_REQUEST); + return 0; // the time will be sent later in response to serial mesg +} + diff --git a/arduino_mcu/libraries/Time/examples/TimeSerialDateStrings/TimeSerialDateStrings.ino b/arduino_mcu/libraries/Time/examples/TimeSerialDateStrings/TimeSerialDateStrings.ino new file mode 100644 index 00000000..6024776e --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeSerialDateStrings/TimeSerialDateStrings.ino @@ -0,0 +1,108 @@ +/* + * TimeSerialDateStrings.pde + * example code illustrating Time library date strings + * + * This sketch adds date string functionality to TimeSerial sketch + * Also shows how to handle different messages + * + * A message starting with a time header sets the time + * A Processing example sketch to automatically send the messages is inclided in the download + * On Linux, you can use "date +T%s\n > /dev/ttyACM0" (UTC time zone) + * + * A message starting with a format header sets the date format + + * send: Fs\n for short date format + * send: Fl\n for long date format + */ + +#include + +// single character message tags +#define TIME_HEADER 'T' // Header tag for serial time sync message +#define FORMAT_HEADER 'F' // Header tag indicating a date format message +#define FORMAT_SHORT 's' // short month and day strings +#define FORMAT_LONG 'l' // (lower case l) long month and day strings + +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +static boolean isLongFormat = true; + +void setup() { + Serial.begin(9600); + while (!Serial) ; // Needed for Leonardo only + setSyncProvider( requestSync); //set function to call when sync required + Serial.println("Waiting for sync message"); +} + +void loop(){ + if (Serial.available() > 1) { // wait for at least two characters + char c = Serial.read(); + if( c == TIME_HEADER) { + processSyncMessage(); + } + else if( c== FORMAT_HEADER) { + processFormatMessage(); + } + } + if (timeStatus()!= timeNotSet) { + digitalClockDisplay(); + } + delay(1000); +} + +void digitalClockDisplay() { + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + if(isLongFormat) + Serial.print(dayStr(weekday())); + else + Serial.print(dayShortStr(weekday())); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + if(isLongFormat) + Serial.print(monthStr(month())); + else + Serial.print(monthShortStr(month())); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits) { + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +void processFormatMessage() { + char c = Serial.read(); + if( c == FORMAT_LONG){ + isLongFormat = true; + Serial.println(F("Setting long format")); + } + else if( c == FORMAT_SHORT) { + isLongFormat = false; + Serial.println(F("Setting short format")); + } +} + +void processSyncMessage() { + unsigned long pctime; + const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 - paul, perhaps we define in time.h? + + pctime = Serial.parseInt(); + if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013) + setTime(pctime); // Sync Arduino clock to the time received on the serial port + } +} + +time_t requestSync() { + Serial.write(TIME_REQUEST); + return 0; // the time will be sent later in response to serial mesg +} diff --git a/arduino_mcu/libraries/Time/examples/TimeTeensy3/TimeTeensy3.ino b/arduino_mcu/libraries/Time/examples/TimeTeensy3/TimeTeensy3.ino new file mode 100644 index 00000000..a06a7f90 --- /dev/null +++ b/arduino_mcu/libraries/Time/examples/TimeTeensy3/TimeTeensy3.ino @@ -0,0 +1,78 @@ +/* + * TimeRTC.pde + * example code illustrating Time library with Real Time Clock. + * + */ + +#include + +void setup() { + // set the Time library to use Teensy 3.0's RTC to keep time + setSyncProvider(getTeensy3Time); + + Serial.begin(115200); + while (!Serial); // Wait for Arduino Serial Monitor to open + delay(100); + if (timeStatus()!= timeSet) { + Serial.println("Unable to sync with the RTC"); + } else { + Serial.println("RTC has set the system time"); + } +} + +void loop() { + if (Serial.available()) { + time_t t = processSyncMessage(); + if (t != 0) { + Teensy3Clock.set(t); // set the RTC + setTime(t); + } + } + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay() { + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +time_t getTeensy3Time() +{ + return Teensy3Clock.get(); +} + +/* code to process time sync messages from the serial port */ +#define TIME_HEADER "T" // Header tag for serial time sync message + +unsigned long processSyncMessage() { + unsigned long pctime = 0L; + const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 + + if(Serial.find(TIME_HEADER)) { + pctime = Serial.parseInt(); + return pctime; + if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013) + pctime = 0L; // return 0 to indicate that the time is not valid + } + } + return pctime; +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + diff --git a/arduino_mcu/libraries/Time/keywords.txt b/arduino_mcu/libraries/Time/keywords.txt new file mode 100644 index 00000000..85b357e4 --- /dev/null +++ b/arduino_mcu/libraries/Time/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For Time +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +time_t KEYWORD1 +####################################### +# Methods and Functions (KEYWORD2) +####################################### +now KEYWORD2 +second KEYWORD2 +minute KEYWORD2 +hour KEYWORD2 +day KEYWORD2 +month KEYWORD2 +year KEYWORD2 +isAM KEYWORD2 +isPM KEYWORD2 +weekday KEYWORD2 +setTime KEYWORD2 +adjustTime KEYWORD2 +setSyncProvider KEYWORD2 +setSyncInterval KEYWORD2 +timeStatus KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/arduino_mcu/libraries/Time/library.json b/arduino_mcu/libraries/Time/library.json new file mode 100644 index 00000000..071e74c9 --- /dev/null +++ b/arduino_mcu/libraries/Time/library.json @@ -0,0 +1,22 @@ +{ +"name": "Time", +"frameworks": "Arduino", +"keywords": "Time, date, hour, minute, second, day, week, month, year, RTC", +"description": "Time keeping library", +"url": "http://playground.arduino.cc/Code/Time", +"authors": +[ +{ + "name": "Michael Margolis" +}, +{ + "name": "Paul Stoffregen" +} +], +"repository": +{ + "type": "git", + "url": "https://github.com/PaulStoffregen/Time" +} +} + diff --git a/arduino_mcu/openScale_MCU/openScale_MCU.ino b/arduino_mcu/openScale_MCU/openScale_MCU.ino new file mode 100644 index 00000000..ff72fa18 --- /dev/null +++ b/arduino_mcu/openScale_MCU/openScale_MCU.ino @@ -0,0 +1,561 @@ +/* Copyright (C) 2014 olie.xdev +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include +#include +#include +#include +#include + +#define SEG_1_1 4 +#define SEG_1_2 5 +#define SEG_2_1 6 +#define SEG_2_2 7 +#define SEG_3_1 8 +#define SEG_3_2 9 +#define SEG_4_1 10 +#define SEG_4_2 11 +#define UP 12 +#define C0 A0 +#define C1 A1 +#define C2 A2 +#define C3 A3 +#define WAKEUP_PIN 3 +#define EXT_SWITCH_PIN 13 + +#define MAX_SAMPLE_SIZE 6 +#define MAX_NO_ACTIVITY_CYCLES 32 + +I2C_eeprom eeprom(0x50); + +char port_control; +char port_digital_pinA; +char port_digital_pinB; + +int control_bit[4]; + +int seg_raw_1_1[4]; +int seg_raw_1_2[4]; +int seg_raw_2_1[4]; +int seg_raw_2_2[4]; +int seg_raw_3_1[4]; +int seg_raw_3_2[4]; +int seg_raw_4_1[4]; +int seg_raw_4_2[4]; + +char seg_value_1; +char seg_value_2; +char seg_value_3; +char seg_value_4; + +RunningMedian seg_samples_1; +RunningMedian seg_samples_2; +RunningMedian seg_samples_3; +RunningMedian seg_samples_4; + +int sample_count = 0; + +int no_activity_cycles = 0; + +volatile boolean sleep_state = true; + +volatile boolean repeat_state = false; + +int measured_weight = -1; +int measured_fat = -1; +int measured_water = -1; +int measured_muscle = -1; + +typedef struct scale_data{ + int year; + byte month; + byte day; + byte hour; + byte minute; + int weight; + int fat; + int water; + int muscle; + int checksum; +} __attribute__ ((packed)); // avoiding byte padding in this struct. Important for continuous writing/reading to/from eeprom! + + +void interrupt_handler() +{ + sleep_state = false; +} + +void setup() { + Serial.begin(9600); + + pinMode(SEG_1_1, INPUT); + pinMode(SEG_1_2, INPUT); + pinMode(SEG_2_1, INPUT); + pinMode(SEG_2_2, INPUT); + pinMode(SEG_3_1, INPUT); + pinMode(SEG_3_2, INPUT); + pinMode(SEG_4_1, INPUT); + pinMode(SEG_4_2, INPUT); + pinMode(UP, OUTPUT); + pinMode(C0, INPUT); + pinMode(C1, INPUT); + pinMode(C2, INPUT); + pinMode(C3, INPUT); + pinMode(WAKEUP_PIN, INPUT); + pinMode(EXT_SWITCH_PIN, OUTPUT); + + digitalWrite(EXT_SWITCH_PIN, HIGH); +} + +void set_seg_raw(int cycle_n) +{ + seg_raw_1_1[cycle_n] = (port_digital_pinA & (1 << 4)) ? 1 : 0; + seg_raw_1_2[cycle_n] = (port_digital_pinA & (1 << 5)) ? 1 : 0; + seg_raw_2_1[cycle_n] = (port_digital_pinA & (1 << 6)) ? 1 : 0; + seg_raw_2_2[cycle_n] = (port_digital_pinA & (1 << 7)) ? 1 : 0; + seg_raw_3_1[cycle_n] = (port_digital_pinB & (1 << 0)) ? 1 : 0; + seg_raw_3_2[cycle_n] = (port_digital_pinB & (1 << 1)) ? 1 : 0; + seg_raw_4_1[cycle_n] = (port_digital_pinB & (1 << 2)) ? 1 : 0; + seg_raw_4_2[cycle_n] = (port_digital_pinB & (1 << 3)) ? 1 : 0; +} + +char decode_seg(int seg_x[4], int seg_y[4]) +{ + boolean b = seg_x[0]; + boolean c = seg_x[1]; + boolean e = seg_x[2]; + boolean f = seg_x[3]; + boolean a = seg_y[0]; + boolean d = seg_y[1]; + boolean g = seg_y[2]; + boolean x = seg_y[3]; + + if (!e && !c && !b && !f && + !g && !d && !a) + return ' '; + + if (e && !c && b && f && + g && d && a) + return '0'; + + if (e && !c && b && !f && + !g && !d && !a) + return '1'; + + if (!e && c && b && f && + g && !d && a) + return '2'; + + if (e && c && b && f && + !g && !d && a) + return '3'; + + if (e && c && b && !f && + !g && d && !a) + return '4'; + + if (e && c && !b && f && + !g && d && a) + return '5'; + + if (e && c && !b && f && + g && d && a) + return '6'; + + if (e && !c && b && !f && + !g && !d && a) + return '7'; + + if (e && c && b && f && + g && d && a) + return '8'; + + if (e && c && b && f && + !g && d && a) + return '9'; + + if (!e && c && !b && !f && + !g && !d && !a) + return '-'; + + if (!e && c && b && !f && + g && d && a) + return 'P'; + + if (e && !c && b && !f && + g && d && a) + return 'M'; + + if (!e && c && !b && f && + g && d && a) + return 'E'; + + if (!e && c && !b && !f && + g && d && a) + return 'F'; + + if (e && c && b && !f && + g && d && !a) + return 'H'; + + return -1; +} + +void before_sleep_event() +{ + Serial.println("$I$ going to sleep in 3 seconds!"); + + if (measured_weight != -1 && measured_fat != -1 && measured_water != -1 && measured_muscle != -1) { + write_scale_data(measured_weight, measured_fat, measured_water, measured_muscle); + delay(100); + } + + send_scale_data(); + + delay(3000); + + digitalWrite(EXT_SWITCH_PIN, LOW); +} + +void after_sleep_event() +{ + digitalWrite(EXT_SWITCH_PIN, HIGH); + + measured_weight = -1; + measured_fat = -1; + measured_water = -1; + measured_muscle = -1; + + delay(4000); + digitalWrite(UP, HIGH); + delay(500); + digitalWrite(UP, LOW); + + setSyncProvider(RTC.get); + if (timeStatus() != timeSet) { + Serial.println("$E$ Can't sync to RTC clock!"); + } else { + Serial.println("$I$ Successful sync to RTC clock"); + } + + Serial.print("$I$ Time: "); + Serial.print(hour()); + Serial.write(':'); + Serial.print(minute()); + Serial.write(':'); + Serial.print(second()); + Serial.print(" Date: "); + Serial.print(day()); + Serial.write('/'); + Serial.print(month()); + Serial.write('/'); + Serial.print(year()); + Serial.println(); + + Serial.println("$I$ openScale MCU ready!"); +} + + +void check_display_activity() +{ + if (no_activity_cycles > MAX_NO_ACTIVITY_CYCLES) + { + sleep_state = true; + no_activity_cycles = 0; + } + + + if (sleep_state == true) + { + before_sleep_event(); + + // Allow wake up pin to trigger interrupt on rising edge. + attachInterrupt(1, interrupt_handler, RISING); + + // Enter power down state with ADC and BOD module disabled. + // Wake up when wake up pin is rising. + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + + // Disable external pin interrupt on wake up pin. + detachInterrupt(1); + + after_sleep_event(); + } +} + +int calc_checksum(struct scale_data* wdata) +{ + int checksum = 0; + + checksum ^= wdata->year; + checksum ^= wdata->month; + checksum ^= wdata->day; + checksum ^= wdata->hour; + checksum ^= wdata->minute; + checksum ^= (int)((float)wdata->weight / 10.0f); + checksum ^= (int)((float)wdata->fat / 10.0f); + checksum ^= (int)((float)wdata->water / 10.0f); + checksum ^= (int)((float)wdata->muscle / 10.0f); + + return checksum; +} + +void write_scale_data(int weight, int fat, int water, int muscle) +{ + int data_size = 0; + struct scale_data wdata; + + eeprom.readBlock(0, (uint8_t*)&data_size, sizeof(data_size)); + + wdata.year = year(); + wdata.month = month(); + wdata.day = day(); + wdata.hour = hour(); + wdata.minute = minute(); + wdata.weight = weight; + wdata.fat = fat; + wdata.water = water; + wdata.muscle = muscle; + wdata.checksum = calc_checksum(&wdata); + + if (eeprom.writeBlock(sizeof(data_size)+data_size*sizeof(wdata), (uint8_t*)&wdata, sizeof(wdata)) != 0) { + Serial.println("$E$ Error writing data to eeprom"); + } + + delay(100); + data_size++; + + if (eeprom.writeBlock(0, (uint8_t*)&data_size, sizeof(data_size)) != 0) { + Serial.println("$E$ Error writing data to eeprom"); + } +} + +void send_scale_data() +{ + int data_size = 0; + struct scale_data wdata; + + eeprom.readBlock(0, (uint8_t*)&data_size, sizeof(data_size)); + + Serial.print("$S$"); + Serial.println(data_size); + + for (int i=0; i < data_size; i++) + { + eeprom.readBlock(sizeof(data_size)+i*sizeof(wdata), (uint8_t*)&wdata, sizeof(wdata)); + + if (wdata.checksum != calc_checksum(&wdata)) { + Serial.print("$E$ Wrong Checksum for data "); + Serial.print(i); + Serial.println(); + } + + Serial.print("$D$"); + Serial.print(i); + Serial.print(','); + Serial.print(wdata.year); + Serial.print(','); + Serial.print(wdata.month); + Serial.print(','); + Serial.print(wdata.day); + Serial.print(','); + Serial.print(wdata.hour); + Serial.print(','); + Serial.print(wdata.minute); + Serial.print(','); + Serial.print((float)wdata.weight / 10.0f); + Serial.print(','); + Serial.print((float)wdata.fat / 10.0f); + Serial.print(','); + Serial.print((float)wdata.water / 10.0f); + Serial.print(','); + Serial.print((float)wdata.muscle / 10.0f); + Serial.print(','); + Serial.print(wdata.checksum); + Serial.print('\n'); + } + +} + +void clear_scale_data() +{ + int data_size = 0; + eeprom.writeBlock(0, (uint8_t*)&data_size, sizeof(data_size)); +} + +void loop() +{ + check_display_activity(); + + port_control = PINC; + port_digital_pinA = PIND; + port_digital_pinB = PINB; + + control_bit[0] = (port_control & (1 << 0)) ? 1 : 0; + control_bit[1] = (port_control & (1 << 1)) ? 1 : 0; + control_bit[2] = (port_control & (1 << 2)) ? 1 : 0; + control_bit[3] = (port_control & (1 << 3)) ? 1 : 0; + + if (control_bit[0] == LOW && control_bit[1] == HIGH && control_bit[2] == HIGH && control_bit[3] == HIGH) + { + set_seg_raw(0); + + } + else if (control_bit[0] == HIGH && control_bit[1] == LOW && control_bit[2] == HIGH && control_bit[3] == HIGH) + { + set_seg_raw(1); + + } + else if (control_bit[0] == HIGH && control_bit[1] == HIGH && control_bit[2] == LOW && control_bit[3] == HIGH) + { + set_seg_raw(2); + + } + else if (control_bit[0] == HIGH && control_bit[1] == HIGH && control_bit[2] == HIGH && control_bit[3] == LOW) + { + set_seg_raw(3); + + } + else if (control_bit[0] == HIGH && control_bit[1] == HIGH && control_bit[2] == HIGH && control_bit[3] == HIGH) + { + no_activity_cycles++; + } + + seg_value_1 = decode_seg(seg_raw_1_1, seg_raw_1_2); + seg_value_2 = decode_seg(seg_raw_2_1, seg_raw_2_2); + seg_value_3 = decode_seg(seg_raw_3_1, seg_raw_3_2); + seg_value_4 = decode_seg(seg_raw_4_1, seg_raw_4_2); + + if (seg_value_1 != -1 && seg_value_2 != -1 && seg_value_3 != -1 && seg_value_4 != -1) + { + seg_samples_1.add(seg_value_1); + seg_samples_2.add(seg_value_2); + seg_samples_3.add(seg_value_3); + seg_samples_4.add(seg_value_4); + + sample_count++; + } + + + if (sample_count > MAX_SAMPLE_SIZE) + { + seg_samples_1.getMedian(seg_value_1); + seg_samples_2.getMedian(seg_value_2); + seg_samples_3.getMedian(seg_value_3); + seg_samples_4.getMedian(seg_value_4); + + if (seg_value_4 == ' ') { + measured_weight = char_to_int(seg_value_1) + char_to_int(seg_value_2)*10 + char_to_int(seg_value_3)*100; + } + + if (seg_value_4 == 'F') { + measured_fat = char_to_int(seg_value_1) + char_to_int(seg_value_2)*10 + char_to_int(seg_value_3)*100; + } + + if (seg_value_4 == 'H') { + measured_water = char_to_int(seg_value_1) + char_to_int(seg_value_2)*10 + char_to_int(seg_value_3)*100; + } + + if (seg_value_4 == 'M') { + measured_muscle = char_to_int(seg_value_1) + char_to_int(seg_value_2)*10 + char_to_int(seg_value_3)*100; + } + + sample_count = 0; + } + + delay(10); + + + if (Serial.available() > 0) + { + char command = Serial.read(); + + switch(command) + { + case '0': + Serial.println("$I$ openScale MCU Version 1.0"); + break; + case '1': + Serial.println("$I$ Sending scale data!"); + send_scale_data(); + break; + case '9': + clear_scale_data(); + Serial.println("$I$ Scale data cleared!"); + break; + } + } +} + +int char_to_int(char c) +{ + if (c == ' ') + return 0; + + return (c - '0'); +} + +void print_debug_output() +{ + Serial.print("Debug Ausgabe\n"); + Serial.print("-----------------------------------\n"); + Serial.print("\nSeg 1\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_1_1[i]); + } + Serial.print("\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_1_2[i]); + } + + Serial.print("\nSeg 2\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_2_1[i]); + } + Serial.print("\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_2_2[i]); + } + + Serial.print("\nSeg 3\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_3_1[i]); + } + Serial.print("\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_3_2[i]); + } + + Serial.print("\nSeg 4\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_4_1[i]); + } + Serial.print("\n"); + for (int i=0; i<4; i++) + { + Serial.print(seg_raw_4_2[i]); + } + + Serial.print("\n-----------------------------------\n"); +}