Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 21 | jlesech | 1 | // Code by JeeLabs http://news.jeelabs.org/code/ |
| 2 | // Released to the public domain! Enjoy! |
||
| 3 | |||
| 4 | #include <Wire.h> |
||
| 5 | #include <avr/pgmspace.h> |
||
| 6 | #include "RTClib.h" |
||
| 7 | |||
| 8 | #define DS1307_ADDRESS 0x68 |
||
| 9 | #define SECONDS_PER_DAY 86400L |
||
| 10 | |||
| 11 | #define SECONDS_FROM_1970_TO_2000 946684800 |
||
| 12 | |||
| 13 | #if (ARDUINO >= 100) |
||
| 14 | #include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems |
||
| 15 | #else |
||
| 16 | #include <WProgram.h> |
||
| 17 | #endif |
||
| 18 | |||
| 19 | int i = 0; //The new wire library needs to take an int when you are sending for the zero register |
||
| 20 | //////////////////////////////////////////////////////////////////////////////// |
||
| 21 | // utility code, some of this could be exposed in the DateTime API if needed |
||
| 22 | |||
| 23 | const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; //has to be const or compiler compaints |
||
| 24 | |||
| 25 | // number of days since 2000/01/01, valid for 2001..2099 |
||
| 26 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { |
||
| 27 | if (y >= 2000) |
||
| 28 | y -= 2000; |
||
| 29 | uint16_t days = d; |
||
| 30 | for (uint8_t i = 1; i < m; ++i) |
||
| 31 | days += pgm_read_byte(daysInMonth + i - 1); |
||
| 32 | if (m > 2 && y % 4 == 0) |
||
| 33 | ++days; |
||
| 34 | return days + 365 * y + (y + 3) / 4 - 1; |
||
| 35 | } |
||
| 36 | |||
| 37 | static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { |
||
| 38 | return ((days * 24L + h) * 60 + m) * 60 + s; |
||
| 39 | } |
||
| 40 | |||
| 41 | //////////////////////////////////////////////////////////////////////////////// |
||
| 42 | // DateTime implementation - ignores time zones and DST changes |
||
| 43 | // NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second |
||
| 44 | |||
| 45 | DateTime::DateTime (uint32_t t) { |
||
| 46 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 |
||
| 47 | |||
| 48 | ss = t % 60; |
||
| 49 | t /= 60; |
||
| 50 | mm = t % 60; |
||
| 51 | t /= 60; |
||
| 52 | hh = t % 24; |
||
| 53 | uint16_t days = t / 24; |
||
| 54 | uint8_t leap; |
||
| 55 | for (yOff = 0; ; ++yOff) { |
||
| 56 | leap = yOff % 4 == 0; |
||
| 57 | if (days < 365 + leap) |
||
| 58 | break; |
||
| 59 | days -= 365 + leap; |
||
| 60 | } |
||
| 61 | for (m = 1; ; ++m) { |
||
| 62 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); |
||
| 63 | if (leap && m == 2) |
||
| 64 | ++daysPerMonth; |
||
| 65 | if (days < daysPerMonth) |
||
| 66 | break; |
||
| 67 | days -= daysPerMonth; |
||
| 68 | } |
||
| 69 | d = days + 1; |
||
| 70 | } |
||
| 71 | |||
| 72 | DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { |
||
| 73 | if (year >= 2000) |
||
| 74 | year -= 2000; |
||
| 75 | yOff = year; |
||
| 76 | m = month; |
||
| 77 | d = day; |
||
| 78 | hh = hour; |
||
| 79 | mm = min; |
||
| 80 | ss = sec; |
||
| 81 | } |
||
| 82 | |||
| 83 | static uint8_t conv2d(const char* p) { |
||
| 84 | uint8_t v = 0; |
||
| 85 | if ('0' <= *p && *p <= '9') |
||
| 86 | v = *p - '0'; |
||
| 87 | return 10 * v + *++p - '0'; |
||
| 88 | } |
||
| 89 | |||
| 90 | // A convenient constructor for using "the compiler's time": |
||
| 91 | // DateTime now (__DATE__, __TIME__); |
||
| 92 | // NOTE: using PSTR would further reduce the RAM footprint |
||
| 93 | DateTime::DateTime (const char* date, const char* time) { |
||
| 94 | // sample input: date = "Dec 26 2009", time = "12:34:56" |
||
| 95 | yOff = conv2d(date + 9); |
||
| 96 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
||
| 97 | switch (date[0]) { |
||
| 98 | case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break; |
||
| 99 | case 'F': m = 2; break; |
||
| 100 | case 'A': m = date[2] == 'r' ? 4 : 8; break; |
||
| 101 | case 'M': m = date[2] == 'r' ? 3 : 5; break; |
||
| 102 | case 'S': m = 9; break; |
||
| 103 | case 'O': m = 10; break; |
||
| 104 | case 'N': m = 11; break; |
||
| 105 | case 'D': m = 12; break; |
||
| 106 | } |
||
| 107 | d = conv2d(date + 4); |
||
| 108 | hh = conv2d(time); |
||
| 109 | mm = conv2d(time + 3); |
||
| 110 | ss = conv2d(time + 6); |
||
| 111 | } |
||
| 112 | |||
| 113 | uint8_t DateTime::dayOfWeek() const { |
||
| 114 | uint16_t day = date2days(yOff, m, d); |
||
| 115 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 |
||
| 116 | } |
||
| 117 | |||
| 118 | uint32_t DateTime::unixtime(void) const { |
||
| 119 | uint32_t t; |
||
| 120 | uint16_t days = date2days(yOff, m, d); |
||
| 121 | t = time2long(days, hh, mm, ss); |
||
| 122 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 |
||
| 123 | |||
| 124 | return t; |
||
| 125 | } |
||
| 126 | |||
| 127 | //////////////////////////////////////////////////////////////////////////////// |
||
| 128 | // RTC_DS1307 implementation |
||
| 129 | |||
| 130 | static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); } |
||
| 131 | static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); } |
||
| 132 | |||
| 133 | uint8_t RTC_DS1307::begin(void) { |
||
| 134 | return 1; |
||
| 135 | } |
||
| 136 | |||
| 137 | |||
| 138 | #if (ARDUINO >= 100) |
||
| 139 | |||
| 140 | uint8_t RTC_DS1307::isrunning(void) { |
||
| 141 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 142 | Wire.write(i); |
||
| 143 | Wire.endTransmission(); |
||
| 144 | |||
| 145 | Wire.requestFrom(DS1307_ADDRESS, 1); |
||
| 146 | uint8_t ss = Wire.read(); |
||
| 147 | return !(ss>>7); |
||
| 148 | } |
||
| 149 | |||
| 150 | void RTC_DS1307::adjust(const DateTime& dt) { |
||
| 151 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 152 | Wire.write(i); |
||
| 153 | Wire.write(bin2bcd(dt.second())); |
||
| 154 | Wire.write(bin2bcd(dt.minute())); |
||
| 155 | Wire.write(bin2bcd(dt.hour())); |
||
| 156 | Wire.write(bin2bcd(0)); |
||
| 157 | Wire.write(bin2bcd(dt.day())); |
||
| 158 | Wire.write(bin2bcd(dt.month())); |
||
| 159 | Wire.write(bin2bcd(dt.year() - 2000)); |
||
| 160 | Wire.write(i); |
||
| 161 | Wire.endTransmission(); |
||
| 162 | } |
||
| 163 | |||
| 164 | DateTime RTC_DS1307::now() { |
||
| 165 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 166 | Wire.write(i); |
||
| 167 | Wire.endTransmission(); |
||
| 168 | |||
| 169 | Wire.requestFrom(DS1307_ADDRESS, 7); |
||
| 170 | uint8_t ss = bcd2bin(Wire.read() & 0x7F); |
||
| 171 | uint8_t mm = bcd2bin(Wire.read()); |
||
| 172 | uint8_t hh = bcd2bin(Wire.read()); |
||
| 173 | Wire.read(); |
||
| 174 | uint8_t d = bcd2bin(Wire.read()); |
||
| 175 | uint8_t m = bcd2bin(Wire.read()); |
||
| 176 | uint16_t y = bcd2bin(Wire.read()) + 2000; |
||
| 177 | |||
| 178 | return DateTime (y, m, d, hh, mm, ss); |
||
| 179 | } |
||
| 180 | |||
| 181 | #else |
||
| 182 | |||
| 183 | uint8_t RTC_DS1307::isrunning(void) { |
||
| 184 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 185 | Wire.send(i); |
||
| 186 | Wire.endTransmission(); |
||
| 187 | |||
| 188 | Wire.requestFrom(DS1307_ADDRESS, 1); |
||
| 189 | uint8_t ss = Wire.receive(); |
||
| 190 | return !(ss>>7); |
||
| 191 | } |
||
| 192 | |||
| 193 | void RTC_DS1307::adjust(const DateTime& dt) { |
||
| 194 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 195 | Wire.send(i); |
||
| 196 | Wire.send(bin2bcd(dt.second())); |
||
| 197 | Wire.send(bin2bcd(dt.minute())); |
||
| 198 | Wire.send(bin2bcd(dt.hour())); |
||
| 199 | Wire.send(bin2bcd(0)); |
||
| 200 | Wire.send(bin2bcd(dt.day())); |
||
| 201 | Wire.send(bin2bcd(dt.month())); |
||
| 202 | Wire.send(bin2bcd(dt.year() - 2000)); |
||
| 203 | Wire.send(i); |
||
| 204 | Wire.endTransmission(); |
||
| 205 | } |
||
| 206 | |||
| 207 | DateTime RTC_DS1307::now() { |
||
| 208 | Wire.beginTransmission(DS1307_ADDRESS); |
||
| 209 | Wire.send(i); |
||
| 210 | Wire.endTransmission(); |
||
| 211 | |||
| 212 | Wire.requestFrom(DS1307_ADDRESS, 7); |
||
| 213 | uint8_t ss = bcd2bin(Wire.receive() & 0x7F); |
||
| 214 | uint8_t mm = bcd2bin(Wire.receive()); |
||
| 215 | uint8_t hh = bcd2bin(Wire.receive()); |
||
| 216 | Wire.receive(); |
||
| 217 | uint8_t d = bcd2bin(Wire.receive()); |
||
| 218 | uint8_t m = bcd2bin(Wire.receive()); |
||
| 219 | uint16_t y = bcd2bin(Wire.receive()) + 2000; |
||
| 220 | |||
| 221 | return DateTime (y, m, d, hh, mm, ss); |
||
| 222 | } |
||
| 223 | |||
| 224 | #endif |
||
| 225 | |||
| 226 | |||
| 227 | //////////////////////////////////////////////////////////////////////////////// |
||
| 228 | // RTC_Millis implementation |
||
| 229 | |||
| 230 | long RTC_Millis::offset = 0; |
||
| 231 | |||
| 232 | void RTC_Millis::adjust(const DateTime& dt) { |
||
| 233 | offset = dt.unixtime() - millis() / 1000; |
||
| 234 | } |
||
| 235 | |||
| 236 | DateTime RTC_Millis::now() { |
||
| 237 | return (uint32_t)(offset + millis() / 1000); |
||
| 238 | } |
||
| 239 | |||
| 240 | //////////////////////////////////////////////////////////////////////////////// |