Arduino Library for the DS3231 Real Time Clock

Update: for some fascinating details and images of the silicon and other parts inside the DS2131, see the article "A look inside the DS3231 real-time clock" on the HeyPete.com blog.  Pete also does some investigation into whether modules like the one I purchased on eBay contain legitimate, Maxim DS3231 ICs, or whether they use some type of counterfeit chip.  You may be surprised by his findings...

The DS3231 is a precision, Real Time Clock (RTC) module that is widely available on breakout boards from Adafruit and many eBay vendors (see photos below which shows a module I purchased from an eBay vendor for less than $3 that includes a coin cell battery to keep time when the unit is unpowered and a AT24C32D 32kBit (4096x8) EEPROM.)  The DS3231 is significantly more accurate (±2ppm from 0°C to +40°C) than other I2C-based RTC ICs, such as the DS1307 or the PFC8523 and is easier to design with because it contains its own, internal, temperature-compensated (TCXO) crystal oscillator and can run in 3.3 or 5 volt systems without needing level shifters for the I/O pins.

  

I decided to write my own Arduino library for DS3231 because I could not find one that supported using the 2 alarms provided in the DS3231.  Also, for convenience, I wanted to add functions to parse and generate ASCII string representations of time and date values and perform simple addition on time values so you can, for example, reset an alarm to happen again after so many seconds from when the prior alarm went off.  Future updates may add the ability to do addition on date values, or other types of time/date math, but this is not currently supported.

The DS3231 uses the I2C (Arduino 'Wire' library) interface and, by default is set to the fixed address 0x68.  There is a version of this IC, the DS3234, that uses the SPI interface, but I did not code my library to support it.  I did not base my library on any other library for the DS3231 so, if you've been using another library for the DS3231, you'll find my API to be different.  I recommend studying the example program provided with the library to get an idea how it works.

Note: I've tried to test this library as thoroughly as possible but, being only human, it's possible bugs still lurk inside.  So, if you choose to use this code for any purpose that could endanger human life, or cause any kind of damage or destruction, you must perform your own safety analysis of this code and assume full responsibility for its use.  Full source code is provided in the DS3231.zip file you can download below.  See source and header files for license details.

The Library API (for Arduino)

DS3231 (void)

Constructor for the DS3231 library.  Should be declared as a global variable, such as:

DS3231  rtc;

void begin (void)

Initializer function.  Should be called in setup() before any other functions in the DS3231 library are called.

boolean parseTime (char* src, byte* time)

Parse an ASCII reprentation of a time value in either 23 hour format "h:m:s" or AM/PM format "h:m:sP" (suffix of 'P' or 'A' identifies format) and convert into BCD values placed into the array 'time'.  Returns 'true' if the input string was successfully parsed, else false.

The DS3231 internally runs in either AM/PM or 24 hour format and the appropriate mode is configured by parseTime() and parseDateTime() depending on the format of the input string.  Here are some examples of valid time input strings:

Note: leading zeroes are not required on h,m or s values, but are allowed

Note: time[] array must be of length 7, or larger.

void setTimeMode (uint8_t* time, boolean amPm)

If 'amPm' is true and current format is 24 hour, change value in time[] array to AM/PM format else, if false and current format is AM/PM, change to 24 hour format.  Does nothing if value in time[] is already the requested format.  The hours value in time[] is adjusted to convert to new mode.

Note: time[] array must be of length 7.

boolean parseDateTime (char* src, byte* time)

Parse an ASCII reprentation of a date and time value in either 23 hour format or AM/PM format (see parseTime() function) and convert into BCD values placed into the time[] array.  Uses Zeller's Congruence to compute and set the 'day of week' value in time[].  Returns 'true' if the input string was successfully parsed, else false.

Input format: "m/d/y h:m:s", "m/d/y hh:mm:ssA" (AM) or "m/d/y hh:mm:ssP" (PM)

Note: leading zeroes are not required on m,d,y,h,m or s values, but are allowed.

Note: time[] array must be of length 7, or larger.

void setDateTime (byte* time)

Set current time copying values in time[] array to DS3231's registers.

Note: time[] array must be of length 7, or larger.

void getDateTime (byte* time)

Get current time by reading DS3231's registers into the time[] array.

Note: time[] array must be of length 7 or larger.

char* timeToString (byte* time, char* dst)

Convert time value in time[] array into ASCII string copied into dst[] array.  Format of ACSII output is either "hh:mm:ss PM" or "hh:mm:ss" depending on how  time was originally set via parseTime() or parseDateTime().  All values have a leading zero to maintain a fixed length format.

Note: returns pointer to dst[] array passed a parameter to support chain calls.  

Note: time[] array must be of length 7, or larger.

Note: dst[] array must support expected output format (either length 9 (24 hour), or length 12 (AM/PM), which includes terminating null.

char* dateToString (byte* time, char* dst)

Convert date value in time[] array into ASCII string copied into dst[] array.  ACSII output is a null terminated string such as "mm/dd/yy" with leading zeroes for a fixed length format.  The format of the output string is set by the format of the string passed to parseTime() or parseDate() that was used to set the time value.  Here are some example output strings:

Note: returns pointer to dst[] array passed a parameter to support chain calls.  

Note: time[] array must be of length 7, or larger.

Note: dst[] array must support expected output format (either length 9 (24 hour), or length 12 (AM/PM), which includes terminating null.

char* dayOfWeekToString (byte* time, char* dst)

Convert the day of week value in time[] array into ASCII string copied into dst[] array.  ACSII output is a null terminated string with the value of either "Sun", "Mon", "Tue", "Wed", "Thr", "Fri" or "Sat".

Note: returns pointer to dst[] array passed a parameter to support chain calls.  

Note: time[] array must be of length 7, or larger.

Note: dst[] array must be at least 9.

unsigned long timeToSeconds (byte* time)

Convert time value in time[] array into an unsigned long value that represents the number of seconds since midnight (0 - 86399).  Used internally by the addTime() function  to compute a future time, but may be useful for other purposes, such as conversion of time to some other format.

boolean addTime (byte* time, unsigned long seconds)

Add the number of seconds to the time value in the time[] array.  Provided as a way to reissue an alarm by computing a new time advanced from the current time.  Returns 'true' if addition caused wrap around to new day.

Note: time[] array must be of length 7, or larger.

void setAlarm (byte* time, byte type)

Set the Alarm selected via the 'type' value (values defined  in DS3231.h)  See example program to see how this is used and the DS3231 data sheet for additional details on how these values are used.

Important: the time format (24 hr, AM/PM) used to define the Alarm must match the time format of the DS3231's clock or the Alarm will not trip.

Here are the valid 'type' values for Alarm1:

Here are the valid 'type' values for Alarm2:

void enableAlarmInt (byte alarm, boolean enable)

Enable or disable alarm defined by 'alarm' value (1 = alarm1, 2 = alarm2, 3 = both alarms 1 & 2).  May be used to enable or disable each alarm individually, or both at the same time.  For example, calling enableAlarm(2, true) will enable alarm1 without altering the enable status of alarm2, but calling enableAlarm(3, true) will enable both alarms.

void clearAlarms (void) 

Clear internal alarm status and IRQ output pin for both alarms (if set).

byte getAlarms (void)

Returns value indicating which Alarms are active (1 = Alarm1, 2 = Alarm2, 3 = both Alarms).

byte* getAlarmTime (byte alarm, byte* time)

Retreive a previously set Alarm time and copy into the time[] array.  Copy time of Alarm1 into time[] if 'alarm' == 1, or time of Alarm2 if 'alarm' == 2.

Note: time[] array must be of length 7.

void enable32kHzPin (boolean enable)

Enable or disable the DS3231's 32 kHz output pin.