DS3231 — это микросхема часов реального времени (RTC, Real-Time Clock). Она автономно считает секунды, минуты, часы, дни недели, дату, месяц и год, даже когда Arduino или ESP32 выключены. Для этого модуль получает основное питание от платы и резервное — от маленькой батарейки.
Такой модуль нужен, когда проект должен понимать реальное календарное время без постоянного доступа к интернету: например, включать свет по расписанию, вести лог измерений с корректными метками времени, будить ESP32 раз в сутки, управлять поливом или показывать часы на дисплее.
DS3231 особенно популярен, потому что точнее простых RTC-модулей вроде DS1307: внутри уже есть кварцевый резонатор и температурная компенсация частоты. По спецификации оригинальный DS3231 обеспечивает точность до ±2 ppm при 0…40 °C и до ±3,5 ppm при −40…85 °C. Это соответствует порядку одной минуты в год при нормальной температуре, хотя реальный результат зависит от происхождения микросхемы и качества конкретного модуля.
Что умеет DS3231
| Возможность | Что это даёт проекту |
|---|---|
| Часы и календарь | Секунды, минуты, часы, день недели, число, месяц и год |
| Високосные годы | Календарь сам учитывает длину месяцев и високосные годы до 2100 года |
| Резервное питание | Время продолжает идти при отключении основной платы |
| Интерфейс I2C | Для связи нужны всего две сигнальные линии: SDA и SCL |
| Высокая точность | Внутренний TCXO компенсирует влияние температуры на частоту |
| Два будильника | Можно генерировать прерывание в заданное время |
| Выход SQW/INT | Квадратный сигнал или активный низкий сигнал от будильника |
| Выход 32K | Отдельный эталонный сигнал 32,768 кГц |
| Датчик температуры | Измерение температуры кристалла, обычно с разрешением 0,25 °C; это не замена выносному датчику воздуха |
Микросхема работает по I2C с фиксированным адресом 0x68. Поэтому на одной I2C-шине нельзя одновременно использовать DS3231 и DS1307: у них совпадает адрес.
Как DS3231 сохраняет время без питания
В обычном режиме питание приходит на контакт VCC. Когда питание платы исчезает, DS3231 автоматически переключается на резервный вход VBAT, который на готовом модуле обычно соединён с держателем батарейки.
Важно понимать, что батарейка поддерживает прежде всего сам RTC: ход часов, календарь и критически нужные внутренние регистры. Arduino/ESP32, экран, Wi-Fi и подключённые датчики от неё работать не будут.
Внутри оригинальной DS3231 есть температурно-компенсированный генератор (TCXO) с частотой 32,768 кГц. Микросхема измеряет температуру и корректирует работу генератора, поэтому время менее чувствительно к нагреву и охлаждению, чем в RTC, где внешний кварц подключён отдельно.
DS3231, DS3231M и дешёвые модули
На маркетплейсах под названием «DS3231» встречаются разные устройства:
- Оригинальный DS3231/DS3231SN — RTC с кварцевым TCXO. Для него заявляется точность ±2 ppm при 0…40 °C.
- DS3231M — совместимый по функциям вариант с MEMS-резонатором; его паспортная точность хуже: до ±5 ppm. Для большинства бытовых проектов он всё равно подходит.
- Модули ZS-042 и аналоги — обычно плата с RTC, держателем батарейки и иногда EEPROM AT24C32. Наличие платы с маркировкой DS3231 не гарантирует происхождение установленной микросхемы.
Для расписания освещения, даталоггера, метеостанции или теплицы разница чаще всего не критична. Но если важна долговременная точность, покупайте модуль у проверенного поставщика, сверяйте маркировку чипа и периодически сравнивайте его с NTP/GPS/эталонным временем.
Распиновка модуля DS3231
У плат чаще всего есть шесть или семь выводов:
| Вывод на модуле | Назначение | Подключение |
|---|---|---|
VCC | Основное питание модуля | 3.3 V или 5 V — зависит от конкретной платы и уровней I2C |
GND | Общий провод | GND контроллера |
SDA | Данные I2C | SDA контроллера |
SCL | Тактирование I2C | SCL контроллера |
SQW / INT | Квадратный сигнал или выход прерывания от будильника | Опционально на GPIO с прерыванием |
32K | Выход 32,768 кГц | Обычно не нужен |
RST | Сброс, бывает на платах с полным выводом микросхемы | Обычно не подключают |
На платах ZS-042 также может быть микросхема памяти AT24C32. Это независимая I2C EEPROM, а не часть RTC. Её адрес обычно находится в диапазоне 0x50–0x57; конкретное значение зависит от разводки адресных выводов платы.
Важное предупреждение о батарейке
Многие дешёвые модули DS3231 с держателем под «2032» имеют цепь подзаряда: часто это диод и резистор рядом с батарейным держателем. Такая схема рассчитана на перезаряжаемую LIR2032, но продавцы нередко кладут в комплект обычную одноразовую литиевую CR2032.
Обычную CR2032 нельзя заряжать. Если модуль питается от 5 V и зарядная цепь не отключена, попытка подзаряда может привести к вздутию, протечке и повреждению батареи или модуля.
Безопасные варианты:
- использовать LIR2032 только если вы понимаете ограничения зарядной схемы конкретного модуля;
- использовать обычную CR2032, но отключить зарядную цепь на модуле — в зависимости от ревизии обычно удаляют зарядный диод или последовательный резистор;
- выбрать модуль без зарядной цепи;
- не устанавливать батарейку, если резервное хранение времени пока не требуется.
Перед доработкой платы изучите её дорожки и маркировку компонентов. У разных ревизий ZS-042 разводка может отличаться.
Подключение DS3231 к Arduino Uno / Nano
У Arduino Uno и классического Nano аппаратная I2C-шина выведена на A4 и A5:
| DS3231 | Arduino Uno / Nano |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 / SDA |
| SCL | A5 / SCL |
| SQW/INT | D2, если нужны будильники и прерывания |
Схема в текстовом виде:
DS3231 Arduino Uno / Nano
------ ------------------
VCC ------------- 5V
GND ------------- GND
SDA ------------- A4 (SDA)
SCL ------------- A5 (SCL)
SQW ------------- D2 [необязательно]
На Arduino Mega 2560 линии I2C находятся на SDA = 20 и SCL = 21. На платах с отдельными подписанными контактами SDA/SCL лучше пользоваться именно ими, а не ориентироваться только на номера аналоговых входов.
Подключение DS3231 к ESP32
У классической ESP32 DevKit часто используют GPIO21 для SDA и GPIO22 для SCL. На ESP32 можно назначить I2C практически на другие подходящие GPIO программно, но для первого проекта лучше начать с этой распространённой пары.
| DS3231 | ESP32 DevKit |
|---|---|
| VCC | 3V3 |
| GND | GND |
| SDA | GPIO21 |
| SCL | GPIO22 |
| SQW/INT | GPIO27, GPIO25 или другой свободный GPIO [необязательно] |
DS3231 ESP32 DevKit
------ ------------
VCC ------------- 3V3
GND ------------- GND
SDA ------------- GPIO21
SCL ------------- GPIO22
SQW ------------- GPIO27 [необязательно]
Почему ESP32 лучше питать от 3,3 V
Сама DS3231 по паспорту может работать в диапазоне питания 2,3…5,5 V. Однако многие готовые модули содержат подтягивающие резисторы I2C к VCC. Если подать на модуль 5 V, линии SDA и SCL могут подтянуться к 5 V — это небезопасно для GPIO ESP32, которые не являются 5-вольтовыми tolerant-входами.
Поэтому для ESP32 подключайте VCC модуля к 3V3, если конкретная плата DS3231 стабильно работает при таком питании. Если модуль требует 5 V или на нём есть другие особенности обвязки, используйте двунаправленный I2C level shifter и проверяйте уровни мультиметром или осциллографом.
Подробнее о выборе GPIO и уровнях сигналов: .
Проверяем I2C-адрес сканером
Перед подключением библиотеки полезно проверить шину I2C. DS3231 должен появиться по адресу 0x68.
Сканер для Arduino
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("I2C scan started");
}
void loop() {
byte error;
byte address;
int devices = 0;
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("Found I2C device at 0x");
if (address < 16) Serial.print('0');
Serial.println(address, HEX);
devices++;
}
}
if (devices == 0) {
Serial.println("No I2C devices found");
}
Serial.println("---");
delay(3000);
}
Сканер для ESP32
Для ESP32 важно передать пины в Wire.begin():
#include <Wire.h>
constexpr int SDA_PIN = 21;
constexpr int SCL_PIN = 22;
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("I2C scan started");
}
void loop() {
int devices = 0;
for (uint8_t address = 1; address < 127; address++) {
Wire.beginTransmission(address);
uint8_t error = Wire.endTransmission();
if (error == 0) {
Serial.printf("Found I2C device at 0x%02X\n", address);
devices++;
}
}
if (devices == 0) {
Serial.println("No I2C devices found");
}
Serial.println("---");
delay(3000);
}
Откройте Serial Monitor на скорости 115200 бод. Нормальный результат:
Found I2C device at 0x68
Если видите ещё один адрес, например 0x57, это может быть EEPROM AT24C32 на той же плате.
Библиотека RTClib в Arduino IDE
Для примеров ниже используется популярная библиотека RTClib от Adafruit.
Установка:
- В Arduino IDE откройте Sketch → Include Library → Manage Libraries…
- Введите в поиск
RTClib. - Выберите библиотеку RTClib by Adafruit.
- Нажмите Install.
RTClib поддерживает RTC_DS3231 и предоставляет простые методы для чтения времени, установки даты/времени, проверки потери питания и чтения температуры.
Пример 1. Читаем дату, время и температуру
Этот скетч подходит и для Arduino Uno/Nano, и для ESP32. Для ESP32 раскомментируйте строку Wire.begin(21, 22) и используйте свои пины при необходимости.
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
void setup() {
Serial.begin(115200);
// Для ESP32 при нестандартных пинах I2C:
// Wire.begin(21, 22);
if (!rtc.begin()) {
Serial.println("DS3231 не найден. Проверьте питание и I2C-подключение.");
while (true) {
delay(1000);
}
}
if (rtc.lostPower()) {
Serial.println("RTC потерял питание: время нужно установить.");
}
}
void loop() {
DateTime now = rtc.now();
char timestamp[] = "DD.MM.YYYY hh:mm:ss";
Serial.println(now.toString(timestamp));
Serial.print("Temperature: ");
Serial.print(rtc.getTemperature());
Serial.println(" C");
delay(1000);
}
Пример вывода:
01.09.2026 18:42:07
Temperature: 28.25 C
Температура отражает состояние кристалла и платы, а не обязательно температуру воздуха в комнате. Для метеостанции или теплицы используйте BME280, SHT31, DS18B20 либо другой внешний датчик.
Пример 2. Устанавливаем время один раз
Новый модуль может иметь случайную дату. Также время сбрасывается, если отсутствовало и основное питание, и резервная батарейка. Установить его можно вручную или по времени компиляции скетча.
Вариант A: установить дату и время вручную
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
void setup() {
Serial.begin(115200);
// Для ESP32:
// Wire.begin(21, 22);
if (!rtc.begin()) {
Serial.println("DS3231 не найден");
while (true) delay(1000);
}
rtc.adjust(DateTime(2026, 9, 1, 18, 45, 0));
Serial.println("Время установлено");
}
void loop() {
}
Прошейте скетч один раз, убедитесь, что время задано, а затем закомментируйте или удалите строку:
rtc.adjust(DateTime(2026, 9, 1, 18, 45, 0));
Если оставить её в программе, часы будут заново возвращаться к этой дате после каждого перезапуска контроллера.
Вариант B: установить по времени компиляции
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
Этот вариант устанавливает дату и время, записанные компилятором в прошивку. Он удобен для первого старта, но есть нюанс: время соответствует моменту компиляции, а не точной секунде прошивки. Кроме того, lostPower() становится истинным, когда DS3231 останавливал генератор из-за отсутствия питания; этот флаг не следует использовать как вечную причину для установки времени на каждом старте.
Для более точной синхронизации ESP32 с Wi-Fi лучше получить UTC через NTP и записать его в DS3231. Это можно вынести в отдельную статью: .
Пример 3. Полный минимальный скетч с автоматической первичной установкой
Этот вариант читает время всегда, а устанавливает его от времени компиляции только если DS3231 сообщает о потере питания.
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
void setup() {
Serial.begin(115200);
// Для ESP32 раскомментируйте:
// Wire.begin(21, 22);
if (!rtc.begin()) {
Serial.println("Не удалось найти DS3231");
while (true) delay(1000);
}
if (rtc.lostPower()) {
Serial.println("Устанавливаем время после потери питания");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
DateTime now = rtc.now();
Serial.print(now.year());
Serial.print('-');
if (now.month() < 10) Serial.print('0');
Serial.print(now.month());
Serial.print('-');
if (now.day() < 10) Serial.print('0');
Serial.print(now.day());
Serial.print(' ');
if (now.hour() < 10) Serial.print('0');
Serial.print(now.hour());
Serial.print(':');
if (now.minute() < 10) Serial.print('0');
Serial.print(now.minute());
Serial.print(':');
if (now.second() < 10) Serial.print('0');
Serial.println(now.second());
delay(1000);
}
Будильники DS3231 и выход SQW/INT
DS3231 содержит два независимых будильника. Когда условие будильника срабатывает, вывод INT/SQW может перейти в низкий уровень. Этот вывод обычно работает как open-drain: сам DS3231 уверенно тянет линию к GND, но для высокого уровня нужна подтяжка.
Будильники полезны для:
- пробуждения ESP32 из deep sleep;
- включения измерений по расписанию;
- запуска логирования раз в минуту, час или сутки;
- аппаратного сигнала, не зависящего от таймера в основном коде;
- работы устройства без Wi-Fi и без постоянного опроса времени.
Подключение SQW/INT к ESP32
DS3231 SQW/INT ---- GPIO27 ESP32
DS3231 GND ---- GND ESP32
Если на модуле нет подтяжки на INT/SQW или она не подходит уровню питания, добавьте резистор примерно 4,7–10 кОм между линией SQW/INT и 3V3. Не подтягивайте GPIO ESP32 к 5 V.
Пример: прерывание от будильника каждые 60 секунд
Ниже показан базовый пример с RTClib. Реальные имена методов настройки alarm зависят от установленной версии RTClib; перед компиляцией обновите библиотеку и проверьте её examples для DS3231.
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
constexpr int RTC_INT_PIN = 27;
volatile bool alarmTriggered = false;
void IRAM_ATTR onRtcAlarm() {
alarmTriggered = true;
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
pinMode(RTC_INT_PIN, INPUT_PULLUP);
if (!rtc.begin()) {
Serial.println("DS3231 не найден");
while (true) delay(1000);
}
rtc.disable32K();
rtc.clearAlarm(1);
rtc.clearAlarm(2);
rtc.writeSqwPinMode(DS3231_OFF);
if (!rtc.setAlarm1(
rtc.now() + TimeSpan(60),
DS3231_A1_Date
)) {
Serial.println("Не удалось настроить Alarm 1");
}
attachInterrupt(digitalPinToInterrupt(RTC_INT_PIN), onRtcAlarm, FALLING);
}
void loop() {
if (alarmTriggered) {
alarmTriggered = false;
Serial.println("Сработал будильник DS3231");
// Подтверждаем флаг и назначаем следующее срабатывание через 60 секунд.
rtc.clearAlarm(1);
rtc.setAlarm1(rtc.now() + TimeSpan(60), DS3231_A1_Date);
}
}
Этот пример показывает принцип: DS3231 выдаёт аппаратное прерывание, контроллер очищает флаг будильника и назначает следующее событие. В рабочем устройстве не выполняйте долгие операции внутри ISR: обработчик прерывания должен только установить флаг, а основную работу выполняйте в loop().
Для ESP32 deep sleep потребуется дополнительно настроить пробуждение по внешнему GPIO и выбрать пин, который поддерживает используемый режим пробуждения. Это отдельная тема, поскольку доступные механизмы отличаются между обычным ESP32, S2, S3, C3 и C6.
Квадратный сигнал SQW и выход 32K
Вывод INT/SQW может использоваться не только для будильников, но и как программируемый квадратный сигнал. В DS3231 доступны частоты 1 Гц, 4,096 кГц, 8,192 кГц и 32,768 кГц. Отдельный вывод 32K выдаёт фиксированную частоту 32,768 кГц, если функция включена.
В бытовых Arduino-проектах эти выводы нужны редко. Они могут быть полезны как точный временной опорный сигнал, источник аппаратного прерывания или для синхронизации внешней логики.
Частые проблемы
Сканер не находит 0x68
Проверьте последовательно:
- Есть ли общее соединение GND.
- Не перепутаны ли SDA и SCL.
- Используются ли верные пины I2C на вашей плате.
- Вызван ли
Wire.begin(21, 22)на ESP32 с такой распиновкой. - Исправен ли USB-кабель и питание платы.
- Не слишком ли длинные провода и нет ли плохих контактов на breadboard.
- Не питается ли модуль от 5 V при прямом подключении к ESP32 без согласования уровней.
Время сбрасывается при отключении питания
- Установите резервную батарейку правильного типа.
- Проверьте её напряжение и контакты в держателе.
- Убедитесь, что время было записано методом
rtc.adjust(). - Проверьте, что не выполняете
rtc.adjust()при каждом старте программы. - Убедитесь, что модуль не повреждён неправильной зарядкой CR2032.
Время всегда возвращается к одной дате
Почти всегда в скетче осталась строка rtc.adjust(...), которая вызывается в setup() при каждом reset. Оставляйте установку времени только на первый запуск или под условием rtc.lostPower().
На ESP32 шина работает только от 3,3 V
Это ожидаемо для многих модулей. При питании DS3231 от 5 V подтягивающие резисторы I2C могут поднять SDA/SCL выше безопасного уровня ESP32. Используйте питание 3V3 либо level shifter.
Время заметно спешит или отстаёт
- Проверьте, не установлен ли вариант DS3231M или совместимый клон.
- Сравните часы с NTP или GPS в течение нескольких дней/недель.
- Убедитесь, что модуль не расположен рядом с сильным источником тепла.
- Для тонкой корректировки оригинальный DS3231 имеет регистр aging offset, но применять его стоит только после измерения реального стабильного ухода.
Практические применения
- Автополив: включать насос только в нужные часы и не зависеть от Wi-Fi.
- Метеостанция: добавлять корректную дату и время к измерениям температуры, влажности и давления.
- Логгер на SD-карте: создавать файлы по дате и хранить timestamp каждой записи.
- Реле по расписанию: управлять подсветкой, вентиляцией, кормушкой или зарядным устройством.
- ESP32 с deep sleep: просыпаться для измерения по внешнему будильнику RTC.
- Настольные часы: выводить время на OLED, LCD 1602 или LED-матрицу.
Итог
DS3231 — один из самых полезных модулей для автономных Arduino- и ESP32-проектов, где важно настоящее время. Он общается по I2C, имеет фиксированный адрес 0x68, сохраняет ход часов от резервной батарейки, автоматически ведёт календарь и даёт два аппаратных будильника.
Для простого старта подключите четыре линии — VCC, GND, SDA и SCL, проверьте адрес I2C-сканером, установите RTClib и запустите пример чтения времени. Если используете ESP32, подавайте на модуль 3,3 V или согласуйте уровни I2C. А если модуль имеет цепь заряда, никогда не ставьте обычную CR2032, пока не убедитесь, что зарядный путь отключён.