ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DS1307RTC.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "DS1307RTC.h"
24 #include "../I2C/I2CMaster.h"
25 #if defined(ARDUINO) && ARDUINO >= 100
26 #include <Arduino.h>
27 #else
28 #include <WProgram.h>
29 #endif
30 
54 // I2C address of the RTC chip (7-bit).
55 #define DS1307_I2C_ADDRESS 0x68
56 
57 // Registers.
58 #define DS1307_SECOND 0x00
59 #define DS1307_MINUTE 0x01
60 #define DS1307_HOUR 0x02
61 #define DS1307_DAY_OF_WEEK 0x03
62 #define DS1307_DATE 0x04
63 #define DS1307_MONTH 0x05
64 #define DS1307_YEAR 0x06
65 #define DS1307_CONTROL 0x07
66 #define DS1307_NVRAM 0x08
67 
68 // Alarm storage at the end of the RTC's NVRAM.
69 #define DS1307_ALARM_SIZE 3
70 #define DS1307_ALARMS (64 - RTC::ALARM_COUNT * DS1307_ALARM_SIZE - 1)
71 #define DS1307_ALARM_MAGIC 63
72 
83 DS1307RTC::DS1307RTC(I2CMaster &bus, uint8_t oneHzPin)
84  : _bus(&bus)
85  , _oneHzPin(oneHzPin)
86  , prevOneHz(false)
87  , _isRealTime(true)
88 {
89  // Make sure the CH bit in register 0 is off or the clock won't update.
90  _bus->startWrite(DS1307_I2C_ADDRESS);
91  _bus->write(DS1307_SECOND);
92  if (_bus->startRead(DS1307_I2C_ADDRESS, 1)) {
93  uint8_t value = _bus->read();
94  if ((value & 0x80) != 0)
95  writeRegister(DS1307_SECOND, value & 0x7F);
96  } else {
97  // Did not get an acknowledgement from the RTC chip.
98  _isRealTime = false;
99  }
100 
101  // Turn on the 1 Hz square wave signal if required.
102  if (oneHzPin != 255 && _isRealTime) {
103  pinMode(oneHzPin, INPUT);
104  digitalWrite(oneHzPin, HIGH);
105  writeRegister(DS1307_CONTROL, 0x10);
106  }
107 
108  // Initialize the alarms in the RTC chip's NVRAM.
109  if (_isRealTime)
110  initAlarms();
111 }
112 
119 {
120  // If not using a 1 Hz pin or there is no RTC chip available,
121  // then assume that there is an update available.
122  if (_oneHzPin == 255 || !_isRealTime)
123  return true;
124 
125  // The DS1307 updates the internal registers on the falling edge of the
126  // 1 Hz clock. The values should be ready to read on the rising edge.
127  bool value = digitalRead(_oneHzPin);
128  if (value && !prevOneHz) {
129  prevOneHz = value;
130  return true;
131  } else {
132  prevOneHz = value;
133  return false;
134  }
135 }
136 
137 inline uint8_t fromBCD(uint8_t value)
138 {
139  return (value >> 4) * 10 + (value & 0x0F);
140 }
141 
142 inline uint8_t fromHourBCD(uint8_t value)
143 {
144  if ((value & 0x40) != 0) {
145  // 12-hour mode.
146  uint8_t result = ((value >> 4) & 0x01) * 10 + (value & 0x0F);
147  if ((value & 0x20) != 0)
148  return (result == 12) ? 12 : (result + 12); // PM
149  else
150  return (result == 12) ? 0 : result; // AM
151  } else {
152  // 24-hour mode.
153  return fromBCD(value);
154  }
155 }
156 
158 {
159  if (_isRealTime) {
160  _bus->startWrite(DS1307_I2C_ADDRESS);
161  _bus->write(DS1307_SECOND);
162  if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
163  value->second = fromBCD(_bus->read() & 0x7F);
164  value->minute = fromBCD(_bus->read());
165  value->hour = fromHourBCD(_bus->read());
166  } else {
167  // RTC chip is not responding.
168  value->second = 0;
169  value->minute = 0;
170  value->hour = 0;
171  }
172  } else {
173  RTC::readTime(value);
174  }
175 }
176 
178 {
179  if (!_isRealTime) {
180  RTC::readDate(value);
181  return;
182  }
183  _bus->startWrite(DS1307_I2C_ADDRESS);
184  _bus->write(DS1307_DATE);
185  if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
186  value->day = fromBCD(_bus->read());
187  value->month = fromBCD(_bus->read());
188  value->year = fromBCD(_bus->read()) + 2000;
189  } else {
190  // RTC chip is not responding.
191  value->day = 1;
192  value->month = 1;
193  value->year = 2000;
194  }
195 }
196 
197 inline uint8_t toBCD(uint8_t value)
198 {
199  return ((value / 10) << 4) + (value % 10);
200 }
201 
202 void DS1307RTC::writeTime(const RTCTime *value)
203 {
204  if (_isRealTime) {
205  _bus->startWrite(DS1307_I2C_ADDRESS);
206  _bus->write(DS1307_SECOND);
207  _bus->write(toBCD(value->second));
208  _bus->write(toBCD(value->minute));
209  _bus->write(toBCD(value->hour)); // Changes mode to 24-hour clock.
210  _bus->endWrite();
211  } else {
212  RTC::writeTime(value);
213  }
214 }
215 
216 void DS1307RTC::writeDate(const RTCDate *value)
217 {
218  if (_isRealTime) {
219  _bus->startWrite(DS1307_I2C_ADDRESS);
220  _bus->write(DS1307_DATE);
221  _bus->write(toBCD(value->day));
222  _bus->write(toBCD(value->month));
223  _bus->write(toBCD(value->year % 100));
224  _bus->endWrite();
225  } else {
226  RTC::writeDate(value);
227  }
228 }
229 
230 void DS1307RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
231 {
232  if (_isRealTime) {
233  _bus->startWrite(DS1307_I2C_ADDRESS);
234  _bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
235  if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
236  value->hour = fromBCD(_bus->read());
237  value->minute = fromBCD(_bus->read());
238  value->flags = _bus->read();
239  } else {
240  // RTC chip is not responding.
241  value->hour = 0;
242  value->minute = 0;
243  value->flags = 0;
244  }
245  } else {
246  RTC::readAlarm(alarmNum, value);
247  }
248 }
249 
250 void DS1307RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
251 {
252  if (_isRealTime) {
253  _bus->startWrite(DS1307_I2C_ADDRESS);
254  _bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
255  _bus->write(toBCD(value->hour));
256  _bus->write(toBCD(value->minute));
257  _bus->write(value->flags);
258  _bus->endWrite();
259  } else {
260  RTC::writeAlarm(alarmNum, value);
261  }
262 }
263 
265 {
266  return DS1307_ALARMS - DS1307_NVRAM;
267 }
268 
269 uint8_t DS1307RTC::readByte(uint8_t offset)
270 {
271  if (_isRealTime)
272  return readRegister(DS1307_NVRAM + offset);
273  else
274  return RTC::readByte(offset);
275 }
276 
277 void DS1307RTC::writeByte(uint8_t offset, uint8_t value)
278 {
279  if (_isRealTime)
280  writeRegister(DS1307_NVRAM + offset, value);
281  else
282  RTC::writeByte(offset, value);
283 }
284 
285 void DS1307RTC::initAlarms()
286 {
287  uint8_t value = readRegister(DS1307_ALARM_MAGIC);
288  if (value != (0xB0 + ALARM_COUNT)) {
289  // This is the first time we have used this clock chip,
290  // so initialize all alarms to their default state.
291  RTCAlarm alarm;
292  alarm.hour = 6; // Default to 6am for alarms.
293  alarm.minute = 0;
294  alarm.flags = 0;
295  for (uint8_t index = 0; index < ALARM_COUNT; ++index)
296  writeAlarm(index, &alarm);
297  writeRegister(DS1307_ALARM_MAGIC, 0xB0 + ALARM_COUNT);
298 
299  // Also clear the rest of NVRAM so that it is in a known state.
300  // Otherwise we'll have whatever garbage was present at power-on.
301  _bus->startWrite(DS1307_I2C_ADDRESS);
302  _bus->write(DS1307_NVRAM);
303  for (uint8_t index = DS1307_NVRAM; index < DS1307_ALARMS; ++index)
304  _bus->write(0);
305  _bus->endWrite();
306  }
307 }
308 
309 uint8_t DS1307RTC::readRegister(uint8_t reg)
310 {
311  _bus->startWrite(DS1307_I2C_ADDRESS);
312  _bus->write(reg);
313  if (!_bus->startRead(DS1307_I2C_ADDRESS, 1))
314  return 0; // RTC chip is not responding.
315  return _bus->read();
316 }
317 
318 bool DS1307RTC::writeRegister(uint8_t reg, uint8_t value)
319 {
320  _bus->startWrite(DS1307_I2C_ADDRESS);
321  _bus->write(reg);
322  _bus->write(value);
323  return _bus->endWrite();
324 }
uint8_t month
Month of the year (1-12)
Definition: RTC.h:38
virtual void writeTime(const RTCTime *value)
Updates the time in the realtime clock to match value.
Definition: RTC.cpp:179
uint8_t minute
Minute within the hour (0-59)
Definition: RTC.h:31
virtual void readAlarm(uint8_t alarmNum, RTCAlarm *value)
Reads the details of the alarm with index alarmNum into value.
Definition: RTC.cpp:209
virtual void readDate(RTCDate *value)
Reads the current date from the realtime clock into value.
Definition: RTC.cpp:169
void readTime(RTCTime *value)
Reads the current time from the realtime clock into value.
Definition: DS1307RTC.cpp:157
bool hasUpdates()
Returns true if the realtime clock has updated since the last call to this function.
Definition: DS1307RTC.cpp:118
void writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
Updates the details of the alarm with index alarmNum from value.
Definition: DS1307RTC.cpp:250
virtual void write(uint8_t value)=0
Writes a single byte value on the I2C bus.
virtual void writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
Updates the details of the alarm with index alarmNum from value.
Definition: RTC.cpp:224
static const uint8_t ALARM_COUNT
Number of alarms that are supported by RTC::readAlarm() and RTC::writeAlarm().
Definition: RTC.h:77
void writeTime(const RTCTime *value)
Updates the time in the realtime clock to match value.
Definition: DS1307RTC.cpp:202
virtual void writeDate(const RTCDate *value)
Updates the date in the realtime clock to match value.
Definition: RTC.cpp:194
virtual bool startRead(unsigned int address, unsigned int count)=0
Starts a read operation for count bytes by sending the start condition and the I2C control byte...
uint8_t hour
Hour of the day for the alarm (0-23).
Definition: RTC.h:46
uint8_t flags
Additional flags for the alarm.
Definition: RTC.h:49
Stores date information from a realtime clock chip.
Definition: RTC.h:35
void readDate(RTCDate *value)
Reads the current date from the realtime clock into value.
Definition: DS1307RTC.cpp:177
virtual void startWrite(unsigned int address)
Starts a write operation by sending a start condition and the I2C control byte.
virtual bool endWrite()=0
Ends the current write operation.
unsigned int year
Year (4-digit)
Definition: RTC.h:37
virtual void writeByte(uint8_t offset, uint8_t value)
Writes value to offset within the realtime clock's non-volatile memory.
Definition: RTC.cpp:262
uint8_t minute
Minute of the hour for the alarm (0-59).
Definition: RTC.h:47
virtual uint8_t readByte(uint8_t offset)
Reads the byte at offset within the realtime clock's non-volatile memory.
Definition: RTC.cpp:247
Stores time information from a realtime clock chip.
Definition: RTC.h:28
Abstract base class for I2C master implementations.
Definition: I2CMaster.h:28
void writeDate(const RTCDate *value)
Updates the date in the realtime clock to match value.
Definition: DS1307RTC.cpp:216
Stores alarm information from a realtime clock chip.
Definition: RTC.h:42
void readAlarm(uint8_t alarmNum, RTCAlarm *value)
Reads the details of the alarm with index alarmNum into value.
Definition: DS1307RTC.cpp:230
DS1307RTC(I2CMaster &bus, uint8_t oneHzPin=255)
Attaches to a realtime clock slave device on bus.
Definition: DS1307RTC.cpp:83
int byteCount() const
Returns the number of bytes of non-volatile memory that can be used for storage of arbitrary settings...
Definition: DS1307RTC.cpp:264
virtual uint8_t read()=0
Reads a single byte from the I2C bus.
uint8_t readByte(uint8_t offset)
Reads the byte at offset within the realtime clock's non-volatile memory.
Definition: DS1307RTC.cpp:269
uint8_t hour
Hour of the day (0-23)
Definition: RTC.h:30
uint8_t day
Day of the month (1-31)
Definition: RTC.h:39
uint8_t second
Second within the minute (0-59)
Definition: RTC.h:32
virtual void readTime(RTCTime *value)
Reads the current time from the realtime clock into value.
Definition: RTC.cpp:144
void writeByte(uint8_t offset, uint8_t value)
Writes value to offset within the realtime clock's non-volatile memory.
Definition: DS1307RTC.cpp:277