Rex Belli (One of my students and an all-around bright guy, contact me if you're hiring a summer intern) pointed me towards the DS3231 as a possible replacement. It has several advantages over the DS1307:
- It runs fine on either 3.3V or 5V.
- It has a built-in oscillator: no external crystal required.
- It has two built-in alarms that can drive an interrupt pin, so if you just need a periodic interrupt signal this chip can in many cases do the job without a microcontroller.
- It' rated to 2 minutes per year (max) drift. (My best DS1307 clock drifts about 2 minutes per month!)
I wrote an Arduino library for it, so if you want to use this clock chip with that microcontroller it makes things a bit easier.
Here's the library: DS3231.zip
The header file (DS3231.h) is extensively commented, and there are several example sketches included as well. Enjoy! If you use the library for anything interesting, send me an email. I'd be happy to hear what's been done with it.

The DS3232 has all the features of the DS3231, plus it has 240 bytes of storage, just like the DS1307.
ReplyDeletehttp://kennethfinnegan.blogspot.com/2010/02/dot-matrix-arduino-clock.html
Thank you, I search a lot to find how to set time.
ReplyDeleteThanks. This is very handy for me. I am making a simple 7-segment LED clock with the 3231.
ReplyDeleteI found a minor problem in SetClockMode. You have:
// Set the flag to the requested value:
if (h12) {
temp_buffer = temp_buffer | 0x01000000;
} else {
temp_buffer = temp_buffer & 0x10111111;
}
I am sure you meant those bit masks to be in binary not hex, like 0b01000000.
Thanks for the code,
David
Thanks for catching that, David. I've posted an update.
ReplyDeleteI also added a getTime() function which reads all components of time in one call. This eliminates the chance of rollover error should you call, say, getHour() at 1:59:59.999 and getMinute() at 2:00:00.001. (That combination would tell you it's 1:00 instead of 2:00.) If you need just one component of time, use the appropriate getWhatever(); but if you need everything it'd probably be best to use getTime(). Thanks Andy Wickert for pointing out the need for this!
-ea
Thanks for the library.
ReplyDeleteI seem to have a small problem with it, and wondered if you had any idea what I was doing wrong?
I'm setting it using the arduino Time library functions - casting ints to bytes:
Clock.setClockMode(false); // set to 24h
Clock.setYear((byte)(year()-2000));
Clock.setMonth((byte)month());
Clock.setDate((byte)day());
Clock.setDoW((byte)weekday());
Clock.setHour((byte)hour());
Clock.setMinute((byte)minute());
Clock.setSecond((byte)second());
...then getting the time later using this code:
byte byear, bmonth, bdate, bDoW, bhour, bminute, bsecond;
Clock.getTime(byear, bmonth, bdate, bDoW, bhour, bminute, bsecond);
String ts = "";
ts+=(int)bhour; ts+=":"; ts+=(int)bminute; ts+=":"; ts+=(int)bsecond;
In some cases the hour isn't the expected number, for example I'm expecting 17 and getting 11.
I've been using the DS1307 library for the DS3231, but prefer yours if I can work out what I'm doing wrong!
Thanks
Andy Betsworth
Andy--
ReplyDeleteBeats me. Your code looks good, I don't see a problem with it, and I can't reproduce the problem here.
Anyone else have a suggestion?
-ea
I managed to work around the problem by resorting to:
ReplyDeletebyte byear, bmonth, bdate, bDoW, bhour, bminute, bsecond;
bool b1,b2;
Clock.getTime(byear, bmonth, bdate, bDoW, bhour, bminute, bsecond);
bhour = Clock.getHour(b1,b2);
String ts = "";
ts+=(int)bhour; ts+=":"; ts+=(int)bminute; ts+=":"; ts+=(int)bsecond;
So calling the getHour function separately doesn't cause the problem... odd though, I can't pin the problem down, and the rollover issue still potentially applies with my code.
Possibly you are not setting the hours register correctly. If you wanted to set the hours to 17 and you are reading 11 then it seems you may not be converting the hours to Packed BCD (http://en.wikipedia.org/wiki/Packed_BCD#Packed_BCD) before setting the register.
ReplyDeleteIf you converted decimal 17 to hex then of course that would be 0x11 and if read out of the hours register in the intended manner that would then be a value of 11. However to correctly load the hours register you need to convert decimal 17 to Packed BCD which is a hex value of 0x17. The decimal 10s are stored in the upper 4 bits and the decimal units are stored in the lower 4 bits. Each nibble is converted to and from decimal as a separate conversion. Hope that makes sense. Refer the DS3231 datasheet.