This is a DS3231 high precision I2C RTC library for Arduino.
- libc
<time.h>
compatible - Read/write date/time
struct tm
- Set/get Unix epoch UTC
time_t
- Set/get time (hour, min, sec)
- Set/get date and time (hour, min, sec, mday, mon, year, wday)
- Read temperature (0.25 degree resolution)
- Alarm 1 (second/minute/hour/day/date match)
- Alarm 2 (minute/hour/day/date match)
- Polling and Alarm
INT/SQW
interrupt pin - Control
32kHz
out signal (enable/disable) - Control
SQW
signal (disable / 1 / 1024 / 4096 / 8192Hz) - Configure aging offset
- Serial terminal interface
- Full RTC register access
- Set date/time over serial with Python script
Any Arduino hardware with a TWI interface and Wire.h
support.
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 board - DS3231 | VCC | GND | SDA | SCL | SQW |
---|---|---|---|---|---|
Arduino UNO (ATMega328 boards) | 5V | GND | A4 | A5 | D2 (INT0) |
Arduino Mega2560 | 5V | GND | D20 | D21 | D2 (INT4) |
Arduino Leonardo | 5V | GND | D2 | D3 | D7 (INT6) |
Arduino DUE (ATSAM3X8E) | 3V3 | GND | 20 | 21 | 2 |
ESP8266 | 3V3 | GND | GPIO4 (D2) | GPIO5 (D1) | GPIO0 (D3) |
ESP32 | 3V3 | GND | GPIO21 | GPIO22 | GPIO0 |
Note: Tested ESP8266 / ESP32 boards:
- ESP8266 boards: ESP12F / WeMos D1 & R2 / Node MCU v2 / v3
- ESP32 boards: WeMos LOLIN32 / LOLIN D32
Other unlisted MCU's may work, but are not tested.
Arduino IDE | Examples | Erriez DS3231 RTC:
- AgingOffset Aging offset programming
- AlarmInterrupt Alarm with interrupts
- AlarmPolling Alarm polled
- DumpRegisters Dump registers polled
- SetBuildDateTime Set build date/time
- SetGetDateTime Simple RTC read date/time example
- SetGetTime Set/Get time
- SQWInterrupt Blink LED on SQW interrupt pin
- Temperature Temperature
- Terminal Advanced terminal interface with set date/time Python script
- Test Regression test
- WriteRead Write/read
struct tm
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
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.1 | v2.0.0 |
---|---|
DS3231_DateTime |
struct tm |
Function returns true : failure |
Function 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) |
|
ErriezDS3231Debug |
class removed to reduce flash size |
Wire.h
Terminal.ino
requiresErriezSerialTerminal
library.
Please refer to the Wiki page.