Home

Awesome

DS3231 high precision I2C RTC library for Arduino

Build Status

This is a DS3231 high precision I2C RTC library for Arduino.

DS3231

Library features

Hardware

Any Arduino hardware with a TWI interface and Wire.h support.

DS3231 - Arduino UNO

ESP32 notes

ESP32 problem: The Arduino IDE | Board manager installs an old version 1.0.0 from https://dl.espressif.com/dl/package_esp32_index.json which contains a broken I2C repeated start. Generating a repeated start with Wire.endTransmission(false); results in reading zero's from any I2C device and is not a problem of this library.

Solution: Use the Git master branch (or a newer release when available) to solve this problem as described on: https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/windows.md.

Pins

Pins board - DS3231VCCGNDSDASCLSQW
Arduino UNO (ATMega328 boards)5VGNDA4A5D2 (INT0)
Arduino Mega25605VGNDD20D21D2 (INT4)
Arduino Leonardo5VGNDD2D3D7 (INT6)
Arduino DUE (ATSAM3X8E)3V3GND20212
ESP82663V3GNDGPIO4 (D2)GPIO5 (D1)GPIO0 (D3)
ESP323V3GNDGPIO21GPIO22GPIO0

Note: Tested ESP8266 / ESP32 boards:

Other unlisted MCU's may work, but are not tested.

Examples

Arduino IDE | Examples | Erriez DS3231 RTC:

Documentation

Usage

Initialization

#include <Wire.h>
#include <ErriezDS3231.h>

// Create RTC object
ErriezDS3231 rtc;

void setup()
{
    // Initialize TWI with a 100kHz (default) or 400kHz clock
    Wire.begin();
    Wire.setClock(400000);
    
    // Initialize RTC
    while (!rtc.begin()) {
        // Error: Could not detect DS3231 RTC, retry after some time
        delay(3000);
    }
}

Check oscillator status at startup

// Check oscillator status
if (rtc.isOscillatorStopped()) {
    // Error: RTC oscillator stopped. Date/time cannot be trusted. 
    // Set new date/time before reading date/time.

    // Enable oscillator
    rtc.clockEnable(true);
}

Set time

// Write time to RTC
if (!rtc.setTime(12, 0, 0)) {
    // Error: Set time failed
}

Get time

uint8_t hour;
uint8_t minute;
uint8_t second;

// Read time from RTC
if (!rtc.getTime(&hour, &minute, &second)) {
    // Error: RTC read failed
}

Set date and time

// Write RTC date/time: 13:45:09  31 December 2019  0=Sunday, 2=Tuesday
if (!rtc.setDateTime(13, 45, 9,  31, 12, 2019,  2) {
    // Error: RTC write failed
}

Get date and time

uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t mday;
uint8_t mon;
uint16_t year;
uint8_t wday;

// Read RTC date/time
if (!rtc.getDateTime(&hour, &min, &sec, &mday, &mon, &year, &wday) {
    // Error: RTC read failed
}

// hour: 0..23
// min: 0..59
// sec: 0..59
// mday: 1..31
// mon: 1..12
// year: 2000..2099
// wday: 0..6 (0=Sunday .. 6=Saturday)

Write date/time struct tm

struct tm dt;

dt.tm_hour = 12;
dt.tm_min = 34;
dt.tm_sec = 56;
dt.tm_mday = 29;
dt.tm_mon = 1; // 0=January
dt.tm_year = 2020-1900;
dt.tm_wday = 6; // 0=Sunday

if (!rtc.write(&dt)) {
    // Error: RTC Read failed
}

Read date/time struct tm

struct tm dt;

// Read RTC date/time
if (!rtc.read(&dt)) {
    // Error: RTC read failed
}

Read Unix Epoch UTC

time_t t;

// Read Unix epoch UTC from RTC
if (!rtc.getEpoch(&t)) {
    // Error: RTC read failed
}

Write Unix Epoch UTC

// Write Unix epoch UTC to RTC
if (!rtc.setEpoch(1599416430UL)) {
    // Error: Set epoch failed
}

Get temperature

int8_t temperature = 0;
uint8_t fraction = 0;

// Force temperature conversion
// Without this call, it takes 64 seconds before the temperature is updated.
if (!rtc.startTemperatureConversion()) {
    // Error: Start temperature conversion failed 
}

// Read temperature
if (!rtc.getTemperature(&temperature, &fraction)) {
    // Error: Get temperature failed
}

// Print temperature. The output below is for example: 28.25C
Serial.print(temperature);
Serial.print(F("."));
Serial.print(fraction);
Serial.println(F("C"));

Program Alarm 1

Note: Alarm 1 and Alarm 2 have different behavior. Please refer to the documentation which Alarm1Type and Alarm2Type are supported. Some examples:

// Generate alarm 1 every second
rtc.setAlarm1(Alarm1EverySecond, 0, 0, 0, 0);

// Generate alarm 1 every minute and second match
rtc.setAlarm1(Alarm1EverySecond, 0, 0, 45, 30);

// Generate alarm 1 every day, hour, minute and second match
rtc.setAlarm1(Alarm1MatchDay, 
              1,  // Alarm day match (1 = Monday)
              12, // Alarm hour match
              45, // Alarm minute match
              30  // Alarm second match
);

Program Alarm 2

// Generate alarm 2 every minute
rtc.setAlarm2(Alarm2EveryMinute, 0, 0, 0);

// Generate alarm 2 every hour, minute match
rtc.setAlarm2(Alarm2MatchHours, 0, 23, 59);

// Generate alarm 2 every date, hour, minute match
rtc.setAlarm2(Alarm2MatchDate, 28, 7, 0);

Alarm polling

Note: The INT pin changes to low when an Alarm 1 or Alarm 2 match occurs and and the interrupt is enabled. The pin remains low until both alarm flags are cleared by the application.

// Poll alarm 1 flag
if (rtc.getAlarmFlag(Alarm1)) {
    // Handle Alarm 1
    
    // Clear alarm 1 flag
	rtc.clearAlarmFlag(Alarm1);
}

// Poll alarm 2 flag
if (rtc.getAlarmFlag(Alarm2)) {
    // Handle Alarm 2
    
    // Clear alarm 2 flag
	rtc.clearAlarmFlag(Alarm2);
}

Alarm interrupt

Note: Enabling interrupt will disable the SQW output signal.

// Uno, Nano, Mini, other 328-based: pin D2 (INT0) or D3 (INT1)
#define INT_PIN     2

// Alarm interrupt flag must be volatile
volatile bool alarmInterrupt = false;


#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
ICACHE_RAM_ATTR
#endif
void alarmHandler()
{
    // Set global interrupt flag
    alarmInterrupt = true;
}

void setup()
{
    ...

    // Attach to INT0 interrupt falling edge
    pinMode(INT_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(INT_PIN), alarmHandler, FALLING);
    
    // Enable Alarm 1 and 2 interrupts
    rtc.alarmInterruptEnable(Alarm1, true);
    rtc.alarmInterruptEnable(Alarm2, true);
}

void loop()
{
    // Check global alarm interrupt flag
    if (alarmInterrupt) {
        if (rtc.getAlarmFlag(Alarm1)) {
            // Handle alarm 1
            
            // Clear alarm 1 interrupt
            rtc.clearAlarmFlag(Alarm1);
        }
        
        if (rtc.getAlarmFlag(Alarm2)) {
            // Handle alarm 2
            
            // Clear alarm 2 interrupt
            rtc.clearAlarmFlag(Alarm2);
        }
    }
}

32kHz clock out

Enable or disable 32kHz output pin.

rtc.outputClockPinEnable(true);  // Enable 
rtc.outputClockPinEnable(false);	// Disable

Square Wave Out (SQW)

Note: Enabling SQW pin will disable the alarm INT signal.

rtc.setSquareWave(SquareWaveDisable);	// Disable
rtc.setSquareWave(SquareWave1Hz);		// 1Hz
rtc.setSquareWave(SquareWave1024Hz);	// 1024Hz
rtc.setSquareWave(SquareWave4096Hz);	// 4096Hz
rtc.setSquareWave(SquareWave8192Hz);	// 8192Hz

API changes v1.0.1 to v2.0.0

The API has been changed to make RTC libraries compatible with libc time.h. This makes it easier to calculate with date/time and port the application to different platforms. See changes below:

v1.0.1v2.0.0
DS3231_DateTimestruct tm
Function returns true: failureFunction returns false: failure
clearOscillatorStopFlag() merged into oscillatorEnable()
setDateTime()bool write(struct tm *dt)
getDateTime()bool read(struct tm *dt)
getEpochTime()time_t getEpoch()
bool setEpoch(time_t t)
void setDateTime(uint8_t hour, uint8_t min, uint8_t sec, uint8_t mday, uint8_t mon, uint16_t year, uint8_t wday)
void getDateTime(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *mday, uint8_t *mon, uint16_t *year, uint8_t *wday)
ErriezDS3231Debugclass removed to reduce flash size

Library dependencies

Library installation

Please refer to the Wiki page.

More Arduino Libraries from Erriez