The DS3231 is a temperature-compensated real-time clock that drifts only about a minute a year, and keeps counting on a coin cell when the power goes.
On the ESP32 DevKit V1 it runs at 3.3 V on D21/D22 — no level shifting. The sketch sets the clock from your PC’s time the first time (or after the battery dies), then prints the date, time and the chip’s own temperature reading every second.
Wiring
| ESP32 DevKit V1 | DS3231 real-time clock (RTC) module | Wire | Notes |
|---|---|---|---|
| 3V3 | VCC | red | The module pulls SDA/SCL up to VCC, so 3V3 keeps them at ESP32 levels. The DS3231 keeps full accuracy at 3.3 V. |
| GND | GND | black | |
| D22 | SCL | yellow | |
| D21 | SDA | blue |
2.3–5.5 V part, 3.3 V board. The module pulls SDA/SCL up to its own VCC. On a 3.3 V board, power it from 3.3 V — the DS3231 keeps excellent time at 3.3 V.
Board quirks
- Why an RTC on a Wi-Fi board? NTP needs internet. During a power cut the router is off too, so a timer or logger that must know the time at boot gets it from the DS3231 and its coin cell.
- The common ZS-042 module has a charging resistor and diode that try to charge the coin cell from VCC. With a non-rechargeable CR2032 that is unsafe; remove the diode (or the 200 Ω resistor next to it), or fit an LIR2032. At 3.3 V the charge current is small, but the fix still matters.
- The time is set from your PC’s clock when you compile — IST if your PC is on IST. It only happens when the RTC reports lost power, so later uploads don’t overwrite a running clock.
- 32K and SQW are unused here. SQW can wake the ESP32 from deep sleep as an alarm output — wire it to an RTC-capable pin such as D33 with
esp_sleep_enable_ext0_wakeup(). - The module also carries a 24C32 EEPROM at 0x57. It is not the RTC; the RTC is always at 0x68.
Code
// DS3231 real-time clock on an ESP32 DevKit V1 — keeps time through power cuts.
// VCC → 3V3, GND → GND, SCL → D22, SDA → D21. 32K and SQW unused.
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
const char *DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
if (!rtc.begin(&Wire)) {
Serial.println("No DS3231 at 0x68 — check wiring");
while (true) delay(1000);
}
if (rtc.lostPower()) {
// First run or flat coin cell: set the clock to the time this sketch was compiled
// (your PC's local time, e.g. IST). Upload right after compiling for best accuracy.
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
Serial.println("RTC had lost power — set from compile time");
}
rtc.disable32K(); // the 32 kHz output isn't used; saves a little current
}
void loop() {
DateTime now = rtc.now();
Serial.printf("%s %02d-%02d-%04d %02d:%02d:%02d RTC temp %.2f °C\n", DAYS[now.dayOfTheWeek()],
now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(),
rtc.getTemperature());
delay(1000);
}// DS3231 real-time clock on an ESP32 DevKit V1 — keeps time through power cuts.
// VCC → 3V3, GND → GND, SCL → D22, SDA → D21. 32K and SQW unused.
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
const char *DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
if (!rtc.begin(&Wire)) {
Serial.println("No DS3231 at 0x68 — check wiring");
while (true) delay(1000);
}
if (rtc.lostPower()) {
// First run or flat coin cell: set the clock to the time this sketch was compiled
// (your PC's local time, e.g. IST). Upload right after compiling for best accuracy.
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
Serial.println("RTC had lost power — set from compile time");
}
rtc.disable32K(); // the 32 kHz output isn't used; saves a little current
}
void loop() {
DateTime now = rtc.now();
Serial.printf("%s %02d-%02d-%04d %02d:%02d:%02d RTC temp %.2f °C\n", DAYS[now.dayOfTheWeek()],
now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(),
rtc.getTemperature());
delay(1000);
}Library: RTClib (Adafruit) — compiled with RTClib 2.1.4.
Expected serial output
RTC had lost power — set from compile time
Tue 03-11-2026 14:22:07 RTC temp 29.25 °C
Tue 03-11-2026 14:22:08 RTC temp 29.25 °CRTC had lost power — set from compile time Tue 03-11-2026 14:22:07 RTC temp 29.25 °C Tue 03-11-2026 14:22:08 RTC temp 29.25 °C
Common errors
Time resets to the compile time on every power-up
The coin cell is flat, missing or the wrong way round. Replace the CR2032 (+ side up on most modules).
“No DS3231 at 0x68”
SDA/SCL swapped or no power. The I2C scanner should show 0x68 and 0x57.
Clock is a few seconds behind after setting
The compile-time stamp is taken before the upload finishes. Adjust once with rtc.adjust(DateTime(2026, 11, 3, 14, 22, 0)), upload, then remove the line.