DS3231: часы реального времени для Arduino и ESP32 — подключение, код и полезные нюансы

DS3231: часы реального времени для Arduino и ESP32 — подключение, код и полезные нюансы

Полное руководство по модулю DS3231: что это за RTC-часы, как они работают, подключение к Arduino и ESP32 по I2C, примеры кода, установка времени, будильники, температура и батарейка.

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Данные I2CSDA контроллера
SCLТактирование I2CSCL контроллера
SQW / INTКвадратный сигнал или выход прерывания от будильникаОпционально на GPIO с прерыванием
32KВыход 32,768 кГцОбычно не нужен
RSTСброс, бывает на платах с полным выводом микросхемыОбычно не подключают

На платах ZS-042 также может быть микросхема памяти AT24C32. Это независимая I2C EEPROM, а не часть RTC. Её адрес обычно находится в диапазоне 0x500x57; конкретное значение зависит от разводки адресных выводов платы.

Важное предупреждение о батарейке

Многие дешёвые модули DS3231 с держателем под «2032» имеют цепь подзаряда: часто это диод и резистор рядом с батарейным держателем. Такая схема рассчитана на перезаряжаемую LIR2032, но продавцы нередко кладут в комплект обычную одноразовую литиевую CR2032.

Обычную CR2032 нельзя заряжать. Если модуль питается от 5 V и зарядная цепь не отключена, попытка подзаряда может привести к вздутию, протечке и повреждению батареи или модуля.

Безопасные варианты:

  • использовать LIR2032 только если вы понимаете ограничения зарядной схемы конкретного модуля;
  • использовать обычную CR2032, но отключить зарядную цепь на модуле — в зависимости от ревизии обычно удаляют зарядный диод или последовательный резистор;
  • выбрать модуль без зарядной цепи;
  • не устанавливать батарейку, если резервное хранение времени пока не требуется.

Перед доработкой платы изучите её дорожки и маркировку компонентов. У разных ревизий ZS-042 разводка может отличаться.

Подключение DS3231 к Arduino Uno / Nano

У Arduino Uno и классического Nano аппаратная I2C-шина выведена на A4 и A5:

DS3231Arduino Uno / Nano
VCC5V
GNDGND
SDAA4 / SDA
SCLA5 / SCL
SQW/INTD2, если нужны будильники и прерывания

Схема в текстовом виде:

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 программно, но для первого проекта лучше начать с этой распространённой пары.

DS3231ESP32 DevKit
VCC3V3
GNDGND
SDAGPIO21
SCLGPIO22
SQW/INTGPIO27, 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.

Установка:

  1. В Arduino IDE откройте Sketch → Include Library → Manage Libraries…
  2. Введите в поиск RTClib.
  3. Выберите библиотеку RTClib by Adafruit.
  4. Нажмите 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, пока не убедитесь, что зарядный путь отключён.