ESP32: Руководство по модулю часов реального времени DS3231 (RTC) – Получение времени и настройка будильников

Это руководство представляет собой вводное пособие по модулю часов реального времени DS3231 с ESP32. Модуль RTC DS3231 – это отличный модуль для точного хронометража, он также позволяет настраивать будильники, генерировать прямоугольные сигналы различных частот и получать показания температуры.

ESP32: Руководство по модулю часов реального времени DS3231 (RTC) -- Получение времени и настройка будильников

Используете модуль RTC DS1307? Следуйте этому руководству: ESP32: Guide for DS1307 Real Time Clock Module (RTC).

В этом руководстве мы рассмотрим следующие темы:

Введение в модули часов реального времени (RTC)

Модули RTC, такие как DS3231 и DS1307, имеют собственные миниатюрные часы для самостоятельного отслеживания времени. Обычно они поставляются с держателем батареи для подключения батарейки, чтобы они продолжали работать даже при перезагрузке ESP32 или отключении питания.

Модули RTC DS3231 и RTC DS1307

DS3231 и DS1307 – одни из самых популярных вариантов для использования с микроконтроллерами. Оба совместимы с ESP32 и обмениваются данными по протоколу I2C. DS3231 более точен, поскольку выдает результаты с температурной компенсацией. Кроме того, с DS3231 также можно настраивать внешние будильники, что может быть крайне полезно.

Знакомство с модулем RTC DS3231

На следующем изображении показан модуль RTC DS3231. Он использует кварцевый генератор с температурной компенсацией (TCXO) частотой 32 кГц для точного отслеживания времени (он устойчив к изменениям температуры). Благодаря этому он также позволяет получать данные о температуре.

Модуль RTC DS3231

Помимо точного отслеживания даты и времени, он также имеет встроенную память для хранения до двух будильников и может генерировать прямоугольные сигналы на различных частотах: 1 Гц, 4 кГц, 8 кГц и 32 кГц.

Связь с модулем RTC осуществляется по протоколу I2C. Обычно его адрес – 0x68.

Этот модуль также поставляется с EEPROM 24C32 объемом 32 байта, которую можно использовать для хранения любых энергонезависимых данных. Вы можете обращаться к этой памяти EEPROM по шине I2C, указав соответствующий адрес (0x57).

Держатель батареи DS3231

DS3231 поставляется с держателем батареи для подключения батарейки, обеспечивающей точное хронометрирование. В случае отключения питания модуль продолжит точно отслеживать время и сохранит все настройки будильников.

Вы должны использовать батарею LIR2032, которая является перезаряжаемой. Не используйте CR2032 (не перезаряжаемая).

Держатель батареи RTC DS3231 Модуль RTC DS3231 с резервной батареей

Если вы хотите использовать батарею CR2032, которая не является перезаряжаемой, вам необходимо отключить цепь зарядки батареи, отпаяв и удалив резистор (обозначенный R4 на моем модуле) рядом с диодом.

RTC DS3231 -- удаление резистора для неперезаряжаемой батареи

Будильники DS3231

DS3231 может хранить до двух будильников: будильник 1 и будильник 2. Эти будильники можно настроить на срабатывание по определенному времени и/или дате. При срабатывании будильника вывод SQW модуля выдает сигнал LOW.

Вы можете обнаружить этот сигнал с помощью ESP32 и вызвать прерывания или даже разбудить его из режима глубокого сна. Таким образом, эта функция крайне полезна для настройки периодического пробуждения из глубокого сна и других периодических задач, автоматизации на основе времени, а также одноразовых оповещений (поскольку вы можете сбросить будильник после его срабатывания).

Каждый будильник можно настроить на срабатывание в различных режимах. Эти режимы позволяют создавать будильники, которые повторяются каждую секунду, минуту, час, ежедневно, еженедельно или даже раз в месяц.

Будильник 1:

  • Каждую секунду

  • При совпадении секунд, минут, часов, дня или даты

Будильник 2:

  • Каждую минуту

  • При совпадении минут, часов, дня или даты

Мы рассмотрим, как настраивать будильники, далее в этом руководстве.

I2C-адрес модуля RTC DS3231

По умолчанию адрес RTC DS3231 – 0x68, а EEPROM, подключенная к модулю, имеет адрес 0x57. Вы можете запустить скетч сканера I2C для проверки адресов.

DS3231 -- получение I2C-адреса

Распиновка модуля RTC DS3231

В следующей таблице кратко описана распиновка модуля RTC DS3231.

32K

Выход генератора 32 кГц – может использоваться как источник тактового сигнала

SQW

Выход прямоугольного сигнала / прерывания

SCL

Вывод SCL для I2C

SDA

Вывод SDA для I2C

VCC

Питание модуля (3.3 В или 5 В)

GND

GND

Подключение модуля RTC DS3231 к ESP32

Вот список компонентов, необходимых для этого руководства:

Вы можете использовать ссылки выше или перейти напрямую на MakerAdvisor.com/tools для поиска всех компонентов по лучшей цене!

Подключите DS3231 к ESP32. Вы можете использовать следующую таблицу в качестве справки или посмотреть на схему подключения.

Модуль RTC DS3231

ESP32

SQW

GPIO 4 (или любой другой цифровой вывод)

SCL

GPIO 22

SDA

GPIO 21

VCC

3V3

GND

GND

ESP32 с модулем RTC DS3231 -- схема подключения

Вам также может быть полезно: Руководство по I2C-связи с ESP32.

Работа с RTC

Использование модуля RTC в ваших проектах всегда требует двух важных шагов.

  1. Установка текущего времени: вы можете сделать это вручную, вставив текущее время (или другое желаемое время) в код; системное локальное время; или получить время с NTP-сервера.

  2. Сохранение времени: чтобы RTC сохранял правильное время, даже при отключении питания, к нему необходимо подключить батарею. Модули RTC поставляются с держателем батареи, обычно для монетной батарейки.

Установка библиотеки RTCLib

Мы будем программировать ESP32 с использованием Arduino IDE. Убедитесь, что у вас установлены платы ESP32, следуя этому руководству: Установка платы ESP32 в Arduino IDE 2 (Windows, Mac OS X, Linux)

Существует несколько библиотек для взаимодействия с модулем RTC DS3231. Мы будем использовать RTCLib от Adafruit, которая совместима с модулями RTC DS1307, DS3231 и PCF8523. Кроме того, эта библиотека также совместима с платами ESP32 (хотя это не упоминается на странице библиотеки).

В Arduino IDE перейдите в Sketch > Include Library > Manage Libraries. Найдите RTCLib и установите библиотеку от Adafruit. Мы используем версию 2.1.4.

Arduino IDE -- установка библиотеки RTCLib

ESP32 с DS3231: Установка и чтение времени

ESP32 с модулем RTC DS3231 -- установка и чтение времени

Следующий пример устанавливает время на часах RTC, а затем считывает время в цикле каждые три секунды. Мы также считываем температуру. Этот код показывает два разных способа установки времени: синхронизацию RTC с системным временем (дата и время компиляции скетча) и установку определенной даты и времени вручную, записав их самостоятельно в код.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-ds3231-real-time-clock-arduino/
*********/

// Based on the RTCLib Library examples: https://github.com/adafruit/RTClib
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include "RTClib.h"

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void setup () {
  Serial.begin(115200);

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  // When time needs to be re-set on a previously configured device, the
  // following line sets the RTC to the date & time this sketch was compiled
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  //rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}

void loop () {
  // Get the current time from the RTC
  DateTime now = rtc.now();

  // Getting each time field in individual variables
  // And adding a leading zero when needed;
  String yearStr = String(now.year(), DEC);
  String monthStr = (now.month() < 10 ? "0" : "") + String(now.month(), DEC);
  String dayStr = (now.day() < 10 ? "0" : "") + String(now.day(), DEC);
  String hourStr = (now.hour() < 10 ? "0" : "") + String(now.hour(), DEC);
  String minuteStr = (now.minute() < 10 ? "0" : "") + String(now.minute(), DEC);
  String secondStr = (now.second() < 10 ? "0" : "") + String(now.second(), DEC);
  String dayOfWeek = daysOfTheWeek[now.dayOfTheWeek()];

  // Complete time string
  String formattedTime = dayOfWeek + ", " + yearStr + "-" + monthStr + "-" + dayStr + " " + hourStr + ":" + minuteStr + ":" + secondStr;

  // Print the complete formatted time
  Serial.println(formattedTime);

  // Getting temperature
  Serial.print(rtc.getTemperature());
  Serial.println("ºC");

  Serial.println();
  delay(3000);
}

Просмотреть исходный код

Как работает код

Начните с импорта библиотеки RTCLib.

#include "RTClib.h"

Затем создайте объект RTC_DS3231 с именем rtc.

RTC_DS3231 rtc;

Далее создайте массив символов с днями недели.

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

Вы можете получить доступ к каждому дню по его индексу. Например:

  • daysOfTheWeek[0] вернет «Sunday».

  • daysOfTheWeek[1] вернет «Monday».

В setup() инициализируйте Serial Monitor.

Serial.begin(115200);

Инициализируйте модуль RTC следующим образом:

if (! rtc.begin()) {
  Serial.println("Couldn't find RTC");
  Serial.flush();
  while (1) delay(10);
}

Проверка состояния RTC

Затем проверьте, потерял ли RTC питание, с помощью функции lostPower(). Если он не работает, потому что это новое устройство или потому что резервная батарея разрядилась, мы выведем сообщение в Serial Monitor и установим время.

if (rtc.lostPower()) {
  Serial.println("RTC lost power, let's set the time!");

Установка времени

Для установки времени на RTC мы можем использовать метод adjust() нашего объекта rtc. Следующая строка устанавливает дату и время RTC на текущую дату и время, когда этот скетч был последний раз скомпилирован.

rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

__DATE__ и __TIME__ – это макросы, которые предоставляют текущую дату и время на момент компиляции.

В качестве альтернативы вы можете установить дату и время вручную. Передайте поля времени в следующем порядке: год, месяц, день, час, минута, секунда. Эта строка закомментирована в коде.

// January 21, 2014 at 3am you would call:
rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

Если вам нужно переустановить время на ранее настроенном устройстве, вы можете вызвать одну из двух предыдущих строк для установки времени без проверки потери питания (это закомментировано в коде).

// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
//rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

Получение даты и времени

В loop() мы получаем дату и время каждые три секунды и выводим их в Serial Monitor.

Мы вызываем rtc.now() для получения текущей даты и времени из модуля RTC.

DateTime now = rtc.now();

Он возвращает объект DateTime, содержащий значения текущего года, месяца, дня, часа, минуты и секунды.

Для доступа к каждому полю даты и времени мы можем использовать следующие методы:

now.year()

Получает текущий год (например, 2024)

now.month()

Получает текущий месяц (1–12)

now.day()

Получает текущий день месяца (1–31)

now.dayOfTheWeek()

Получает день недели (0-6), где 0 – воскресенье, а 6 – суббота

now.hour()

Получает текущий час (0–23)

now.minute()

Получает текущую минуту (0–59)

now.second()

Получает текущую секунду (0–59)

Для преобразования результата в строку мы можем использовать метод String(). Мы также передаем DEC в качестве второго аргумента методу String() для получения десятичного числа.

String yearStr = String(now.year(), DEC);

В случае месяца, дня, часа, минуты и секунды мы добавляем ведущий ноль, когда число меньше 10. Таким образом, вместо, например: 3:5:6 (что выглядит странно для формата времени), вы получите 03:05:06.

String monthStr = (now.month() < 10 ? "0" : "") + String(now.month(), DEC);
String dayStr = (now.day() < 10 ? "0" : "") + String(now.day(), DEC);
String hourStr = (now.hour() < 10 ? "0" : "") + String(now.hour(), DEC);
String minuteStr = (now.minute() < 10 ? "0" : "") + String(now.minute(), DEC);
String secondStr = (now.second() < 10 ? "0" : "") + String(now.second(), DEC);

Для получения названия дня недели мы используем массив daysOfTheWeek, созданный в начале кода.

String dayOfWeek = daysOfTheWeek[now.dayOfTheWeek()];

В конце мы объединяем все поля времени в переменную и выводим их в Serial Monitor.

// Complete time string
String formattedTime = dayOfWeek + ", " + yearStr + "-" + monthStr + "-" + dayStr + " " + hourStr + ":" + minuteStr + ":" + secondStr;

// Print the complete formatted time
Serial.println(formattedTime);

DS3231 выдает результаты с температурной компенсацией. Мы можем получить измеряемую температуру с помощью метода getTemperature() объекта rtc. Он возвращает температуру в градусах Цельсия.

// Getting temperature
Serial.print(rtc.getTemperature());
Serial.println("ºC");

Тестирование примера

Подключив RTC к ESP32, загрузите код на вашу плату.

Откройте Serial Monitor на скорости 115200 бод. ESP32 установит время RTC и будет отображать текущее время и температуру каждые три секунды.

ESP32 DS3231 -- установка и получение времени и температуры

DS3231 с ESP32: Настройка будильников

ESP32 с DS3231 -- настройка будильников

Модуль RTC DS3231 позволяет настроить до двух будильников: будильник 1 и будильник 2. При использовании библиотеки RTCLib для будильников доступны следующие режимы:

Будильник

Режим

Значение (Срабатывание будильника…)

Будильник 1

DS3231_A1_PerSecond

каждую секунду

Будильник 1

DS3231_A1_Second

при совпадении секунд

Будильник 1

DS3231_A1_Minute

при совпадении минут

Будильник 1

DS3231_A1_Hour

при совпадении часа

Будильник 1

DS3231_A1_Date

при совпадении даты

Будильник 1

DS3231_A1_Day

при совпадении дня

Будильник 2

DS3231_A2_PerMinute

каждую минуту

Будильник 2

DS3231_A2_Minute

при совпадении минут

Будильник 2

DS3231_A2_Hour

при совпадении часа

Будильник 2

DS3231_A2_Date

при совпадении даты

Будильник 2

DS3231_A2_Day

при совпадении дня

Следующий пример показывает, как настроить два будильника и использовать их для вызова прерывания на ESP32 (узнайте больше о прерываниях ESP32 здесь).

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-ds3231-real-time-clock-arduino/
*********/

// Example based on the RTClib: implementation of an alarm using DS3231 https://github.com/adafruit/RTClib
#include <RTClib.h>
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 4

// LED for visual indication
const int ledPin = 2;

// set the alarms
// (year, month, day, hour, minutes, seconds)
DateTime alarm1Time = DateTime(2024, 12, 18, 12, 49, 0);
DateTime alarm2Time = DateTime(2024, 12, 18, 11, 10, 0);

void printCurrentTime(){
  // Get the current time from the RTC
  DateTime now = rtc.now();

  // Getting each time field in individual variables
  // And adding a leading zero when needed;
  String yearStr = String(now.year(), DEC);
  String monthStr = (now.month() < 10 ? "0" : "") + String(now.month(), DEC);
  String dayStr = (now.day() < 10 ? "0" : "") + String(now.day(), DEC);
  String hourStr = (now.hour() < 10 ? "0" : "") + String(now.hour(), DEC);
  String minuteStr = (now.minute() < 10 ? "0" : "") + String(now.minute(), DEC);
  String secondStr = (now.second() < 10 ? "0" : "") + String(now.second(), DEC);
  String dayOfWeek = daysOfTheWeek[now.dayOfTheWeek()];

  // Complete time string
  String formattedTime = dayOfWeek + ", " + yearStr + "-" + monthStr + "-" + dayStr + " " + hourStr + ":" + minuteStr + ":" + secondStr;

  // Print the complete formatted time
  Serial.println(formattedTime);
}

void onAlarm() {
  Serial.println("Alarm occurred!");
  // toggle the current LED state
  int state = digitalRead(ledPin);
  digitalWrite(ledPin, !state);
}

void setup() {
  Serial.begin(115200);
  pinMode (ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // initializing the rtc
  if(!rtc.begin()) {
    Serial.println("Couldn't find RTC!");
    Serial.flush();
    while (1) delay(10);
  }

  if(rtc.lostPower()) {
    // this will adjust to the date and time at compilation
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  // Uncomment if you need to adjust the time
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  //we don't need the 32K Pin, so disable it
  rtc.disable32K();

  // Trigger an interrupt when the alarm happens
  pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);

  // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
  // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
  rtc.clearAlarm(1);
  rtc.clearAlarm(2);

  // stop oscillating signals at SQW Pin, otherwise setAlarm1 will fail
  rtc.writeSqwPinMode(DS3231_OFF);

  // turn off alarm 2 (in case it isn't off already)
  // again, this isn't done at reboot, so a previously set alarm could easily go overlooked
  rtc.disableAlarm(2);

  // Schedule Alarm1 to fire when the minutes match
  if(!rtc.setAlarm1(alarm1Time, DS3231_A1_Minute)) {  // this mode triggers the alarm when the minutes match
    Serial.println("Error, alarm wasn't set!");
  }else {
    Serial.println("Alarm 1 will happen at specified time");
  }
}

void loop() {
  // print current date and time
  printCurrentTime();

  // Get Details about the alarm1
  DateTime alarm1 = rtc.getAlarm1();
  Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
  char alarm1Date[12] = "DD hh:mm:ss";
  alarm1.toString(alarm1Date);
  Serial.print("[Alarm1: ");\
  Serial.print(alarm1Date);\
  Serial.print(", Mode: ");\
  switch (alarm1mode) {\
    case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;\
    case DS3231_A1_Second: Serial.print("Second"); break;\
    case DS3231_A1_Minute: Serial.print("Minute"); break;\
    case DS3231_A1_Hour: Serial.print("Hour"); break;\
    case DS3231_A1_Date: Serial.print("Date"); break;\
    case DS3231_A1_Day: Serial.print("Day"); break;\
  }\
  // the value at SQW-Pin (because of pullup 1 means no alarm)\
  Serial.print("] SQW: ");
  Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
  // whether a alarm fired
  Serial.print(" Fired: ");
  Serial.print(rtc.alarmFired(1));

  // Only one alarm can be set at a time, reset alarm 1 and activate alarm 2
  // resetting SQW and alarm 1 flag
  // the next alarm could now be configurated
  if (rtc.alarmFired(1)) {
      rtc.clearAlarm(1);
      Serial.println(" - Alarm cleared");

      // Set Alarm 2
      if(!rtc.setAlarm2(alarm2Time, DS3231_A2_Minute)) {  // this mode triggers the alarm when the minutes match
        Serial.println("Error, alarm wasn't set!");
      }else {
        Serial.println("Alarm 2 will happen at specified time");
      }

    // Get Details about the alarm2
    DateTime alarm1 = rtc.getAlarm2();
    Ds3231Alarm2Mode alarm2mode = rtc.getAlarm2Mode();
    char alarm2Date[12] = "DD hh:mm:ss";
    alarm1.toString(alarm2Date);
    Serial.print("[Alarm2: ");\
    Serial.print(alarm2Date);\
    Serial.print(", Mode: ");\
    switch (alarm2mode) {\
      case DS3231_A2_PerMinute: Serial.print("Every Minute"); break;\
      case DS3231_A2_Minute: Serial.print("Minute"); break;\
      case DS3231_A2_Hour: Serial.print("Hour"); break;\
      case DS3231_A2_Date: Serial.print("Date"); break;\
      case DS3231_A2_Day: Serial.print("Day"); break;\
    }\
    // the value at SQW-Pin (because of pullup 1 means no alarm)\
    Serial.print("] SQW: ");
    Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
    // whether a alarm fired
    Serial.print(" Fired: ");
    Serial.print(rtc.alarmFired(1));
  }

  Serial.println();
  delay(2000);
}

Просмотреть исходный код

Важные замечания о будильниках:

  • RTC позволяет сохранять до двух будильников;

  • одновременно может быть активен только один будильник;

  • после срабатывания будильника необходимо сбросить его флаг, чтобы избежать повторного срабатывания и сбоя ESP32;

  • необходимо деактивировать один будильник перед активацией другого.

Как работает код?

Мы уже рассмотрели, как инициализировать RTC, устанавливать и получать время из модуля DS3231. Мы объясним только соответствующие части, связанные с будильниками.

Определите GPIO, подключенный к выводу SQW. В нашем случае мы используем GPIO 4, вы можете использовать любой другой подходящий GPIO.

// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 4

Сначала мы создаем два объекта DateTime для установки времени будильника 1 и будильника 2.

DateTime alarm1Time = DateTime(2024, 12, 18, 12, 05, 0);
DateTime alarm2Time = DateTime(2024, 12, 18, 11, 10, 0);

Затем нам нужно отключить вывод 32K, поскольку мы его не используем.

rtc.disable32K();

Установите вывод SQW как прерывание, чтобы мы могли вызвать функцию при срабатывании будильника. SQW работает по активному низкому уровню, что означает, что его состояние обычно HIGH и меняется на LOW при срабатывании будильника. При срабатывании будильника мы вызовем функцию onAlarm.

// Trigger an interrupt when the alarm happens
pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);

Функция onAlarm(), определенная ранее в коде, выводит сообщение в Serial Monitor и инвертирует текущее состояние GPIO 2 (подключенного к встроенному светодиоду ESP32).

void onAlarm() {
  Serial.println("Alarm occured!");
  int state = digitalRead(ledPin);
  digitalWrite(ledPin, !state);
}

Сбросьте оба будильника – будильник 1 и будильник 2 – перед настройкой любого будильника.

rtc.clearAlarm(1);
rtc.clearAlarm(2);

Мы будем использовать вывод SQW для срабатывания будильников. Мы не будем использовать его функцию генерации прямоугольных сигналов. Поэтому нам нужно её остановить.

rtc.writeSqwPinMode(DS3231_OFF);

Одновременно может работать только один будильник. Поэтому отключите будильник 2 перед настройкой будильника 1.

rtc.disableAlarm(2);

Настройте будильник 1 с помощью функции setAlarm1() объекта rtc. Передайте в качестве аргументов время для будильника 1 и режим будильника. Мы уже рассмотрели варианты режимов для будильника 1 и будильника 2 ранее. В данном случае мы устанавливаем DS3231_A1_Minute, что означает, что будильник сработает при совпадении минут.

// Schedule Alarm1 to fire when the minutes match
if(!rtc.setAlarm1(alarm1Time, DS3231_A1_Minute)) {  // this mode triggers the alarm when the minutes match
  Serial.println("Error, alarm wasn't set!");
}else {
  Serial.println("Alarm 1 will happen at specified time");
}

В loop() мы выводим информацию о текущем будильнике.

// Get Details about the alarm1
DateTime alarm1 = rtc.getAlarm1();
Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
char alarm1Date[12] = "DD hh:mm:ss";
alarm1.toString(alarm1Date);
Serial.print("[Alarm1: ");\
Serial.print(alarm1Date);\
Serial.print(", Mode: ");\
switch (alarm1mode) {\
  case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;\
  case DS3231_A1_Second: Serial.print("Second"); break;\
  case DS3231_A1_Minute: Serial.print("Minute"); break;\
  case DS3231_A1_Hour: Serial.print("Hour"); break;\
  case DS3231_A1_Date: Serial.print("Date"); break;\
  case DS3231_A1_Day: Serial.print("Day"); break;\
}\
// the value at SQW-Pin (because of pullup 1 means no alarm)\
Serial.print("] SQW: ");
Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
// whether a alarm fired
Serial.print(" Fired: ");
Serial.print(rtc.alarmFired(1));

Мы можем проверить, сработал ли будильник 1, используя следующую строку:

if (rtc.alarmFired(1)) {

Когда он срабатывает, мы сбрасываем этот будильник и начинаем настройку будильника 2.

// Set Alarm 2
if(!rtc.setAlarm2(alarm2Time, DS3231_A2_Minute)) {  // this mode triggers the alarm when the minutes match
  Serial.println("Error, alarm wasn't set!");
}else {
  Serial.println("Alarm 2 will happen at specified time");
}

Это лишь краткий пример, показывающий детали настройки будильников с модулем RTC DS3231. Теперь вы сможете модифицировать этот пример для использования будильников в ваших собственных проектах. Эта функция будильников может быть особенно полезна для пробуждения ESP32 из глубокого сна в назначенное время или для планирования периодических задач, которые должны выполняться в определенное время.

После загрузки кода вы должны увидеть информацию о будильниках в Serial Monitor. Встроенный светодиод ESP32 будет переключаться каждый раз при срабатывании будильника.

ESP32 с модулем RTC DS3231 -- срабатывание будильников в Serial Monitor

Заключение

В этом руководстве вы узнали, как использовать модуль RTC DS3231 с ESP32 для установки и получения времени, настройки будильников и получения показаний температуры.

В следующем руководстве мы покажем, как настроить будильники для пробуждения ESP32 из глубокого сна в определенное время.

Надеемся, что это руководство было для вас полезным. Другие руководства, которые могут быть вам интересны:


Источник: ESP32: Guide for DS3231 Real Time Clock Module (RTC) — Getting Time and Setting Alarms