Erriez DS1307 I2C RTC library for Arduino  1.0.0
This is a DS1307 I2C Real Time Clock library for Arduino by Erriez.
ErriezDS1307.cpp
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2020 Erriez
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
33 #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM)
34 #include <avr/pgmspace.h>
35 #else
36 #include <pgmspace.h>
37 #endif
38 
39 #include <Wire.h>
40 
41 #include "ErriezDS1307.h"
42 
53 {
54  uint8_t regDayWeek;
55 
56  // Read seconds register
57  if (!readBuffer(DS1307_REG_DAY_WEEK, &regDayWeek, 1)) {
58  return false;
59  }
60 
61  // Check zero bits in day week register
62  if (regDayWeek & 0xF8) {
63  return false;
64  }
65 
66  // DS1307 detected
67  return true;
68 }
69 
82 {
83  // Return status CH (Clock Halt) bit from seconds register
85  // RTC clock stopped
86  return false;
87  } else {
88  // RTC clock is running
89  return true;
90  }
91 }
92 
105 bool ErriezDS1307::clockEnable(bool enable)
106 {
107  uint8_t regSeconds;
108 
109  // Read seconds register
110  regSeconds = readRegister(DS1307_REG_SECONDS);
111 
112  // Set or clear HT bit
113  if (enable) {
114  // Clear to enable
115  regSeconds &= ~(1 << DS1307_SEC_CH);
116  } else {
117  // Set to disable
118  regSeconds |= (1 << DS1307_SEC_CH);
119  }
120 
121  // Write seconds register
122  return writeRegister(DS1307_REG_SECONDS, regSeconds);
123 }
124 
131 {
132  struct tm dt;
133  time_t t;
134 
135  // Read time structure
136  if (!read(&dt)) {
137  // RTC read failed
138  return 0;
139  }
140 
141  // Convert date/time struct tm to time_t
142  t = mktime(&dt);
143 
144  // An offset is needed for AVR target
145 #ifdef ARDUINO_ARCH_AVR
146  t += UNIX_OFFSET;
147 #endif
148 
149  // Return Unix epoch UTC
150  return t;
151 }
152 
163 {
164  struct tm *dt;
165 
166  // Subtract UNIX offset for AVR targets
167 #ifdef ARDUINO_ARCH_AVR
168  t -= UNIX_OFFSET;
169 #endif
170 
171  // Convert time_t to date/time struct tm
172  dt = gmtime(&t);
173 
174  // Write date/time to RTC
175  return write(dt);
176 }
177 
190 bool ErriezDS1307::read(struct tm *dt)
191 {
192  uint8_t buffer[7];
193 
194  // Read clock date and time registers
195  if (!readBuffer(0x00, buffer, sizeof(buffer))) {
196  memset(dt, 0, sizeof(struct tm));
197  return false;
198  }
199 
200  // Clear dt
201  memset(dt, 0, sizeof(struct tm));
202 
203  // Convert BCD buffer to Decimal
204  dt->tm_sec = bcdToDec(buffer[0] & 0x7F);
205  dt->tm_min = bcdToDec(buffer[1] & 0x7F);
206  dt->tm_hour = bcdToDec(buffer[2] & 0x3F);
207  dt->tm_wday = bcdToDec(buffer[3] & 0x07);
208  dt->tm_mday = bcdToDec(buffer[4] & 0x3F);
209  dt->tm_mon = bcdToDec(buffer[5] & 0x1F);
210  dt->tm_year = bcdToDec(buffer[6]) + 100; // 2000-1900
211 
212  // Month: 0..11
213  if (dt->tm_mon) {
214  dt->tm_mon--;
215  }
216 
217  // Day of the week: 0=Sunday
218  if (dt->tm_wday) {
219  dt->tm_wday--;
220  }
221 
222  // Check buffer for valid data
223  if ((dt->tm_sec > 59) || (dt->tm_min > 59) || (dt->tm_hour > 23) ||
224  (dt->tm_mday < 1) || (dt->tm_mday > 31) || (dt->tm_mon > 11) || (dt->tm_year > 199) ||
225  (dt->tm_wday > 6))
226  {
227  return false;
228  }
229 
230  return true;
231 }
232 
245 bool ErriezDS1307::write(const struct tm *dt)
246 {
247  uint8_t buffer[7];
248 
249  // Encode date time from decimal to BCD
250  buffer[0] = decToBcd(dt->tm_sec) & 0x7F; // Clear CH bit in seconds register
251  buffer[1] = decToBcd(dt->tm_min) & 0x7F;
252  buffer[2] = decToBcd(dt->tm_hour) & 0x3F;
253  buffer[3] = decToBcd(dt->tm_wday + 1) & 0x07;
254  buffer[4] = decToBcd(dt->tm_mday) & 0x3F;
255  buffer[5] = decToBcd(dt->tm_mon + 1) & 0x1F;
256  buffer[6] = decToBcd(dt->tm_year % 100);
257 
258  // Write BCD encoded buffer to RTC registers
259  return writeBuffer(0x00, buffer, sizeof(buffer));
260 }
261 
277 bool ErriezDS1307::setTime(uint8_t hour, uint8_t min, uint8_t sec)
278 {
279  struct tm dt;
280 
281  read(&dt);
282  dt.tm_hour = hour;
283  dt.tm_min = min;
284  dt.tm_sec = sec;
285  return write(&dt);
286 }
287 
303 bool ErriezDS1307::getTime(uint8_t *hour, uint8_t *min, uint8_t *sec)
304 {
305  uint8_t buffer[3];
306 
307  // Read RTC time registers
308  if (!readBuffer(0x00, buffer, sizeof(buffer))) {
309  return false;
310  }
311 
312  // Convert BCD buffer to Decimal
313  *sec = bcdToDec(buffer[0] & 0x7F); // Without CH bit from seconds register
314  *min = bcdToDec(buffer[1] & 0x7F);
315  *hour = bcdToDec(buffer[2] & 0x3F);
316 
317  // Check buffer for valid data
318  if ((*sec > 59) || (*min > 59) || (*hour > 23)) {
319  // Invalid time
320  *sec = 0x00;
321  *min = 0x00;
322  *hour = 0x00;
323 
324  return false;
325  }
326 
327  return true;
328 }
329 
351 bool ErriezDS1307::setDateTime(uint8_t hour, uint8_t min, uint8_t sec,
352  uint8_t mday, uint8_t mon, uint16_t year,
353  uint8_t wday)
354 {
355  struct tm dt;
356 
357  // Prepare struct tm
358  dt.tm_hour = hour;
359  dt.tm_min = min;
360  dt.tm_sec = sec;
361  dt.tm_mday = mday;
362  dt.tm_mon = mon - 1;
363  dt.tm_year = year - 1900;
364  dt.tm_wday = wday;
365 
366  // Write date/time to RTC
367  return write(&dt);
368 }
369 
391 bool ErriezDS1307::getDateTime(uint8_t *hour, uint8_t *min, uint8_t *sec,
392  uint8_t *mday, uint8_t *mon, uint16_t *year,
393  uint8_t *wday)
394 {
395  struct tm dt;
396 
397  // Read date/time from RTC
398  if (!read(&dt)) {
399  return false;
400  }
401 
402  // Set return values
403  *hour = dt.tm_hour;
404  *min = dt.tm_min;
405  *sec = dt.tm_sec;
406  *mday = dt.tm_mday;
407  *mon = dt.tm_mon + 1;
408  *year = dt.tm_year + 1900;
409  *wday = dt.tm_wday;
410 
411  return true;
412 }
413 
431 {
432  // Write control register
433  return writeBuffer(DS1307_REG_CONTROL, &squareWave, sizeof(squareWave));
434 }
435 
443 uint8_t ErriezDS1307::bcdToDec(uint8_t bcd)
444 {
445  return (uint8_t)(10 * ((bcd & 0xF0) >> 4) + (bcd & 0x0F));
446 }
447 
455 uint8_t ErriezDS1307::decToBcd(uint8_t dec)
456 {
457  return (uint8_t)(((dec / 10) << 4) | (dec % 10));
458 }
459 
469 uint8_t ErriezDS1307::readRegister(uint8_t reg)
470 {
471  uint8_t value = 0;
472 
473  // Read buffer with one 8-bit unsigned value
474  readBuffer(reg, &value, 1);
475 
476  return value;
477 }
478 
492 bool ErriezDS1307::writeRegister(uint8_t reg, uint8_t value)
493 {
494  // Write buffer with one 8-bit unsigned value
495  return writeBuffer(reg, &value, 1);
496 }
497 
513 bool ErriezDS1307::writeBuffer(uint8_t reg, void *buffer, uint8_t writeLen)
514 {
515  // Start I2C transfer by writing the I2C address, register number and optional buffer
516  Wire.beginTransmission(DS1307_ADDR);
517  Wire.write(reg);
518  for (uint8_t i = 0; i < writeLen; i++) {
519  Wire.write(((uint8_t *)buffer)[i]);
520  }
521  if (Wire.endTransmission(true) != 0) {
522  return false;
523  }
524 
525  return true;
526 }
527 
541 bool ErriezDS1307::readBuffer(uint8_t reg, void *buffer, uint8_t readLen)
542 {
543  // Start I2C transfer by writing the I2C address and register number
544  Wire.beginTransmission(DS1307_ADDR);
545  Wire.write(reg);
546  // Generate a repeated start, followed by a read buffer
547  if (Wire.endTransmission(false) != 0) {
548  return false;
549  }
550  Wire.requestFrom((uint8_t)DS1307_ADDR, readLen);
551  for (uint8_t i = 0; i < readLen; i++) {
552  ((uint8_t *)buffer)[i] = (uint8_t)Wire.read();
553  }
554 
555  return true;
556 }
bool read(struct tm *dt)
Read date and time from RTC.
bool readBuffer(uint8_t reg, void *buffer, uint8_t len)
Read buffer from RTC.
uint8_t decToBcd(uint8_t dec)
Decimal to BCD conversion.
bool getDateTime(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *mday, uint8_t *mon, uint16_t *year, uint8_t *wday)
Get date time.
bool write(const struct tm *dt)
Write date and time to RTC.
bool setDateTime(uint8_t hour, uint8_t min, uint8_t sec, uint8_t mday, uint8_t mon, uint16_t year, uint8_t wday)
Set date time.
#define DS1307_ADDR
DS1307 I2C 7-bit address.
Definition: ErriezDS1307.h:63
#define DS1307_REG_SECONDS
DS1307 registers.
Definition: ErriezDS1307.h:40
bool setSquareWave(SquareWave squareWave)
Configure SQW (Square Wave) output pin.
#define DS1307_REG_CONTROL
Control register.
Definition: ErriezDS1307.h:47
uint8_t bcdToDec(uint8_t bcd)
BCD to decimal conversion.
bool getTime(uint8_t *hour, uint8_t *min, uint8_t *sec)
Read time from RTC.
bool setEpoch(time_t t)
Write Unix epoch UTC time to RTC.
SquareWave
Squarewave enum.
Definition: ErriezDS1307.h:68
DS1307 RTC library for Arduino.
#define DS1307_REG_DAY_WEEK
Day of the week register.
Definition: ErriezDS1307.h:43
bool writeRegister(uint8_t reg, uint8_t value)
Write register.
#define DS1307_SEC_CH
DS1307 register bit defines.
Definition: ErriezDS1307.h:53
bool begin()
Initialize and detect DS1307 RTC.
time_t getEpoch()
Read Unix UTC epoch time_t.
bool isRunning()
Read RTC CH (Clock Halt) from seconds register.
bool setTime(uint8_t hour, uint8_t min, uint8_t sec)
Write time to RTC.
uint8_t readRegister(uint8_t reg)
Read register.
bool writeBuffer(uint8_t reg, void *buffer, uint8_t len)
Write buffer to RTC.
bool clockEnable(bool enable=true)
Enable or disable oscillator.