BayEOS-Arduino  1.8.0_0.0.4
RTClib.cpp
1 //>>> The latest version of this code can be found at https://github.com/jcw/ !!
2 
3 // A library for handling real-time clocks, dates, etc.
4 // 2010-02-04 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php
5 // $Id: RTClib.cpp 7763 2011-12-11 01:28:16Z jcw $
6 // A library for handling real-time clocks, dates, etc.
7 // 2010-02-04 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
8 
9 #include <avr/pgmspace.h>
10 #include "RTClib.h"
11 #include <Arduino.h>
12 
13 #define DS1307_ADDRESS 0x68
14 
15 #define PCF8563_ADDRESS 0x51
16 #define PCF8563_SEC_ADDR 0x02
17 
18 /*Periodicity */
19 #define EverySecond 0
20 #define EveryMinute 1
21 #define EveryHour 2
22 #define EveryMonth 3
23 
24 #define DS3231_ADDRESS 0x68 //I2C Slave address
25 
26 /* DS3231 Registers. Refer Sec 8.2 of application manual */
27 #define DS3231_SEC_REG 0x00
28 #define DS3231_MIN_REG 0x01
29 #define DS3231_HOUR_REG 0x02
30 #define DS3231_WDAY_REG 0x03
31 #define DS3231_MDAY_REG 0x04
32 #define DS3231_MONTH_REG 0x05
33 #define DS3231_YEAR_REG 0x06
34 
35 #define DS3231_AL1SEC_REG 0x07
36 #define DS3231_AL1MIN_REG 0x08
37 #define DS3231_AL1HOUR_REG 0x09
38 #define DS3231_AL1WDAY_REG 0x0A
39 
40 #define DS3231_AL2MIN_REG 0x0B
41 #define DS3231_AL2HOUR_REG 0x0C
42 #define DS3231_AL2WDAY_REG 0x0D
43 
44 #define DS3231_CONTROL_REG 0x0E
45 #define DS3231_STATUS_REG 0x0F
46 #define DS3231_AGING_OFFSET_REG 0x0F
47 #define DS3231_TMP_UP_REG 0x11
48 #define DS3231_TMP_LOW_REG 0x12
49 
50 
51 #define PERIODIC_INTERRUPT 0x00
52 #define HM_INTERRUPT 0x01
53 
54 #define RX8025_ADDRESS 0x32 //I2C Slave address
55 
56 /* RX8025 Registers. Refer Sec 8.2 of application manual */
57 #define RX8025_SEC_REG 0x00
58 #define RX8025_MIN_REG 0x10
59 #define RX8025_HOUR_REG 0x20
60 #define RX8025_WDAY_REG 0x30
61 #define RX8025_MDAY_REG 0x40
62 #define RX8025_MONTH_REG 0x50
63 #define RX8025_YEAR_REG 0x60
64 #define RX8025_DIGOFF_REG 0x70
65 #define RX8025_ALWMIN_REG 0x80
66 #define RX8025_ALWHOUR_REG 0x90
67 #define RX8025_ALWWDAY_REG 0xA0
68 #define RX8025_ALDMIN_REG 0xB0
69 #define RX8025_ALDHOUR_REG 0xC0
70 #define RX8025_RESERVED_REG 0xD0
71 #define RX8025_CTRL1_REG 0xE0
72 #define RX8025_CTRL2_REG 0xF0
73 
74 #define RX8025_CTRL1_CT_BIT (7 << 0)
75 
76 /* periodic level interrupts used for powersaving mode of MCU*/
77 #define RX8025_CTRL1_CT_PER_OFF 0
78 #define RX8025_CTRL1_CT_PER_SEC 4
79 #define RX8025_CTRL1_CT_PER_MIN 5
80 #define RX8025_CTRL1_CT_PER_HOUR 6
81 #define RX8025_CTRL1_CT_PER_MONTH 7
82 
83 
84 //CTRL1 and CTLR2 register bits
85 
86 #define RX8025_CTRL1_TEST_BIT (1 << 3)
87 #define RX8025_CTRL1_1224_BIT (1 << 5)
88 #define RX8025_CTRL1_DALE_BIT (1 << 6)
89 #define RX8025_CTRL1_WALE_BIT (1 << 7)
90 
91 #define RX8025_CTRL2_DAFG_BIT (1 << 0)
92 #define RX8025_CTRL2_WAFG_BIT (1 << 1)
93 #define RX8025_CTRL2_CTFG_BIT (1 << 2)
94 #define RX8025_CTRL2_CLEN1_BIT (1 << 3)
95 #define RX8025_CTRL2_PON_BIT (1 << 4)
96 #define RX8025_CTRL2_XST_BIT (1 << 5)
97 #define RX8025_CTRL2_VDET_BIT (1 << 6)
98 #define RX8025_CTRL2_VDSL_BIT (1 << 7)
99 
100 
101 // indices within the rtc_bcd[] buffer
102 #define DS1337_SEC 0
103 #define DS1337_MIN 1
104 #define DS1337_HR 2
105 #define DS1337_DOW 3
106 #define DS1337_DATE 4
107 #define DS1337_MTH 5
108 #define DS1337_YR 6
109 
110 #define DS1337_BASE_YR 2000
111 
112 #define DS1337_CTRL_ID B1101000
113 
114  // Define register bit masks
115 #define DS1337_CLOCKHALT B10000000
116 
117 #define DS1337_LO_BCD B00001111
118 #define DS1337_HI_BCD B11110000
119 
120 #define DS1337_HI_SEC B01110000
121 #define DS1337_HI_MIN B01110000
122 #define DS1337_HI_HR B00110000
123 #define DS1337_LO_DOW B00000111
124 #define DS1337_HI_DATE B00110000
125 #define DS1337_HI_MTH B00110000
126 #define DS1337_HI_YR B11110000
127 
128 #define DS1337_ARLM1 0x07
129 #define DS1337_ARLM1_LO_SEC B00001111
130 #define DS1337_ARLM1_HI_SEC B01110000
131 #define DS1337_ARLM1_LO_MIN B01110000
132 #define DS1337_ARLM1_HI_MIN B00001111
133 
134 #define DS1337_SP 0x0E
135 #define DS1337_SP_EOSC B10000000
136 #define DS1337_SP_RS2 B00010000
137 #define DS1337_SP_RS1 B00001000
138 #define DS1337_SP_INTCN B00000100
139 #define DS1337_SP_A2IE B00000010
140 #define DS1337_SP_A1IE B00000001
141 
142 #define DS1337_STATUS 0x0F
143 #define DS1337_STATUS_OSF B10000000
144 #define DS1337_STATUS_A2F B00000010
145 #define DS1337_STATUS_A1F B00000001
146 
147 /* Definitions for alarm repeat */
148 /* The private variable alarm_repeat holds the user's alarm repeat preference. However, the DS1337 encodes these in the topmost bit(s) of the 4 alarm registers. */
149 /* Splattering these bits across the alarm regs is handled in the writeAlarm() function. */
150 /* If DY/DT is set, the day field is interpreted as a DayOfWeek (1 ~ 7), else it is interpreted as a DayOfMonth.*/
151 
152 /* user alarm_repeat bit mask:
153  7 6 5 4 3 2 1 0
154  [x x x A1M4 DY/DT A1M3 A1M2 A1M1]
155 */
156 
157 #define DS1337_EVERY_SECOND B00010111
158 #define DS1337_EVERY_MINUTE B00010110
159 #define DS1337_EVERY_HOUR B00010100
160 #define DS1337_EVERY_DAY B00010000
161 #define DS1337_EVERY_WEEK B00001000
162 #define DS1337_EVERY_MONTH B00000000
163 
164 
165 
167 // utility code, some of this could be exposed in the DateTime API if needed
168 static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
169 static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
170 
171 
173 // RTC_DS1307 implementation
174 
175 void RTC_DS1307::adjust(const DateTime& dt) {
176  Wire.beginTransmission(DS1307_ADDRESS);
177  Wire.write((byte) 0);
178  Wire.write(bin2bcd(dt.second()));
179  Wire.write(bin2bcd(dt.minute()));
180  Wire.write(bin2bcd(dt.hour()));
181  Wire.write(bin2bcd(0));
182  Wire.write(bin2bcd(dt.day()));
183  Wire.write(bin2bcd(dt.month()));
184  Wire.write(bin2bcd(dt.year() - 2000));
185  Wire.write((byte) 0);
186  Wire.endTransmission();
187 }
188 
189 DateTime RTC_DS1307::now() {
190  Wire.beginTransmission(DS1307_ADDRESS);
191  Wire.write((byte) 0);
192  Wire.endTransmission();
193 
194  Wire.requestFrom(DS1307_ADDRESS, 7);
195  uint8_t ss = bcd2bin(Wire.read());
196  uint8_t mm = bcd2bin(Wire.read());
197  uint8_t hh = bcd2bin(Wire.read());
198  Wire.read();
199  uint8_t d = bcd2bin(Wire.read());
200  uint8_t m = bcd2bin(Wire.read());
201  uint16_t y = bcd2bin(Wire.read()) + 2000;
202 
203  return DateTime (y, m, d, hh, mm, ss);
204 }
205 
207 // RTC_PCF8563 implementation
208 // contributed by @mariusster, see http://forum.jeelabs.net/comment/1902
209 
210 void RTC_PCF8563::adjust(const DateTime& dt) {
211  Wire.beginTransmission(PCF8563_ADDRESS);
212  Wire.write((byte) 0);
213  Wire.write((byte) 0x0); // control/status1
214  Wire.write((byte) 0x0); // control/status2
215  Wire.write(bin2bcd(dt.second())); // set seconds
216  Wire.write(bin2bcd(dt.minute())); // set minutes
217  Wire.write(bin2bcd(dt.hour())); // set hour
218  Wire.write(bin2bcd(dt.day())); // set day
219  Wire.write((byte) 0x01); // set weekday
220  Wire.write(bin2bcd(dt.month())); // set month, century to 1
221  Wire.write(bin2bcd(dt.year() - 2000)); // set year to 00-99
222  Wire.write((byte) 0x80); // minute alarm value reset to 00
223  Wire.write((byte) 0x80); // hour alarm value reset to 00
224  Wire.write((byte) 0x80); // day alarm value reset to 00
225  Wire.write((byte) 0x80); // weekday alarm value reset to 00
226  Wire.write((byte) 0x0); // set freqout 0= 32768khz, 1= 1hz
227  Wire.write((byte) 0x0); // timer off
228  Wire.endTransmission();
229 }
230 
231 DateTime RTC_PCF8563::now() {
232  Wire.beginTransmission(PCF8563_ADDRESS);
233  Wire.write(PCF8563_SEC_ADDR);
234  Wire.endTransmission();
235 
236  Wire.requestFrom(PCF8563_ADDRESS, 7);
237  uint8_t ss = bcd2bin(Wire.read() & 0x7F);
238  uint8_t mm = bcd2bin(Wire.read() & 0x7F);
239  uint8_t hh = bcd2bin(Wire.read() & 0x3F);
240  uint8_t d = bcd2bin(Wire.read() & 0x3F);
241  Wire.read();
242  uint8_t m = bcd2bin(Wire.read()& 0x1F);
243  uint16_t y = bcd2bin(Wire.read()) + 2000;
244 
245  return DateTime (y, m, d, hh, mm, ss);
246 }
247 
249 // RTC_Timer2 implementation
250 
251 void RTC_Timer2::adjust(const DateTime& dt) {
252  noInterrupts();
253  _seconds = dt.get();
254  interrupts();
255 }
256 
257 DateTime RTC_Timer2::now() {
258  noInterrupts();
259  unsigned long s=_seconds;
260  interrupts();
261  return s;
262 }
263 
265 // RTC_Millis implementation
266 
267 long RTC_Millis::offset = 0;
268 
269 void RTC_Millis::adjust(const DateTime& dt) {
270  offset = dt.get() - millis() / 1000;
271 }
272 
273 DateTime RTC_Millis::now() {
274  return offset + millis() / 1000;
275 }
276 
278 // RTC RX8025 implementation
279 
280 void R8025::begin(void) {
281  unsigned char ctReg1=0, ctReg2=0;
282  Wire.beginTransmission(RX8025_ADDRESS);
283  Wire.write((byte)RX8025_CTRL1_REG); //CTRL1 Address
284  // set the clock to 24hr format
285  ctReg1 |= RX8025_CTRL1_1224_BIT;
286  Wire.write((byte)ctReg1);
287  //Set VDSL and XST bits. Also clear PON (power on reset) flag.
288  Wire.write((byte)(RX8025_CTRL2_VDSL_BIT | RX8025_CTRL2_XST_BIT ));
289  Wire.endTransmission();
290  delay(10);
291 
292 }
293 
294 //Adjust the time-date specified in DateTime format
295 //writing any non-existent time-data may interfere with normal operation of the RTC
296 void R8025::adjust(const DateTime& dt) {
297 
298  Wire.beginTransmission(RX8025_ADDRESS);
299  Wire.write((byte)RX8025_SEC_REG); //beginning from SEC Register address
300 
301  Wire.write(bin2bcd(dt.second()));
302  Wire.write(bin2bcd(dt.minute()));
303  Wire.write(bin2bcd(dt.hour()));
304  Wire.write(dt.dayOfWeek());
305  Wire.write(bin2bcd(dt.day()));
306  Wire.write(bin2bcd(dt.month()));
307  Wire.write(bin2bcd(dt.year() - 2000));
308 
309  Wire.endTransmission();
310 
311 }
312 
313 //Read the current time-date and return it in DateTime format
314 DateTime R8025::now() {
315  Wire.beginTransmission(RX8025_ADDRESS);
316  Wire.write((byte)0x00);
317  Wire.endTransmission();
318 
319  Wire.requestFrom(RX8025_ADDRESS, 8);
320  Wire.read(); //ignore this data read from 0xF. Refer app note. Only Mode 3 Read operation
321  // is supported by wire library. i.e 0xF->0x0->0x2
322  uint8_t ss = bcd2bin(Wire.read());
323  uint8_t mm = bcd2bin(Wire.read());
324  uint8_t hh = bcd2bin(Wire.read());
325  uint8_t wd = Wire.read();
326  uint8_t d = bcd2bin(Wire.read());
327  uint8_t m = bcd2bin(Wire.read());
328  uint16_t y = bcd2bin(Wire.read()) + 2000;
329 
330  return DateTime (y, m, d, hh, mm, ss);
331 }
332 
333 //Enable periodic interrupt at /INTA pin. Supports only the level interrupt
334 //for consistency with other /INTA interrupts. All interrupts works like single-shot counter
335 //Use refreshINTA() to re-enable interrupt.
336 void R8025::enableINTA_Interrupts(uint8_t periodicity)
337 {
338  intType=PERIODIC_INTERRUPT; //Record interrupt type and periodicity for use of refreshINTA() method
339  intPeriodicity=periodicity;
340 
341  uint8_t ctReg1= periodicity + 4;
342  /*
343  The above statement maps the periodicity defines from 0-3 into actual register value to be set for that mode.
344  This arithmetic operation is simpler and faster than switch-case or if-else... Hence,
345 
346  EverySecond maps to RX8025_CTRL1_CT_PER_SEC
347  EveryMinute maps to RX8025_CTRL1_CT_PER_MIN
348  EveryHour maps to RX8025_CTRL1_CT_PER_HOUR
349  EveryMonth maps to RX8025_CTRL1_CT_PER_MONTH
350 
351 */
352  //Maintain the clock in 24 Hour format
353  ctReg1 |= RX8025_CTRL1_1224_BIT ;
354  Wire.beginTransmission(RX8025_ADDRESS);
355  Wire.write(RX8025_CTRL1_REG);
356  Wire.write(ctReg1);
357  Wire.endTransmission();
358  delay(10);
359 
360  //set XST and VDSL flags.Clear all other flags
361  Wire.beginTransmission(RX8025_ADDRESS);
362  uint8_t ctReg2 = RX8025_CTRL2_XST_BIT | RX8025_CTRL2_VDSL_BIT;
363  Wire.write(RX8025_CTRL2_REG);
364  Wire.write(ctReg2);
365  Wire.endTransmission();
366  delay(10);
367 }
368 
369 //Enable HH/MM interrupt on /INTA pin. All interrupts works like single-shot counter
370 //Use refreshINTA() to re-enable interrupt.
371 void R8025::enableINTA_Interrupts(uint8_t hh24, uint8_t mm)
372 {
373  // hh24 is hours in 24 format (0-23). mm is in minutes(0 - 59)
374  intType=HM_INTERRUPT; //Record interrupt type, hh24 and mm for use of refreshINTA() method
375  intHH24 = hh24;
376  intMM = mm;
377 
378  Wire.beginTransmission(RX8025_ADDRESS);
379  Wire.write(RX8025_CTRL1_REG); //CTRL1 Address
380  //Set DALE bit to 0 and take care of other bits of CTRL1
381  Wire.write(RX8025_CTRL1_1224_BIT);
382  Wire.endTransmission();
383 
384  Wire.beginTransmission(RX8025_ADDRESS);
385  Wire.write(RX8025_ALDMIN_REG); //ALD Minute register Address
386  Wire.write(bin2bcd(mm));
387  Wire.write(bin2bcd(hh24));
388  Wire.endTransmission();
389 
390  Wire.beginTransmission(RX8025_ADDRESS);
391  Wire.write(RX8025_CTRL2_REG); //CTRL2 Address
392  //Set DAFG bit to 0 and take care of other bits of CTRL2
393  Wire.write(RX8025_CTRL2_VDSL_BIT | RX8025_CTRL2_XST_BIT );
394  Wire.endTransmission();
395 
396  Wire.beginTransmission(RX8025_ADDRESS);
397  Wire.write(RX8025_CTRL1_REG); //CTRL1 Address
398  //Set DALE bit to 1 and take care of other bits of CTRL1
399  Wire.write(RX8025_CTRL1_1224_BIT | RX8025_CTRL1_DALE_BIT);
400  Wire.endTransmission();
401 
402 }
403 
404 //Disable Interrupts. This is equivalent to begin() method.
405 void R8025::disableINTA_Interrupts()
406 {
407  begin(); //Restore the to initial value.
408 }
409 
410 //This method must be called after an interrupt is detected. This refreshes the interrupt.
411 void R8025::refreshINTA()
412 {
413 
414  if(intType==PERIODIC_INTERRUPT)
415  {
416  //It is essential to clear CTFG flag to make /INTA high. Otherwise next interrupt will not be
417  //detected by MCU. This is mentioned in page-19 timing-diagram of RX8025 App manual
418  enableINTA_Interrupts(intPeriodicity); //Writing to CTRL2 is sufficient. But calling this method
419  //is equilvalent for cleatring flag and setting Level interrupt.
420  }
421  else if(intType==HM_INTERRUPT)
422  {
423  enableINTA_Interrupts(intHH24, intMM);
424  }
425 }
426 
427 // Adjustment RTC Precision . Refer sec 8.3 of Application Manual
428 // This could be used only when required.
429 void R8025::changeOffset(uint8_t digitalOffset)
430 {
431  // 'digitalOffset' can be any 7bit number
432  Wire.beginTransmission(RX8025_DIGOFF_REG);
433  Wire.write((digitalOffset & 0x7F));
434  Wire.endTransmission();
435 }
436 
437 
438 uint8_t DS3231::readRegister(uint8_t regaddress)
439 {
440  Wire.beginTransmission(DS3231_ADDRESS);
441  Wire.write(regaddress);
442  Wire.endTransmission();
443 
444  Wire.requestFrom(DS3231_ADDRESS, 1);
445  return Wire.read();
446 }
447 
448 void DS3231::writeRegister(uint8_t regaddress,uint8_t value)
449 {
450  Wire.beginTransmission(DS3231_ADDRESS);
451  Wire.write(regaddress);
452  Wire.write(value);
453  Wire.endTransmission();
454 }
455 
456 void DS3231::begin(void) {
457 
458  unsigned char ctReg=0;
459  ctReg |= 0b00011100;
460  writeRegister(DS3231_CONTROL_REG, ctReg); //CONTROL Register Address
461  delay(10);
462 
463  // set the clock to 24hr format
464  uint8_t hrReg = readRegister(DS3231_HOUR_REG);
465  hrReg &= 0b10111111;
466  writeRegister(DS3231_HOUR_REG, hrReg);
467 
468  delay(10);
469 }
470 
471 //Adjust the time-date specified in DateTime format
472 //writing any non-existent time-data may interfere with normal operation of the RTC
473 void DS3231::adjust(const DateTime& dt) {
474 
475  Wire.beginTransmission(DS3231_ADDRESS);
476  Wire.write((byte)DS3231_SEC_REG); //beginning from SEC Register address
477 
478  Wire.write(bin2bcd(dt.second()));
479  Wire.write(bin2bcd(dt.minute()));
480  Wire.write(bin2bcd((dt.hour()) & 0b10111111)); //Make sure clock is still 24 Hour
481  Wire.write(dt.dayOfWeek());
482  Wire.write(bin2bcd(dt.day()));
483  Wire.write(bin2bcd(dt.month()));
484  Wire.write(bin2bcd(dt.year() - 2000));
485  Wire.endTransmission();
486 
487 }
488 
489 //Read the current time-date and return it in DateTime format
490 DateTime DS3231::now() {
491  Wire.beginTransmission(DS3231_ADDRESS);
492  Wire.write((byte)0x00);
493  Wire.endTransmission();
494 
495  Wire.requestFrom(DS3231_ADDRESS, 8);
496  uint8_t ss = bcd2bin(Wire.read());
497  uint8_t mm = bcd2bin(Wire.read());
498 
499  uint8_t hrreg = Wire.read();
500  uint8_t hh = bcd2bin((hrreg & ~0b11000000)); //Ignore 24 Hour bit
501 
502  uint8_t wd = Wire.read();
503  uint8_t d = bcd2bin(Wire.read());
504  uint8_t m = bcd2bin(Wire.read());
505  uint16_t y = bcd2bin(Wire.read()) + 2000;
506 
507  return DateTime (y, m, d, hh, mm, ss);
508 }
509 //Enable periodic interrupt at /INT pin. Supports only the level interrupt
510 //for consistency with other /INT interrupts. All interrupts works like single-shot counter
511 //Use refreshINTA() to re-enable interrupt.
512 void DS3231::enableInterrupts(uint8_t periodicity)
513 {
514 
515  unsigned char ctReg=0;
516  ctReg |= 0b00011101;
517  writeRegister(DS3231_CONTROL_REG, ctReg); //CONTROL Register Address
518 
519  switch(periodicity)
520  {
521  case EverySecond:
522  writeRegister(DS3231_AL1SEC_REG, 0b10000000 ); //set AM1
523  writeRegister(DS3231_AL1MIN_REG, 0b10000000 ); //set AM2
524  writeRegister(DS3231_AL1HOUR_REG, 0b10000000 ); //set AM3
525  writeRegister(DS3231_AL1WDAY_REG, 0b10000000 ); //set AM4
526 
527  break;
528 
529  case EveryMinute:
530  writeRegister(DS3231_AL1SEC_REG, 0b00000000 ); //Clr AM1
531  writeRegister(DS3231_AL1MIN_REG, 0b10000000 ); //set AM2
532  writeRegister(DS3231_AL1HOUR_REG, 0b10000000 ); //set AM3
533  writeRegister(DS3231_AL1WDAY_REG, 0b10000000 ); //set AM4
534 
535  break;
536 
537  case EveryHour:
538  writeRegister(DS3231_AL1SEC_REG, 0b00000000 ); //Clr AM1
539  writeRegister(DS3231_AL1MIN_REG, 0b00000000 ); //Clr AM2
540  writeRegister(DS3231_AL1HOUR_REG, 0b10000000 ); //Set AM3
541  writeRegister(DS3231_AL1WDAY_REG, 0b10000000 ); //set AM4
542 
543  break;
544  }
545 }
546 
547 //Enable HH/MM/SS interrupt on /INTA pin. All interrupts works like single-shot counter
548 void DS3231::enableInterrupts(uint8_t hh24, uint8_t mm, uint8_t ss)
549 {
550  unsigned char ctReg=0;
551  ctReg |= 0b00011101;
552  writeRegister(DS3231_CONTROL_REG, ctReg); //CONTROL Register Address
553 
554  writeRegister(DS3231_AL1SEC_REG, 0b00000000 | bin2bcd(ss) ); //Clr AM1
555  writeRegister(DS3231_AL1MIN_REG, 0b00000000 | bin2bcd(mm)); //Clr AM2
556  writeRegister(DS3231_AL1HOUR_REG, (0b00000000 | (bin2bcd(hh24) & 0b10111111))); //Clr AM3
557  writeRegister(DS3231_AL1WDAY_REG, 0b10000000 ); //set AM4
558 }
559 
560 //Disable Interrupts. This is equivalent to begin() method.
561 void DS3231::disableInterrupts()
562 {
563  begin(); //Restore to initial value.
564 }
565 
566 //Clears the interrrupt flag in status register.
567 //This is equivalent to preparing the DS3231 /INT pin to high for MCU to get ready for recognizing the next INT0 interrupt
568 void DS3231::clearINTStatus()
569 {
570  // Clear interrupt flag
571  uint8_t statusReg = readRegister(DS3231_STATUS_REG);
572  statusReg &= 0b11111110;
573  writeRegister(DS3231_STATUS_REG, statusReg);
574 
575 }
576 
577 //force temperature sampling and converting to registers. If this function is not used the temperature is sampled once 64 Sec.
578 void DS3231::convertTemperature()
579 {
580  // Set CONV
581  uint8_t ctReg = readRegister(DS3231_CONTROL_REG);
582  ctReg |= 0b00100000;
583  writeRegister(DS3231_CONTROL_REG,ctReg);
584 
585 
586  //wait until CONV is cleared. Indicates new temperature value is available in register.
587  do
588  {
589  //do nothing
590  } while ((readRegister(DS3231_CONTROL_REG) & 0b00100000) == 0b00100000 );
591 
592 }
593 
594 //Read the temperature value from the register and convert it into float (deg C)
595 float DS3231::getTemperature()
596 {
597  int temperatureCelsius;
598  float fTemperatureCelsius;
599  uint8_t tUBYTE = readRegister(DS3231_TMP_UP_REG); //Two's complement form
600  uint8_t tLRBYTE = readRegister(DS3231_TMP_LOW_REG); //Fractional part
601 
602  if(tUBYTE & 0b10000000) //check if -ve number
603  {
604  tUBYTE ^= 0b11111111;
605  tUBYTE += 0x1;
606  fTemperatureCelsius = tUBYTE + ((tLRBYTE >> 6) * 0.25);
607  fTemperatureCelsius = fTemperatureCelsius * -1;
608  }
609  else
610  {
611  fTemperatureCelsius = tUBYTE + ((tLRBYTE >> 6) * 0.25);
612  }
613 
614  return (fTemperatureCelsius);
615 
616 }
617 
618 
619 /********************************************************
620  * DS1337
621  *********************************************************/
622 // Cumulative number of days elapsed at the start of each month, assuming a normal (non-leap) year.
623 const unsigned int monthdays[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
624 
625 // Aquire data from the RTC chip in BCD format
626 // refresh the buffer
627 void DS1337::readTime(void)
628 {
629 // use the Wire lib to connect to tho rtc
630 // reset the register pointer to zero
631  Wire.beginTransmission(DS1337_CTRL_ID);
632  Wire.write((uint8_t)0x00); // Explicit cast is to hack around http://code.google.com/p/arduino/issues/detail?id=527
633  Wire.endTransmission();
634 
635 // request the 7 bytes of data (secs, min, hr, dow, date. mth, yr)
636  Wire.requestFrom(DS1337_CTRL_ID, 7);
637  for(int i=0; i<7; i++)
638  {
639  // store data in raw bcd format
640  if (Wire.available())
641  rtc_bcd[i]=Wire.read();
642  }
643 }
644 
645 // Read the current alarm value. Note that the repeat flags and DY/DT are removed from the result.
646 void DS1337::readAlarm(void)
647 {
648  //alarm_repeat = 0;
649  byte temp;
650 // use the Wire lib to connect to tho rtc
651 // point to start of Alarm1 registers
652  Wire.beginTransmission(DS1337_CTRL_ID);
653  Wire.write((uint8_t)DS1337_ARLM1);
654  Wire.endTransmission();
655 
656 // request the *4* bytes of data (secs, min, hr, dow/date). Note the format is nearly identical, except for the choice of dayOfWeek vs. date,
657 // and that the topmost bit of each helps determine if/how the alarm repeats.
658  Wire.requestFrom(DS1337_CTRL_ID, 4);
659  for(int i=0; i<4; i++)
660  {
661  // store data in raw bcd format
662  if (Wire.available())
663  {
664  temp = Wire.read();
665  rtc_bcd[i] = temp & B01111111;
666  }
667  }
668 
669  // 4th byte read may contain either a date or DayOfWeek, depending on the value of the DY/DT flag.
670  // For laziness sake we read it into the DayOfWeek field regardless (rtc_bcd[3]). Correct as needed...
671  if(rtc_bcd[3] & B01000000) // DY/DT set: DayOfWeek
672  {
673  rtc_bcd[3] &= B10111111; // clear DY/DT flag
674  rtc_bcd[4] = 0; // alarm *date* undefined
675  }
676  else
677  {
678  rtc_bcd[4] = rtc_bcd[3];
679  rtc_bcd[3] = 0; // alarm dayOfWeek undefined
680  }
681 }
682 
683 // update the data on the IC from the bcd formatted data in the buffer
684 
685 void DS1337::writeTime(void)
686 {
687  Wire.beginTransmission(DS1337_CTRL_ID);
688  Wire.write((uint8_t)0x00); // reset register pointer
689  for(int i=0; i<7; i++)
690  {
691  Wire.write(rtc_bcd[i]);
692  }
693  Wire.endTransmission();
694 
695  // clear the Oscillator Stop Flag
696  setRegister(DS1337_STATUS, getRegister(DS1337_STATUS) & !DS1337_STATUS_OSF);
697 }
698 
699 
700 // FIXME: automatically set alarm interrupt after writing new alarm? Nah...
701 
702 // Write the BCD alarm value in the buffer to the alarm registers.
703 // If an alarm repeat mode has been specified, poke those bytes into the buffer before sending.
704 void DS1337::writeAlarm(void)
705 {
706  Wire.beginTransmission(DS1337_CTRL_ID);
707  Wire.write((uint8_t)DS1337_ARLM1); // set register pointer
708 
709  Wire.write(rtc_bcd[DS1337_SEC] | ((alarm_repeat & B00000001 ) << 7)); // A1M1
710  Wire.write(rtc_bcd[DS1337_MIN] | ((alarm_repeat & B00000010 ) << 6)); // A1M2
711  Wire.write(rtc_bcd[DS1337_HR] | ((alarm_repeat & B00000100 ) << 5)); // A1M3
712 
713  // Check if we are using date or DayOfWeek and send the appropriate value
714  if(alarm_repeat & B00001000) // DayOfWeek
715  {
716  // send DOW as 4th alarm reg byte
717  Wire.write(rtc_bcd[DS1337_DOW] | ((alarm_repeat & B00011000 ) << 3)); // A1M4 and DY/DT
718  }
719  else // date
720  {
721  // send date as 4th alarm reg byte
722  Wire.write(rtc_bcd[DS1337_DATE] | ((alarm_repeat & B00011000 ) << 3)); // A1M4 and DY/DT
723  }
724 
725  Wire.endTransmission();
726 }
727 
728 
729 void DS1337::writeAlarm(unsigned long sse)
730 {
731  epoch_seconds_to_date(sse);
732  writeAlarm();
733 }
734 
735 
736 void DS1337::setAlarmRepeat(byte repeat)
737 {
738  alarm_repeat = repeat;
739 }
740 
741 
742 unsigned char DS1337::getRegister(unsigned char registerNumber)
743 {
744  Wire.beginTransmission(DS1337_CTRL_ID);
745  Wire.write(registerNumber);
746  Wire.endTransmission();
747 
748  Wire.requestFrom(DS1337_CTRL_ID, 1);
749 
750  return Wire.read();
751 }
752 
753 void DS1337::setRegister(unsigned char registerNumber, unsigned char value)
754 {
755  Wire.beginTransmission(DS1337_CTRL_ID);
756  Wire.write(registerNumber); // set register pointer
757 
758  Wire.write(value);
759 
760  Wire.endTransmission();
761 }
762 
763 unsigned char DS1337::time_is_set()
764 {
765  // Return TRUE if Oscillator Stop Flag is clear (osc. not stopped since last time setting), FALSE otherwise
766  byte asdf = ((getRegister(DS1337_STATUS) & DS1337_STATUS_OSF) == 0);
767  return asdf;
768 }
769 unsigned char DS1337::alarm_is_set()
770 {
771  // Return TRUE if the alarm interrupt flag is enabled.
772  byte asdf = (getRegister(DS1337_SP) & DS1337_SP_A1IE);
773  return asdf;
774 }
775 
776 void DS1337::enable_interrupt()
777 {
778  clear_interrupt();
779  setRegister(DS1337_SP, getRegister(DS1337_SP) | DS1337_SP_INTCN | DS1337_SP_A1IE); // map alarm interrupt to INT1 and enable interrupt
780 }
781 
782 void DS1337::disable_interrupt()
783 {
784  setRegister(DS1337_SP, getRegister(DS1337_SP) & !DS1337_SP_A1IE);
785 }
786 
787 void DS1337::clear_interrupt()
788 {
789  setRegister(DS1337_STATUS, getRegister(DS1337_STATUS) & !DS1337_STATUS_A1F);
790 }
791 
792 unsigned char DS1337::getSeconds()
793 {
794  return bcd2bin(rtc_bcd[DS1337_SEC]);
795 }
796 
797 unsigned char DS1337::getMinutes()
798 {
799  return bcd2bin(rtc_bcd[DS1337_MIN]);
800 }
801 unsigned char DS1337::getHours()
802 {
803  return bcd2bin(rtc_bcd[DS1337_HR]);
804 }
805 unsigned char DS1337::getDays()
806 {
807  return bcd2bin(rtc_bcd[DS1337_DATE]);
808 }
809 unsigned char DS1337::getDayOfWeek()
810 {
811  return bcd2bin(rtc_bcd[DS1337_DOW]);
812 }
813 unsigned char DS1337::getMonths()
814 {
815  return bcd2bin(rtc_bcd[DS1337_MTH]);
816 }
817 unsigned int DS1337::getYears()
818 {
819  return 2000 + bcd2bin(rtc_bcd[DS1337_YR]);
820 }
821 
822 
823 
824 void DS1337::setSeconds(unsigned char v)
825 {
826  rtc_bcd[DS1337_SEC] = bin2bcd(v);
827 
828 }
829 void DS1337::setMinutes(unsigned char v)
830 {
831  rtc_bcd[DS1337_MIN] = bin2bcd(v);
832 
833 }
834 void DS1337::setHours(unsigned char v)
835 {
836  rtc_bcd[DS1337_HR] = bin2bcd(v);
837 
838 }
839 void DS1337::setDays(unsigned char v)
840 {
841  rtc_bcd[DS1337_DATE] = bin2bcd(v);
842 
843 }
844 void DS1337::setDayOfWeek(unsigned char v)
845 {
846  rtc_bcd[DS1337_DOW] = bin2bcd(v);
847 
848 }
849 void DS1337::setMonths(unsigned char v)
850 {
851  rtc_bcd[DS1337_MTH] = bin2bcd(v);
852 
853 }
854 void DS1337::setYears(unsigned int v)
855 {
856  if (v>1999)
857  {
858  v -= 2000;
859  }
860  rtc_bcd[DS1337_YR] = bin2bcd(v);
861 
862 }
863 
864 byte DS1337::bcd2bin(byte v)
865 {
866  return (v&0x0F) + ((v>>4)*10);
867 }
868 
869 byte DS1337::bin2bcd(byte v)
870 {
871  return ((v / 10)<<4) + (v % 10);
872 }
873 
874 void DS1337::stop(void)
875 {
876  setRegister(DS1337_SP, getRegister(DS1337_SP) | DS1337_SP_EOSC);
877 }
878 
879 void DS1337::start(void)
880 {
881  setRegister(DS1337_SP, getRegister(DS1337_SP) & !DS1337_SP_EOSC);
882 }
883 
884 void DS1337::begin(void){
885  start();
886 }
887 void DS1337::adjust(const DateTime& dt){
888  setSeconds(dt.second());
889  setMinutes(dt.minute());
890  setHours(dt.hour());
891  setDays(dt.day());
892  setMonths(dt.month());
893  setYears(dt.year());
894  writeTime();
895  ; //Changes the date-time
896 }
897 DateTime DS1337::now(){
898  readTime();
899  return DateTime (getYears(), getMonths(), getDays(), getHours(), getMinutes(), getSeconds());
900  ; //Gets the current date-time
901 }
902 
903 void DS1337::epoch_seconds_to_date(unsigned long seconds_left)
904 {
905  // This routine taken from Dallas/Maxim application note 517
906  // http://www.maxim-ic.com/app-notes/index.mvp/id/517
907  // Arn't the fastest thing, but it produces correct results.
908 
909  // NOTE: The earliest date that can be represented by the DS1337 is 1/1/2000 (946684800 in Unix epoch seconds).
910  // Passing an earlier Unix time stamp will fail quietly here (produce a date of 0/0/00),
911  // which will probably make your application angry.
912 
913  // ALSO NOTE: This has been optimized some to minimize redundant variables, with the side-effect
914  // of making it much harder to understand. Please refer to the original appnote above
915  // if you are trying to learn from it :-)
916 
917 
918  //unsigned long hour;
919  //unsigned long day;
920  //unsigned long minute;
921  //unsigned long second;
922  unsigned long month;
923  //unsigned long year;
924 
925  unsigned long seconds_left_2;
926  //unsigned long whole_minutes;
927  //unsigned long whole_hours;
928  //unsigned long whole_days;
929  //unsigned long whole_days_since_1968;
930  unsigned long leap_year_periods;
931  unsigned long days_since_current_lyear;
932  //unsigned long whole_years;
933  unsigned long days_since_first_of_year;
934  unsigned long days_to_month;
935  //unsigned long day_of_week;
936 
937  if(seconds_left >= 946684800)
938  {
939  seconds_left -= 946684800; // correct for difference between DS1337 and UNIX epochs.
940 
941  seconds_left_2 = seconds_left / 60; // seconds_left_2 = "whole_minutes"
942  rtc_bcd[DS1337_SEC] = bin2bcd(seconds_left - (60 * seconds_left_2)); // leftover seconds
943 
944  seconds_left = seconds_left_2 / 60; // seconds_left = "whole_hours"
945  rtc_bcd[DS1337_MIN] = bin2bcd(seconds_left_2 - (60 * seconds_left)); // leftover minutes
946 
947  seconds_left_2 = seconds_left / 24; //seconds_left_2 = "whole_days"
948  rtc_bcd[DS1337_HR] = bin2bcd(seconds_left - (24 * seconds_left_2)); // leftover hours
949 
950  //whole_days_since_1968 = whole_days;// + 365 + 366; // seconds_left_2 = "whole_days" = "whole_days_since_1968"
951  leap_year_periods = seconds_left_2 / ((4 * 365) + 1);
952 
953  days_since_current_lyear = seconds_left_2 % ((4 * 365) + 1);
954 
955  // if days are after a current leap year then add a leap year period
956  if ((days_since_current_lyear >= (31 + 29))) {
957  leap_year_periods++;
958  }
959  seconds_left = (seconds_left_2 - leap_year_periods) / 365; // seconds_left = "whole_years"
960  days_since_first_of_year = seconds_left_2 - (seconds_left * 365) - leap_year_periods;
961 
962  if ((days_since_current_lyear <= 365) && (days_since_current_lyear >= 60)) {
963  days_since_first_of_year++;
964  }
965  //year = seconds_left; // + 68;
966 
967 
968  // seconds_left = "year"
969  //seconds_left_2 = "month"
970  // walk across monthdays[] to find what month it is based on how many days have passed
971  // within the current year
972  month = 13;
973  days_to_month = 366;
974  while (days_since_first_of_year < days_to_month) {
975  month--;
976  days_to_month = monthdays[month-1];
977  if ((month > 2) && ((seconds_left % 4) == 0)) {
978  days_to_month++;
979  }
980  }
981 
982  rtc_bcd[DS1337_DATE] = bin2bcd( days_since_first_of_year - days_to_month + 1);
983 
984  rtc_bcd[DS1337_DOW] = bin2bcd((seconds_left_2 + 4) % 7);
985 
986 
987  //rtc_bcd[DS1337_SEC] = bin2bcd(second);
988  //rtc_bcd[DS1337_MIN] = bin2bcd(minute);
989  //rtc_bcd[DS1337_HR] = bin2bcd(hour);
990  //rtc_bcd[DS1337_DATE] = bin2bcd(day);
991  //rtc_bcd[DS1337_DOW] = bin2bcd(day_of_week);
992  rtc_bcd[DS1337_MTH] = bin2bcd(month);
993  rtc_bcd[DS1337_YR] = bin2bcd(seconds_left);
994  }
995  else
996  {
997  // else: "invalid" (< year 2000) epoch format.
998  // 'Best' way to handle this is to zero out the returned date.
999 
1000  rtc_bcd[DS1337_SEC] = 0; //0x00 binary = 0x00 BCD
1001  rtc_bcd[DS1337_MIN] = 0;
1002  rtc_bcd[DS1337_HR] = 0;
1003  rtc_bcd[DS1337_DATE] = 0;
1004  rtc_bcd[DS1337_DOW] = 0;
1005  rtc_bcd[DS1337_MTH] = 0;
1006  rtc_bcd[DS1337_YR] = 0;
1007  }
1008 
1009 }
1010 
1011 unsigned long DS1337::date_to_epoch_seconds(unsigned int year, byte month, byte day, byte hour, byte minute, byte second)
1012 {
1013 
1014  //gracefully handle 2- and 4-digit year formats
1015  if (year > 1999)
1016  {
1017  year -= 2000;
1018  }
1019 
1020 
1021 // Between year 2000 and 2100, a leap year occurs in every year divisible by 4.
1022 
1023 // sse_y = (((unsigned long)year)*365*24*60*60);
1024 // sse_ly = ((((unsigned long)year+3)>>2) + ((unsigned long)year%4==0 && (unsigned long)month>2))*24*60*60;
1025 // sse_d = ((unsigned long)monthdays[month-1] + (unsigned long)day-1) *24*60*60;
1026 // sse_h = ((unsigned long)hour*60*60);
1027 // sse_m = ((unsigned long)minute*60);
1028 // sse_s = (unsigned long)second;
1029 //
1030 // sse = sse_y + sse_ly + sse_d + sse_h + sse_m + sse_s;
1031 
1032 
1033 
1034 // NB: The multiplication-by-constants below is intentionally left expanded for readability; GCC is smart and will optimize them to single constants during compilation.
1035 
1036 
1037  // Whole year seconds Cumulative total of seconds contributed by elapsed leap year days
1038  unsigned long sse = (((unsigned long)year)*365*24*60*60) + ((((unsigned long)year+3)>>2) + ((unsigned long)year%4==0 && (unsigned long)month>2))*24*60*60 + \
1039  ((unsigned long)monthdays[month-1] + (unsigned long)day-1) *24*60*60 + ((unsigned long)hour*60*60) + ((unsigned long)minute*60) + (unsigned long)second;
1040  // Seconds in days since start of year hours minutes sec
1041  sse += 946684800; // correct for difference between DS1337 epoch and UNIX epoch
1042  return sse;
1043 }
1044 
1045 unsigned long DS1337::date_to_epoch_seconds()
1046 {
1047  unsigned long asdf = date_to_epoch_seconds(int(bcd2bin(rtc_bcd[DS1337_YR])), bcd2bin(rtc_bcd[DS1337_MTH]), bcd2bin(rtc_bcd[DS1337_DATE]), bcd2bin(rtc_bcd[DS1337_HR]), bcd2bin(rtc_bcd[DS1337_MIN]), bcd2bin(rtc_bcd[DS1337_SEC]));
1048  return asdf;
1049 }
1050 
1051 
1052