RTClib.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. // Code by JeeLabs http://news.jeelabs.org/code/
  2. // Released to the public domain! Enjoy!
  3. #include <Wire.h>
  4. #include "RTClib.h"
  5. #ifdef __AVR__
  6. #include <avr/pgmspace.h>
  7. #elif defined(ESP8266)
  8. #include <pgmspace.h>
  9. #elif defined(ARDUINO_ARCH_SAMD)
  10. // nothing special needed
  11. #elif defined(ARDUINO_SAM_DUE)
  12. #define PROGMEM
  13. #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
  14. #define Wire Wire1
  15. #endif
  16. #if (ARDUINO >= 100)
  17. #include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems
  18. // Macro to deal with the difference in I2C write functions from old and new Arduino versions.
  19. #define _I2C_WRITE write
  20. #define _I2C_READ read
  21. #else
  22. #include <WProgram.h>
  23. #define _I2C_WRITE send
  24. #define _I2C_READ receive
  25. #endif
  26. static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  27. Wire.beginTransmission(addr);
  28. Wire._I2C_WRITE((byte)reg);
  29. Wire.endTransmission();
  30. Wire.requestFrom(addr, (byte)1);
  31. return Wire._I2C_READ();
  32. }
  33. static void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  34. Wire.beginTransmission(addr);
  35. Wire._I2C_WRITE((byte)reg);
  36. Wire._I2C_WRITE((byte)val);
  37. Wire.endTransmission();
  38. }
  39. ////////////////////////////////////////////////////////////////////////////////
  40. // utility code, some of this could be exposed in the DateTime API if needed
  41. const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
  42. // number of days since 2000/01/01, valid for 2001..2099
  43. static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
  44. if (y >= 2000)
  45. y -= 2000;
  46. uint16_t days = d;
  47. for (uint8_t i = 1; i < m; ++i)
  48. days += pgm_read_byte(daysInMonth + i - 1);
  49. if (m > 2 && y % 4 == 0)
  50. ++days;
  51. return days + 365 * y + (y + 3) / 4 - 1;
  52. }
  53. static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
  54. return ((days * 24L + h) * 60 + m) * 60 + s;
  55. }
  56. ////////////////////////////////////////////////////////////////////////////////
  57. // DateTime implementation - ignores time zones and DST changes
  58. // NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second
  59. DateTime::DateTime (uint32_t t) {
  60. t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970
  61. ss = t % 60;
  62. t /= 60;
  63. mm = t % 60;
  64. t /= 60;
  65. hh = t % 24;
  66. uint16_t days = t / 24;
  67. uint8_t leap;
  68. for (yOff = 0; ; ++yOff) {
  69. leap = yOff % 4 == 0;
  70. if (days < 365 + leap)
  71. break;
  72. days -= 365 + leap;
  73. }
  74. for (m = 1; ; ++m) {
  75. uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
  76. if (leap && m == 2)
  77. ++daysPerMonth;
  78. if (days < daysPerMonth)
  79. break;
  80. days -= daysPerMonth;
  81. }
  82. d = days + 1;
  83. }
  84. DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
  85. if (year >= 2000)
  86. year -= 2000;
  87. yOff = year;
  88. m = month;
  89. d = day;
  90. hh = hour;
  91. mm = min;
  92. ss = sec;
  93. }
  94. DateTime::DateTime (const DateTime& copy):
  95. yOff(copy.yOff),
  96. m(copy.m),
  97. d(copy.d),
  98. hh(copy.hh),
  99. mm(copy.mm),
  100. ss(copy.ss)
  101. {}
  102. static uint8_t conv2d(const char* p) {
  103. uint8_t v = 0;
  104. if ('0' <= *p && *p <= '9')
  105. v = *p - '0';
  106. return 10 * v + *++p - '0';
  107. }
  108. // A convenient constructor for using "the compiler's time":
  109. // DateTime now (__DATE__, __TIME__);
  110. // NOTE: using F() would further reduce the RAM footprint, see below.
  111. DateTime::DateTime (const char* date, const char* time) {
  112. // sample input: date = "Dec 26 2009", time = "12:34:56"
  113. yOff = conv2d(date + 9);
  114. // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
  115. switch (date[0]) {
  116. case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break;
  117. case 'F': m = 2; break;
  118. case 'A': m = date[2] == 'r' ? 4 : 8; break;
  119. case 'M': m = date[2] == 'r' ? 3 : 5; break;
  120. case 'S': m = 9; break;
  121. case 'O': m = 10; break;
  122. case 'N': m = 11; break;
  123. case 'D': m = 12; break;
  124. }
  125. d = conv2d(date + 4);
  126. hh = conv2d(time);
  127. mm = conv2d(time + 3);
  128. ss = conv2d(time + 6);
  129. }
  130. // A convenient constructor for using "the compiler's time":
  131. // This version will save RAM by using PROGMEM to store it by using the F macro.
  132. // DateTime now (F(__DATE__), F(__TIME__));
  133. DateTime::DateTime (const __FlashStringHelper* date, const __FlashStringHelper* time) {
  134. // sample input: date = "Dec 26 2009", time = "12:34:56"
  135. char buff[11];
  136. memcpy_P(buff, date, 11);
  137. yOff = conv2d(buff + 9);
  138. // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
  139. switch (buff[0]) {
  140. case 'J': m = buff[1] == 'a' ? 1 : m = buff[2] == 'n' ? 6 : 7; break;
  141. case 'F': m = 2; break;
  142. case 'A': m = buff[2] == 'r' ? 4 : 8; break;
  143. case 'M': m = buff[2] == 'r' ? 3 : 5; break;
  144. case 'S': m = 9; break;
  145. case 'O': m = 10; break;
  146. case 'N': m = 11; break;
  147. case 'D': m = 12; break;
  148. }
  149. d = conv2d(buff + 4);
  150. memcpy_P(buff, time, 8);
  151. hh = conv2d(buff);
  152. mm = conv2d(buff + 3);
  153. ss = conv2d(buff + 6);
  154. }
  155. uint8_t DateTime::dayOfTheWeek() const {
  156. uint16_t day = date2days(yOff, m, d);
  157. return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
  158. }
  159. uint32_t DateTime::unixtime(void) const {
  160. uint32_t t;
  161. uint16_t days = date2days(yOff, m, d);
  162. t = time2long(days, hh, mm, ss);
  163. t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
  164. return t;
  165. }
  166. long DateTime::secondstime(void) const {
  167. long t;
  168. uint16_t days = date2days(yOff, m, d);
  169. t = time2long(days, hh, mm, ss);
  170. return t;
  171. }
  172. DateTime DateTime::operator+(const TimeSpan& span) {
  173. return DateTime(unixtime()+span.totalseconds());
  174. }
  175. DateTime DateTime::operator-(const TimeSpan& span) {
  176. return DateTime(unixtime()-span.totalseconds());
  177. }
  178. TimeSpan DateTime::operator-(const DateTime& right) {
  179. return TimeSpan(unixtime()-right.unixtime());
  180. }
  181. ////////////////////////////////////////////////////////////////////////////////
  182. // TimeSpan implementation
  183. TimeSpan::TimeSpan (int32_t seconds):
  184. _seconds(seconds)
  185. {}
  186. TimeSpan::TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds):
  187. _seconds((int32_t)days*86400L + (int32_t)hours*3600 + (int32_t)minutes*60 + seconds)
  188. {}
  189. TimeSpan::TimeSpan (const TimeSpan& copy):
  190. _seconds(copy._seconds)
  191. {}
  192. TimeSpan TimeSpan::operator+(const TimeSpan& right) {
  193. return TimeSpan(_seconds+right._seconds);
  194. }
  195. TimeSpan TimeSpan::operator-(const TimeSpan& right) {
  196. return TimeSpan(_seconds-right._seconds);
  197. }
  198. ////////////////////////////////////////////////////////////////////////////////
  199. // RTC_DS1307 implementation
  200. static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
  201. static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
  202. boolean RTC_DS1307::begin(void) {
  203. Wire.begin();
  204. return true;
  205. }
  206. uint8_t RTC_DS1307::isrunning(void) {
  207. Wire.beginTransmission(DS1307_ADDRESS);
  208. Wire._I2C_WRITE((byte)0);
  209. Wire.endTransmission();
  210. Wire.requestFrom(DS1307_ADDRESS, 1);
  211. uint8_t ss = Wire._I2C_READ();
  212. return !(ss>>7);
  213. }
  214. void RTC_DS1307::adjust(const DateTime& dt) {
  215. Wire.beginTransmission(DS1307_ADDRESS);
  216. Wire._I2C_WRITE((byte)0); // start at location 0
  217. Wire._I2C_WRITE(bin2bcd(dt.second()));
  218. Wire._I2C_WRITE(bin2bcd(dt.minute()));
  219. Wire._I2C_WRITE(bin2bcd(dt.hour()));
  220. Wire._I2C_WRITE(bin2bcd(0));
  221. Wire._I2C_WRITE(bin2bcd(dt.day()));
  222. Wire._I2C_WRITE(bin2bcd(dt.month()));
  223. Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  224. Wire.endTransmission();
  225. }
  226. DateTime RTC_DS1307::now() {
  227. Wire.beginTransmission(DS1307_ADDRESS);
  228. Wire._I2C_WRITE((byte)0);
  229. Wire.endTransmission();
  230. Wire.requestFrom(DS1307_ADDRESS, 7);
  231. uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  232. uint8_t mm = bcd2bin(Wire._I2C_READ());
  233. uint8_t hh = bcd2bin(Wire._I2C_READ());
  234. Wire._I2C_READ();
  235. uint8_t d = bcd2bin(Wire._I2C_READ());
  236. uint8_t m = bcd2bin(Wire._I2C_READ());
  237. uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  238. return DateTime (y, m, d, hh, mm, ss);
  239. }
  240. Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() {
  241. int mode;
  242. Wire.beginTransmission(DS1307_ADDRESS);
  243. Wire._I2C_WRITE(DS1307_CONTROL);
  244. Wire.endTransmission();
  245. Wire.requestFrom((uint8_t)DS1307_ADDRESS, (uint8_t)1);
  246. mode = Wire._I2C_READ();
  247. mode &= 0x93;
  248. return static_cast<Ds1307SqwPinMode>(mode);
  249. }
  250. void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) {
  251. Wire.beginTransmission(DS1307_ADDRESS);
  252. Wire._I2C_WRITE(DS1307_CONTROL);
  253. Wire._I2C_WRITE(mode);
  254. Wire.endTransmission();
  255. }
  256. void RTC_DS1307::readnvram(uint8_t* buf, uint8_t size, uint8_t address) {
  257. int addrByte = DS1307_NVRAM + address;
  258. Wire.beginTransmission(DS1307_ADDRESS);
  259. Wire._I2C_WRITE(addrByte);
  260. Wire.endTransmission();
  261. Wire.requestFrom((uint8_t) DS1307_ADDRESS, size);
  262. for (uint8_t pos = 0; pos < size; ++pos) {
  263. buf[pos] = Wire._I2C_READ();
  264. }
  265. }
  266. void RTC_DS1307::writenvram(uint8_t address, uint8_t* buf, uint8_t size) {
  267. int addrByte = DS1307_NVRAM + address;
  268. Wire.beginTransmission(DS1307_ADDRESS);
  269. Wire._I2C_WRITE(addrByte);
  270. for (uint8_t pos = 0; pos < size; ++pos) {
  271. Wire._I2C_WRITE(buf[pos]);
  272. }
  273. Wire.endTransmission();
  274. }
  275. uint8_t RTC_DS1307::readnvram(uint8_t address) {
  276. uint8_t data;
  277. readnvram(&data, 1, address);
  278. return data;
  279. }
  280. void RTC_DS1307::writenvram(uint8_t address, uint8_t data) {
  281. writenvram(address, &data, 1);
  282. }
  283. ////////////////////////////////////////////////////////////////////////////////
  284. // RTC_Millis implementation
  285. long RTC_Millis::offset = 0;
  286. void RTC_Millis::adjust(const DateTime& dt) {
  287. offset = dt.unixtime() - millis() / 1000;
  288. }
  289. DateTime RTC_Millis::now() {
  290. return (uint32_t)(offset + millis() / 1000);
  291. }
  292. ////////////////////////////////////////////////////////////////////////////////
  293. ////////////////////////////////////////////////////////////////////////////////
  294. // RTC_PCF8563 implementation
  295. boolean RTC_PCF8523::begin(void) {
  296. Wire.begin();
  297. return true;
  298. }
  299. boolean RTC_PCF8523::initialized(void) {
  300. Wire.beginTransmission(PCF8523_ADDRESS);
  301. Wire._I2C_WRITE((byte)PCF8523_CONTROL_3);
  302. Wire.endTransmission();
  303. Wire.requestFrom(PCF8523_ADDRESS, 1);
  304. uint8_t ss = Wire._I2C_READ();
  305. return ((ss & 0xE0) != 0xE0);
  306. }
  307. void RTC_PCF8523::adjust(const DateTime& dt) {
  308. Wire.beginTransmission(PCF8523_ADDRESS);
  309. Wire._I2C_WRITE((byte)3); // start at location 3
  310. Wire._I2C_WRITE(bin2bcd(dt.second()));
  311. Wire._I2C_WRITE(bin2bcd(dt.minute()));
  312. Wire._I2C_WRITE(bin2bcd(dt.hour()));
  313. Wire._I2C_WRITE(bin2bcd(dt.day()));
  314. Wire._I2C_WRITE(bin2bcd(0)); // skip weekdays
  315. Wire._I2C_WRITE(bin2bcd(dt.month()));
  316. Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  317. Wire.endTransmission();
  318. // set to battery switchover mode
  319. Wire.beginTransmission(PCF8523_ADDRESS);
  320. Wire._I2C_WRITE((byte)PCF8523_CONTROL_3);
  321. Wire._I2C_WRITE((byte)0x00);
  322. Wire.endTransmission();
  323. }
  324. DateTime RTC_PCF8523::now() {
  325. Wire.beginTransmission(PCF8523_ADDRESS);
  326. Wire._I2C_WRITE((byte)3);
  327. Wire.endTransmission();
  328. Wire.requestFrom(PCF8523_ADDRESS, 7);
  329. uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  330. uint8_t mm = bcd2bin(Wire._I2C_READ());
  331. uint8_t hh = bcd2bin(Wire._I2C_READ());
  332. uint8_t d = bcd2bin(Wire._I2C_READ());
  333. Wire._I2C_READ(); // skip 'weekdays'
  334. uint8_t m = bcd2bin(Wire._I2C_READ());
  335. uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  336. return DateTime (y, m, d, hh, mm, ss);
  337. }
  338. Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() {
  339. int mode;
  340. Wire.beginTransmission(PCF8523_ADDRESS);
  341. Wire._I2C_WRITE(PCF8523_CLKOUTCONTROL);
  342. Wire.endTransmission();
  343. Wire.requestFrom((uint8_t)PCF8523_ADDRESS, (uint8_t)1);
  344. mode = Wire._I2C_READ();
  345. mode >>= 3;
  346. mode &= 0x7;
  347. return static_cast<Pcf8523SqwPinMode>(mode);
  348. }
  349. void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) {
  350. Wire.beginTransmission(PCF8523_ADDRESS);
  351. Wire._I2C_WRITE(PCF8523_CLKOUTCONTROL);
  352. Wire._I2C_WRITE(mode << 3);
  353. Wire.endTransmission();
  354. }
  355. ////////////////////////////////////////////////////////////////////////////////
  356. // RTC_DS3231 implementation
  357. boolean RTC_DS3231::begin(void) {
  358. Wire.begin();
  359. return true;
  360. }
  361. bool RTC_DS3231::lostPower(void) {
  362. return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7);
  363. }
  364. void RTC_DS3231::adjust(const DateTime& dt) {
  365. Wire.beginTransmission(DS3231_ADDRESS);
  366. Wire._I2C_WRITE((byte)0); // start at location 0
  367. Wire._I2C_WRITE(bin2bcd(dt.second()));
  368. Wire._I2C_WRITE(bin2bcd(dt.minute()));
  369. Wire._I2C_WRITE(bin2bcd(dt.hour()));
  370. Wire._I2C_WRITE(bin2bcd(0));
  371. Wire._I2C_WRITE(bin2bcd(dt.day()));
  372. Wire._I2C_WRITE(bin2bcd(dt.month()));
  373. Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  374. Wire.endTransmission();
  375. uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
  376. statreg &= ~0x80; // flip OSF bit
  377. write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
  378. }
  379. DateTime RTC_DS3231::now() {
  380. Wire.beginTransmission(DS3231_ADDRESS);
  381. Wire._I2C_WRITE((byte)0);
  382. Wire.endTransmission();
  383. Wire.requestFrom(DS3231_ADDRESS, 7);
  384. uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  385. uint8_t mm = bcd2bin(Wire._I2C_READ());
  386. uint8_t hh = bcd2bin(Wire._I2C_READ());
  387. Wire._I2C_READ();
  388. uint8_t d = bcd2bin(Wire._I2C_READ());
  389. uint8_t m = bcd2bin(Wire._I2C_READ());
  390. uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  391. return DateTime (y, m, d, hh, mm, ss);
  392. }
  393. Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
  394. int mode;
  395. Wire.beginTransmission(DS3231_ADDRESS);
  396. Wire._I2C_WRITE(DS3231_CONTROL);
  397. Wire.endTransmission();
  398. Wire.requestFrom((uint8_t)DS3231_ADDRESS, (uint8_t)1);
  399. mode = Wire._I2C_READ();
  400. mode &= 0x93;
  401. return static_cast<Ds3231SqwPinMode>(mode);
  402. }
  403. void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
  404. uint8_t ctrl;
  405. ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
  406. ctrl &= ~0x04; // turn off INTCON
  407. ctrl &= ~0x18; // set freq bits to 0
  408. if (mode == DS3231_OFF) {
  409. ctrl |= 0x04; // turn on INTCN
  410. } else {
  411. ctrl |= mode;
  412. }
  413. write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl);
  414. //Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);
  415. }