Часы реального времени DS3231: подключение и RTClib
DS3231 это температурно-компенсированные часы реального времени с точностью ±2 ppm, то есть примерно минута ухода в год, и с батарейкой CR2032, которая хранит время при выключенном питании. Подключение по I2C: SDA на A4, SCL на A5, адрес 0x68.
Практика в уроках: первое время и будильник с LCD в разделе RTClib.
Ниже разбираем, что внутри модуля помимо часов, почему время слетает при каждой перезагрузке, чем дешёвый модуль отличается от правильного, что делать с батарейкой и как проверить готовые часы по семи шагам.
Схема подключения
| Модуль DS3231 | Arduino Uno |
|---|---|
| VCC | 5 В |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
На модуле обычно три микросхемы, и это стоит понимать. Основная, DS3231, это сам часовой кварц с RTC и встроенным термодатчиком. Вторая, AT24C32, это энергонезависимая память на 4 КБ, с тем же питанием от батарейки, она лежит на той же шине I2C по адресу 0x57 и часто используется для хранения настроек. Третья, преобразователь уровня или стабилизатор, зависит от версии платы. Отсюда практический вывод: если вы видите на шине два адреса, это нормально, а не сбой.
Подтяжки SDA и SCL на модуле обычно уже распаяны, но они подняты к VCC, то есть к 5 В. На ESP32 с логикой 3,3 В это недопустимо: выход 5 В на вход, который такого не терпит, может повредить плату. Для ESP32 нужно либо питать модуль от 3,3 В, либо выпаять подтяжки и поставить свои на 3,3 В. Ещё одна деталь: DS3231 питается от 2,3 до 5,5 В, так что от 3,3 В он работает штатно, а на Uno и Nano можно смело давать 5 В.
Код: установка и чтение времени
#include <RTClib.h>RTC_DS3231 rtc; void setup() { Serial.begin(9600); if (!rtc.begin()) { Serial.println("RTC не найден!"); while (1); } if (rtc.lostPower()) { rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); }} void loop() { DateTime now = rtc.now(); Serial.print(now.year()); Serial.print("-"); Serial.print(now.month()); Serial.print("-"); Serial.print(now.day()); Serial.print(" "); Serial.print(now.hour()); Serial.print(":"); Serial.print(now.minute()); Serial.print(":"); Serial.println(now.second()); delay(1000);}Проверка rtc.begin() нужна для того, чтобы понять, отвечает ли модуль вообще: если чипа на шине нет, begin() возвращает false, и скетч сразу об этом говорит. Дальше проверка rtc.lostPower(): она читает специальный флаг в часах, который ставится, когда питание пропадало и время сбилось. И только если флаг выставлен, вызывается adjust с датой и временем компиляции. Текст в скетче читается по частям: год, месяц, день, часы, минуты и секунды, а функция now() отдаёт готовый объект DateTime.
DS3231 или DS1307?
DS1307 это старый чип с обычным кварцем без температурной компенсации: он уходит на минуты в месяц и заметно проседает на холоде. DS3231 с термокомпенсацией точнее на порядок и стоит почти столько же, так что мы советуем DS3231 и не думать.
Но есть честная оговорка, о которой стоит знать. На рынке под названием DS3231 продаются два разных кристалла: один с MEMS-генератором, он действительно держит ±2 ppm, и второй, более старый, с обычным кварцем и термокомпенсацией, он компактнее и дешевле, но на дневном перепаде температур теряет минуты в месяц. Отличаются они по маркировке на плате и по корпусу чипа, и если модуль выглядит совсем плоским и тонким, скорее всего это второй вариант. Мы покупаем модули с MEMS-генератором и не переживаем о температуре.
Тупик: время слетает при каждой перезагрузке
Первый наш будильник работал, но стоило перезагрузить плату, и время снова становилось временем компиляции скетча. Мы решили, что батарейка не держит, поменяли её, и ничего не изменилось. Проверка была очевидной, но мы её по какой-то причине пропустили.
Дело было в коде: adjust() вызывался безусловно, при каждом старте, и затирал показания часов. Правильный вариант тот, что в примере выше: проверять lostPower() и корректировать время только тогда, когда часы реально потеряли питание. Второй сценарий с той же симптоматикой: батарейка в модуле стоит, но время всё равно сбрасывается, и вот тут важна подробность. Во многих модулях на плате стоит цепь зарядки от VCC к батарейке, рассчитанная на перезаряжаемый аккумулятор LIR2032. Если в такой модуль вставить обычную CR2032, она будет заряжаться, а это путь к тому, что она может потечь или взорваться. Проверяйте, есть ли на плате цепь зарядки, и ставьте батарейку того типа, на который модуль рассчитан.
Личный опыт: как ведёт себя модуль в реальных условиях
Мы пользовались несколькими модулями DS3231 в разных условиях и собрали наблюдения, которые не видны в даташите. Первый модуль стоял на столе рядом с работающей Arduino и показывал время ровно настолько, насколько позволяет сам класс точности: сверка с временем компьютера давала расхождение в пределах десятков секунд за несколько недель, и это ожидаемо. Второй модуль мы выносили на улицу и возвращали обратно, и здесь время уходило сильнее: кристалл реагирует на температуру, а DS3231 с MEMS-генератором реагирует на неё слабее кварцевого DS1307, но не никак.
Отдельно мы проверили, что происходит без батарейки. Модуль продолжает работать, пока на плату подано питание, и показывает время, записанное последний раз. Но стоит выключить питание и включить снова, как часы возвращаются к состоянию «питание пропадало», флаг lostPower поднимается, и время снова нужно задавать вручную. Из этого следует практическое правило: если в проекте важна история событий или расписание, проверку lostPower() надо делать и обрабатывать, а не полагаться на то, что время переживёт отключение питания.
Авторская позиция: какие часы взять
Мы советуем брать DS3231 с MEMS-генератором и с перезаряжаемой батарейкой LIR2032, если на модуле есть цепь зарядки. Модуль с обычной CR2032 удобнее только тем, что батарейку можно купить где угодно, зато в модуль с зарядкой такую батарейку ставить нельзя. Если важна размер, есть модули на AT24C32 поменьше, но там уже нет термокомпенсации и точность ниже.
Дальше важно не переплатить за то, что не нужно. Если проект живёт в сети и на ESP32, то сам RTC оказывается лишним звеном: время берётся по NTP, оно точнее и не требует батарейки вообще. DS3231 нужен там, где плата не имеет сети, питание может отключаться, а время должно пережить отключение: часы на датчиках, логирование событий, расписание полива, бортовой компьютер в машине. Наше правило: сначала спросите, откуда здесь взяться времени, и только потом выбирайте чип. Часто оказывается, что ответ уже есть в вашем проекте.