Skip to content

Commit 816b313

Browse files
author
Jack Christensen
committed
Alpha version 0.8
0 parents  commit 816b313

File tree

3 files changed

+592
-0
lines changed

3 files changed

+592
-0
lines changed

MCP79412RTC.cpp

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
/*----------------------------------------------------------------------*
2+
* MCP79412RTC.cpp - Arduino library for the Microchip MCP79412 *
3+
* Real-Time Clock. This library is intended for use with the Arduino *
4+
* Time.h library, http://www.arduino.cc/playground/Code/Time *
5+
* *
6+
* This library is a drop-in replacement for the DS1307RTC.h library *
7+
* by Michael Margolis that is supplied with the Arduino Time library *
8+
* above. To change from using a DS1307 RTC to an MCP79412 RTC, it is *
9+
* only necessary to change the #include statement to include this *
10+
* library instead of DS1307RTC.h. *
11+
* *
12+
* In addition, this library implements functions to support the *
13+
* additional features of the MCP79412. *
14+
* *
15+
* Jack Christensen 29Jul2012 *
16+
* *
17+
* This work is licensed under the Creative Commons Attribution- *
18+
* ShareAlike 3.0 Unported License. To view a copy of this license, *
19+
* visit http://creativecommons.org/licenses/by-sa/3.0/ or send a *
20+
* letter to Creative Commons, 171 Second Street, Suite 300, *
21+
* San Francisco, California, 94105, USA. *
22+
*----------------------------------------------------------------------*/
23+
24+
#include <Wire.h>
25+
#include "MCP79412RTC.h"
26+
27+
/*----------------------------------------------------------------------*
28+
* Constructor. *
29+
*----------------------------------------------------------------------*/
30+
MCP79412RTC::MCP79412RTC()
31+
{
32+
Wire.begin();
33+
}
34+
35+
/*----------------------------------------------------------------------*
36+
* Read the current time from the RTC and return it as a time_t value. *
37+
*----------------------------------------------------------------------*/
38+
time_t MCP79412RTC::get()
39+
{
40+
tmElements_t tm;
41+
42+
read(tm);
43+
return(makeTime(tm));
44+
}
45+
46+
/*----------------------------------------------------------------------*
47+
* Set the RTC to the given time_t value. *
48+
*----------------------------------------------------------------------*/
49+
void MCP79412RTC::set(time_t t)
50+
{
51+
tmElements_t tm;
52+
53+
breakTime(t, tm);
54+
write(tm);
55+
}
56+
57+
/*----------------------------------------------------------------------*
58+
* Read the current time from the RTC and return it in a tmElements_t *
59+
* structure. *
60+
*----------------------------------------------------------------------*/
61+
void MCP79412RTC::read(tmElements_t &tm)
62+
{
63+
Wire.beginTransmission(RTC_ADDR);
64+
i2cWrite(TIME_REG);
65+
Wire.endTransmission();
66+
67+
//request 7 bytes (secs, min, hr, dow, date, mth, yr)
68+
Wire.requestFrom(RTC_ADDR, tmNbrFields);
69+
tm.Second = bcd2dec(i2cRead() & ~_BV(ST));
70+
tm.Minute = bcd2dec(i2cRead());
71+
tm.Hour = bcd2dec(i2cRead() & ~_BV(HR1224)); //assumes 24hr clock
72+
tm.Wday = bcd2dec(i2cRead() & ~(_BV(OSCON) | _BV(VBAT) | _BV(VBATEN)) ); //mask off OSCON, VBAT, VBATEN bits
73+
tm.Day = bcd2dec(i2cRead());
74+
tm.Month = bcd2dec(i2cRead() & ~_BV(LP)); //mask off the leap year bit
75+
tm.Year = y2kYearToTm(bcd2dec(i2cRead()));
76+
}
77+
78+
/*----------------------------------------------------------------------*
79+
* Set the RTC's time from a tmElements_t structure. *
80+
*----------------------------------------------------------------------*/
81+
void MCP79412RTC::write(tmElements_t &tm)
82+
{
83+
Wire.beginTransmission(RTC_ADDR);
84+
i2cWrite(TIME_REG);
85+
i2cWrite(0x00); //stops the oscillator (Bit 7, ST == 0)
86+
i2cWrite(dec2bcd(tm.Minute));
87+
i2cWrite(dec2bcd(tm.Hour)); //sets 24 hour format (Bit 6 == 0)
88+
i2cWrite(dec2bcd(tm.Wday) | _BV(VBATEN)); //enable battery backup operation
89+
i2cWrite(dec2bcd(tm.Day));
90+
i2cWrite(dec2bcd(tm.Month));
91+
i2cWrite(dec2bcd(tmYearToY2k(tm.Year)));
92+
Wire.endTransmission();
93+
94+
Wire.beginTransmission(RTC_ADDR);
95+
i2cWrite(TIME_REG);
96+
i2cWrite(dec2bcd(tm.Second) | _BV(ST)); //set the seconds and start the oscillator (Bit 7, ST == 1)
97+
Wire.endTransmission();
98+
}
99+
100+
/*----------------------------------------------------------------------*
101+
* Write a single byte to RTC RAM. *
102+
* Valid address range is 0x00 - 0x5F, no checking. *
103+
*----------------------------------------------------------------------*/
104+
void MCP79412RTC::ramWrite(byte addr, byte value)
105+
{
106+
ramWrite(addr, &value, 1);
107+
}
108+
109+
/*----------------------------------------------------------------------*
110+
* Write multiple bytes to RTC RAM. *
111+
* Valid address range is 0x00 - 0x5F, no checking. *
112+
* Number of bytes (nBytes) must be between 1 and 31 (Wire library *
113+
* has a limitation of 31 bytes). *
114+
*----------------------------------------------------------------------*/
115+
void MCP79412RTC::ramWrite(byte addr, byte *values, byte nBytes)
116+
{
117+
Wire.beginTransmission(RTC_ADDR);
118+
i2cWrite(addr);
119+
for (byte i=0; i<nBytes; i++) i2cWrite(values[i]);
120+
Wire.endTransmission();
121+
}
122+
123+
/*----------------------------------------------------------------------*
124+
* Read a single byte from RTC RAM. *
125+
* Valid address range is 0x00 - 0x5F, no checking. *
126+
*----------------------------------------------------------------------*/
127+
byte MCP79412RTC::ramRead(byte addr)
128+
{
129+
byte value;
130+
131+
ramRead(addr, &value, 1);
132+
return value;
133+
}
134+
135+
/*----------------------------------------------------------------------*
136+
* Read multiple bytes from RTC RAM. *
137+
* Valid address range is 0x00 - 0x5F, no checking. *
138+
* Number of bytes (nBytes) must be between 1 and 31 (Wire library *
139+
* has a limitation of 31 bytes). *
140+
*----------------------------------------------------------------------*/
141+
void MCP79412RTC::ramRead(byte addr, byte *values, byte nBytes)
142+
{
143+
Wire.beginTransmission(RTC_ADDR);
144+
i2cWrite(addr);
145+
Wire.endTransmission();
146+
Wire.requestFrom( (uint8_t)RTC_ADDR, nBytes );
147+
for (byte i=0; i<nBytes; i++) values[i] = i2cRead();
148+
}
149+
150+
/*----------------------------------------------------------------------*
151+
* Write a single byte to Static RAM. *
152+
* Address (addr) is constrained to the range (0, 63). *
153+
*----------------------------------------------------------------------*/
154+
void MCP79412RTC::sramWrite(byte addr, byte value)
155+
{
156+
ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 );
157+
}
158+
159+
/*----------------------------------------------------------------------*
160+
* Write multiple bytes to Static RAM. *
161+
* Address (addr) is constrained to the range (0, 63). *
162+
* Number of bytes (nBytes) must be between 1 and 31 (Wire library *
163+
* has a limitation of 31 bytes). *
164+
* Invalid values for nBytes, or combinations of addr and nBytes *
165+
* that would result in addressing past the last byte of SRAM will *
166+
* result in no action. *
167+
*----------------------------------------------------------------------*/
168+
void MCP79412RTC::sramWrite(byte addr, byte *values, byte nBytes)
169+
{
170+
if (nBytes >= 1 && nBytes <= I2C_BYTE_LIMIT && (addr + nBytes) <= SRAM_SIZE) {
171+
ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nBytes );
172+
}
173+
}
174+
175+
/*----------------------------------------------------------------------*
176+
* Read a single byte from Static RAM. *
177+
* Address (addr) is constrained to the range (0, 63). *
178+
*----------------------------------------------------------------------*/
179+
byte MCP79412RTC::sramRead(byte addr)
180+
{
181+
byte value;
182+
183+
ramRead( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 );
184+
return value;
185+
}
186+
187+
/*----------------------------------------------------------------------*
188+
* Read multiple bytes from Static RAM. *
189+
* Address (addr) is constrained to the range (0, 63). *
190+
* Number of bytes (nBytes) must be between 1 and 31 (Wire library *
191+
* has a limitation of 31 bytes). *
192+
* Invalid values for addr or nBytes, or combinations of addr and *
193+
* nBytes that would result in addressing past the last byte of SRAM *
194+
* result in no action. *
195+
*----------------------------------------------------------------------*/
196+
void MCP79412RTC::sramRead(byte addr, byte *values, byte nBytes)
197+
{
198+
if (nBytes >= 1 && nBytes <= I2C_BYTE_LIMIT && (addr + nBytes) <= SRAM_SIZE) {
199+
ramRead((addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nBytes);
200+
}
201+
}
202+
203+
/*----------------------------------------------------------------------*
204+
* Write a single byte to EEPROM. *
205+
* Address (addr) is constrained to the range (0, 127). *
206+
* Can't leverage page write function because a write can't start *
207+
* mid-page. *
208+
*----------------------------------------------------------------------*/
209+
void MCP79412RTC::eepromWrite(byte addr, byte value)
210+
{
211+
Wire.beginTransmission(EEPROM_ADDR);
212+
i2cWrite( addr & (EEPROM_SIZE - 1) );
213+
i2cWrite(value);
214+
Wire.endTransmission();
215+
eepromWait();
216+
}
217+
218+
/*----------------------------------------------------------------------*
219+
* Write a page (or less) to EEPROM. An EEPROM page is 8 bytes. *
220+
* Address (addr) should be a page start address (0, 8, ..., 120), but *
221+
* is ruthlessly coerced into a valid value. *
222+
* Number of bytes (nBytes) must be between 1 and 8, other values *
223+
* result in no action. *
224+
*----------------------------------------------------------------------*/
225+
void MCP79412RTC::eepromWrite(byte addr, byte *values, byte nBytes)
226+
{
227+
if (nBytes >= 1 && nBytes <= EEPROM_PAGE_SIZE) {
228+
Wire.beginTransmission(EEPROM_ADDR);
229+
i2cWrite( addr & ~(EEPROM_PAGE_SIZE - 1) & (EEPROM_SIZE - 1) );
230+
for (byte i=0; i<nBytes; i++) i2cWrite(values[i]);
231+
Wire.endTransmission();
232+
eepromWait();
233+
}
234+
}
235+
236+
/*----------------------------------------------------------------------*
237+
* Read a single byte from EEPROM. *
238+
* Address (addr) is constrained to the range (0, 127). *
239+
*----------------------------------------------------------------------*/
240+
byte MCP79412RTC::eepromRead(byte addr)
241+
{
242+
byte value;
243+
244+
eepromRead( addr & (EEPROM_SIZE - 1), &value, 1 );
245+
return value;
246+
}
247+
248+
/*----------------------------------------------------------------------*
249+
* Read multiple bytes from EEPROM. *
250+
* Address (addr) is constrained to the range (0, 127). *
251+
* Number of bytes (nBytes) must be between 1 and 31 (Wire library *
252+
* has a limitation of 31 bytes). *
253+
* Invalid values for addr or nBytes, or combinations of addr and *
254+
* nBytes that would result in addressing past the last byte of EEPROM *
255+
* result in no action. *
256+
*----------------------------------------------------------------------*/
257+
void MCP79412RTC::eepromRead(byte addr, byte *values, byte nBytes)
258+
{
259+
if (nBytes >= 1 && nBytes <= I2C_BYTE_LIMIT && (addr + nBytes) <= EEPROM_SIZE) {
260+
Wire.beginTransmission(EEPROM_ADDR);
261+
i2cWrite( addr & (EEPROM_SIZE - 1) );
262+
Wire.endTransmission();
263+
Wire.requestFrom( (uint8_t)EEPROM_ADDR, nBytes );
264+
for (byte i=0; i<nBytes; i++) values[i] = i2cRead();
265+
}
266+
}
267+
268+
/*----------------------------------------------------------------------*
269+
* Wait for EEPROM write to complete. *
270+
*----------------------------------------------------------------------*/
271+
byte MCP79412RTC::eepromWait(void)
272+
{
273+
byte waitCount = 0;
274+
byte txStatus;
275+
276+
do
277+
{
278+
++waitCount;
279+
Wire.beginTransmission(EEPROM_ADDR);
280+
i2cWrite(0);
281+
txStatus = Wire.endTransmission();
282+
283+
} while (txStatus != 0);
284+
285+
return waitCount;
286+
}
287+
288+
/*----------------------------------------------------------------------*
289+
* Read the calibration register. *
290+
* The calibration value is not a twos-complement number. The MSB is *
291+
* the sign bit, and the 7 LSBs are an unsigned number, so we convert *
292+
* it and return it to the caller as a regular twos-complement integer. *
293+
*----------------------------------------------------------------------*/
294+
int MCP79412RTC::calibRead(void)
295+
{
296+
byte val = ramRead(CALIB_REG);
297+
298+
if ( val & 0x80 ) return -(val & 0x7F);
299+
else return val;
300+
}
301+
302+
/*----------------------------------------------------------------------*
303+
* Write the calibration register. *
304+
* Calibration value must be between -127 and 127, others result *
305+
* in no action. See note above on the format of the calibration value. *
306+
*----------------------------------------------------------------------*/
307+
void MCP79412RTC::calibWrite(int value)
308+
{
309+
byte calibVal;
310+
311+
if (value >= -127 && value <= 127) {
312+
calibVal = abs(value);
313+
if (value < 0) calibVal += 128;
314+
ramWrite(CALIB_REG, calibVal);
315+
}
316+
}
317+
318+
/*----------------------------------------------------------------------*
319+
* Read the unique ID. *
320+
* Caller must provide an 8-byte array to contain the results. *
321+
*----------------------------------------------------------------------*/
322+
void MCP79412RTC::idRead(byte *uniqueID)
323+
{
324+
Wire.beginTransmission(EEPROM_ADDR);
325+
i2cWrite(UNIQUE_ID_ADDR);
326+
Wire.endTransmission();
327+
Wire.requestFrom( EEPROM_ADDR, UNIQUE_ID_SIZE );
328+
for (byte i=0; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = i2cRead();
329+
}
330+
331+
/*----------------------------------------------------------------------*
332+
* Check to see if the RTC's oscillator is started (ST bit in seconds *
333+
* register). Returns true if started. *
334+
*----------------------------------------------------------------------*/
335+
boolean MCP79412RTC::oscStarted(void)
336+
{
337+
Wire.beginTransmission(RTC_ADDR);
338+
i2cWrite(TIME_REG);
339+
Wire.endTransmission();
340+
341+
//request just the seconds register
342+
Wire.requestFrom(RTC_ADDR, 1);
343+
return i2cRead() & _BV(ST);
344+
}
345+
346+
/*----------------------------------------------------------------------*
347+
* Decimal-to-BCD conversion *
348+
*----------------------------------------------------------------------*/
349+
uint8_t MCP79412RTC::dec2bcd(uint8_t num)
350+
{
351+
return ((num / 10 * 16) + (num % 10));
352+
}
353+
354+
/*----------------------------------------------------------------------*
355+
* BCD-to-Decimal conversion *
356+
*----------------------------------------------------------------------*/
357+
uint8_t MCP79412RTC::bcd2dec(uint8_t num)
358+
{
359+
return ((num / 16 * 10) + (num % 16));
360+
}
361+
362+
MCP79412RTC RTC = MCP79412RTC(); //instantiate an RTC object
363+

0 commit comments

Comments
 (0)