TinyRTClib.cpp 7.0 KB

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