Skip to Content

Reloj en Tiempo Real DS3231 con ESP32

Reloj en Tiempo Real DS3231 con ESP32

En este tutorial aprenderás cómo usar un módulo de reloj en tiempo real (RTC) DS3231 con un ESP32.

Un módulo RTC es un reloj externo que mantiene el seguimiento de la hora y fecha actuales. Funciona de forma independiente a la alimentación principal del sistema, permitiendo mantener la hora precisa incluso cuando la energía está apagada.

Te mostraré cómo usar un RTC en combinación con el ESP32 en modo deep-sleep, cómo ajustar el RTC para el horario de verano y cómo sincronizar el RTC con un servidor de tiempo por internet.

Partes necesarias

Para este proyecto necesitarás un módulo RTC DS3231 y un ESP32. Yo uso el ES32 lite como microprocesador, ya que tiene una interfaz de carga de batería que permite alimentar el ESP32 y el RTC con una batería LiPo. Sin embargo, cualquier otro ESP32 o ESP8266 también funcionará. Para mostrar la hora, elegí un OLED, pero también podrías usar un LCD display.

ESP32 lite Lolin32

ESP32 lite

USB data cable

Cable USB de datos

Módulo RTC DS3231

Dupont wire set

Juego de cables Dupont

Half_breadboard56a

Protoboard

OLED display

Pantalla OLED

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Conceptos básicos del chip DS3231

El DS3231 es un chip pequeño (38 x 22 x 14 mm) con un reloj en tiempo real (RTC) de alta precisión y un oscilador de cristal compensado por temperatura integrado. Este chip incluye un soporte para batería, lo que le permite funcionar incluso cuando la fuente de alimentación principal está desconectada.

DS3231 Chip
Chip DS3231

El RTC mantiene el seguimiento de segundos, minutos, horas, día de la semana, fecha, mes y año. Para meses con menos de 31 días, la fecha se ajusta automáticamente, incluyendo correcciones para años bisiestos. El reloj puede operar en formato de 24 o 12 horas. Proporciona dos alarmas de calendario programables y una salida de onda cuadrada programable. La comunicación es vía bus I2C.

Una referencia de voltaje de precisión compensada por temperatura y un circuito comparador monitorean el estado de VCC, detectan fallos de energía, proporcionan una salida de reset y cambian automáticamente a la fuente de alimentación de respaldo cuando es necesario. El dispositivo integra un sensor de temperatura digital accesible vía interfaz I2C.

La siguiente sección lista las principales características del DS3231 (source):

Especificaciones técnicas

  • Voltaje de operación: 3.3–5.5V
  • Chip de reloj: Chip de reloj de alta precisión DS3231
  • Precisión del reloj: 2ppm en el rango de 0-40°C, error anual aproximadamente 1 minuto
  • Dos alarmas de calendario
  • Salida de onda cuadrada programable
  • El reloj en tiempo real genera segundos, minutos, horas, día de la semana, fecha, mes y año, con compensación para años bisiestos válida hasta 2100
  • Sensor de temperatura incorporado con una precisión de ±3°C
  • Chip de almacenamiento: AT24C32 (capacidad de almacenamiento de 32K)
  • Interfaz de bus IIC, velocidad máxima de transmisión 400KHz (cuando el voltaje de operación es 5V)
  • Puede conectarse en cascada con otros dispositivos IIC, la dirección 24C32 puede modificarse puenteando A0/A1/A2, la dirección por defecto es 0x57
  • Usa batería CR2032 para asegurar que el reloj siga funcionando normalmente tras un corte de energía

Diagrama de bloques del DS3231

El siguiente diagrama de bloques muestra los componentes internos del DS3231. Puedes ver el oscilador de cristal, el sensor de temperatura, el control de energía y la interfaz I2C.

Block Diagram of DS3231 Chip
Diagrama de bloques del chip DS3231

Los pines del DS3231 son los siguientes: VCC y GND para la alimentación general y VBAT para la batería de respaldo. SCL y SDA son para la interfaz I2C.

El pin etiquetado «33kHz» emite la señal de reloj de 32kHz. INT/SQW es un pin de interrupción que puede usarse para señalar alarmas o como salida de onda cuadrada programable.

RST es el pin de reset que puede usarse para indicar al microprocesador conectado que la energía se perdió o se restauró. Los pines «33kHz», INT/SQW y RST tienen otras funciones también. Para más detalles consulta la hoja de datos enlazada abajo:

Conceptos básicos del módulo RTC DS3231

El chip DS3231 es demasiado pequeño para conectarse directamente a un ESP32 y además le faltan algunos componentes necesarios. Por eso normalmente se usa un módulo RTC DS3231. El módulo incluye los componentes faltantes y también un soporte para una CR2032 batería que proporciona la alimentación de respaldo. La imagen abajo muestra el frente y la parte trasera de un módulo típico DS3231 RTC:


Front and back of DS3231 RTC Module
Frontal y trasera del módulo RTC DS3231

En lugar de una CR2032 batería también puedes usar una batería recargable LIR2032 pero debes tener cuidado con el voltaje de alimentación. Más sobre esto más adelante.

Pinout del módulo RTC DS3231

El pinout de un módulo RTC DS3231 es esencialmente el mismo que el descrito para el chip DS3231.

Pinout of DS3231 RTC Module
Pinout del módulo RTC DS3231

VCC y GND son para la alimentación, con un voltaje de suministro de 3.3–5.5V. SCL y SDA son los pines para la interfaz I2C (con resistencias pull-up integradas de 4.7k). Los pines 32K y SQW son salidas para la señal de reloj de 32kHz y la señal de onda cuadrada programable, pero no los necesitarás aquí.

La dirección I2C del módulo RTC DS3231 es configurable mediante tres pads de soldadura (A0, A1, A2) que pueden puentease. Mira la sección resaltada en la esquina inferior derecha del módulo en la imagen anterior. La dirección I2C por defecto es 0x57, cuando no hay puentes. La imagen abajo muestra todas las configuraciones posibles y las direcciones I2C correspondientes.

Setting I2C address of the DS3231 RTC Module
Configuración de la dirección I2C del módulo RTC DS3231 (source)

Carga de batería con el módulo RTC DS3231

El módulo RTC DS3231 permite cargar la batería de respaldo desde la fuente de alimentación principal (VCC). La imagen abajo muestra el diagrama del circuito del módulo RTC DS3231. En la sección marcada en amarillo, ves una resistencia de 200Ω y un diodo 1N4148 que actúan como un circuito de carga muy simple.

Schematic  of DS3231 RTC Module
Esquema del módulo RTC DS3231

Sin embargo, debes desactivar este circuito de carga cuando uses una batería CR2032 no recargable con un voltaje de suministro VCC de 5V. Y si usas una batería recargable LIR2032, VCC nunca debe superar los 4.7 voltios para una carga segura.

El Battery charging circuit of DS3231 module artículo describe los problemas del circuito de carga con más detalle y también muestra cómo desactivarlo. La siguiente tabla del artículo lista los diferentes escenarios con distintos voltajes de suministro y tipos de batería, y qué se debe hacer:

Tipo de bateríaSuministro 3.3 VSuministro 5 V
CR2032Batería no afectadaDesactivar circuito de carga
LIR2032Batería no afectada
La carga no funciona
Desactivar circuito de carga, o
Asegurarse de que 5 V sean realmente 4.7 V

Conexión del módulo RTC DS3231 al ESP32 lite

Conectar el módulo RTC DS3231 a un ES32 es sencillo. Primero conecta SCL del DS3231 al pin 23 del ESP32. Luego conecta SDA al pin 19 del ESP32. Finalmente, conecta tierra a GND y 3.3V a VCC como se muestra abajo:

Connecting DS3231 RTC Module to ESP32 lite
Conexión del módulo RTC DS3231 al ESP32 lite

Como estamos alimentando el módulo RTC DS3231 con 3.3V, puedes tener una batería CR2032 insertada mientras está conectado a la fuente de alimentación.

Código de prueba simple para el módulo RTC DS3231

Necesitarás una librería de software para comunicarte con el módulo RTC DS3231. Hay varias, pero me gusta más la Arduino-DS3231 de Korneliusz Jarzębski. Para instalarla, ve a github repo y haz clic en el botón verde «Code». Luego selecciona «Download Zip» en el menú como se muestra abajo:

Download ZIP file for Arduino-DS3231library
Descargar archivo ZIP para la librería Arduino-DS3231

Esto descargará un archivo llamado «Arduino-DS3231-dev.zip» a tu ordenador. Para instalar esta librería ZIP sigue los pasos habituales. Haz clic en Sketch -> Add .ZIP Library y luego selecciona el archivo Arduino-DS3231-dev.zip que acabas de descargar.

Installing a .ZIP Arduino library
Instalación de una librería Arduino .ZIP

Con la librería instalada, podemos probar la función del módulo RTC DS3231. El siguiente código simple establece la hora y fecha en el módulo RTC al momento de compilación del sketch y luego imprime la hora y fecha en un bucle:

#include "Wire.h"
#include "DS3231.h"

DS3231 rtc;

void setup() {
  Serial.begin(9600);
  rtc.begin();
  rtc.setDateTime(__DATE__, __TIME__);
}

void loop() {
  RTCDateTime  dt = rtc.getDateTime();
  Serial.printf("%4d-%02d-%02d %02d:%02d:%02d\n",
                dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
  delay(1000);
}

El código comienza incluyendo la librería Wire.h para comunicación I2C y la librería DS3231.h para comunicarse con el RTC DS3231.

Luego, creamos una instancia de la clase DS3231. En la función setup() inicializamos el RTC y establecemos la fecha y hora actuales usando rtc.setDateTime(). Las macros __DATE__ y __TIME__ insertan automáticamente la fecha y hora en que se compiló el sketch. Ten en cuenta que la hora no será actual cuando el ESP32 se reinicie después de compilar y subir el código, pero eso lo manejaremos más adelante.

En la función loop, recuperamos la fecha y hora actuales del RTC usando RTCDateTime dt = rtc.getDateTime() y usamos printf para imprimir la fecha y hora en el Monitor Serial.

Ejemplo de salida

Si subes el código y abres el Monitor Serial, deberías ver la fecha y hora impresas así:

Fecha y hora del RTC impresas en el Monitor Serial

Horario de verano con el módulo RTC DS3231

Aunque el DS3231 mantiene un seguimiento preciso de la fecha y hora, no ajusta el horario de verano (DST). Esto significa que el DS3231 mostrará la hora (y fecha) incorrecta cuando tu país cambie a DST o vuelva al horario estándar (ST).

Hay esencialmente dos formas de manejar esto. 1) podrías añadir un botón que cambie manualmente entre DST y ST y viceversa. Esto obviamente no es óptimo. 2) añadir código que realice el cambio automáticamente para la zona horaria de tu país.

En esta sección, te muestro cómo manejar automáticamente el horario de verano usando el módulo RTC DS3231. Usaremos la librería ezTime Library para esto. Puedes instalarla vía Library Manager como de costumbre:

Install ezTime Library via Library Manager
Instalar la librería ezTime vía Library Manager

Una vez instalada, puedes usarla para ajustar el RTC DS3231 al horario de verano con el siguiente código:

#include "Wire.h"
#include "DS3231.h"
#include "ezTime.h"

const char* TIMEZONE = "AEST-10AEDT,M10.1.0,M4.1.0/3";  // Melbourne

Timezone loc;
DS3231 rtc;

void setup() {
  Serial.begin(9600);
  rtc.begin();
  rtc.setDateTime(2024,12,4,3,16,30);  // UTC
  loc.setPosix(TIMEZONE);
}

void loop() {
  RTCDateTime dt = rtc.getDateTime();
  UTC.setTime(dt.hour, dt.minute, dt.second, dt.day, dt.month, dt.year);

  Serial.printf("RTC: %4d-%02d-%02d %02d:%02d:%02d\n",
                dt.year, dt.month, dt.day, 
                dt.hour, dt.minute, dt.second);

  Serial.printf("LOC: %4d-%02d-%02d %02d:%02d:%02d\n",
                loc.year(), loc.month(), loc.day(), 
                loc.hour(), loc.minute(), loc.second());                
               
  Serial.println();

  delay(5000);
}

En el código anterior, conectamos un ESP32 con un módulo RTC DS3231 para mantener la hora actual, incluyendo ajustes para el horario de verano. El programa inicializa el RTC, establece una fecha y hora específicas, y luego recupera y muestra continuamente la hora UTC y local cada 5 segundos.

Vamos a desglosar el código en sus componentes para entenderlo mejor.

Librerías incluidas

Comenzamos incluyendo las librerías necesarias para nuestro proyecto. La librería Wire.h se usa para comunicación I2C, que es como el ESP32 se comunica con el RTC DS3231. La librería DS3231.h proporciona funciones específicas para interactuar con el módulo DS3231, y ezTime.h se usa para manejar zonas horarias y ajustes de horario de verano.

#include "Wire.h"
#include "DS3231.h"
#include "ezTime.h"

Constantes y variables

Luego definimos una constante para la zona horaria. En este caso usamos AEST-10AEDT,M10.1.0,M4.1.0/3, que corresponde a Melbourne, Australia. Esta cadena indica el desfase horario estándar y las reglas para el horario de verano.

const char* TIMEZONE = "AEST-10AEDT,M10.1.0,M4.1.0/3";  // Melbourne

Las partes de esta definición de zona horaria son las siguientes

  • AEST: Hora estándar del este de Australia
  • -10: Desfase UTC de 10 horas adelantado respecto al Tiempo Universal Coordinado (UTC)
  • AEDT: Hora de verano del este de Australia
  • M10.1.0: La transición al horario de verano ocurre el primer domingo de octubre
  • M4.1.0/3: La transición de vuelta al horario estándar ocurre el primer domingo de abril, con una diferencia de 3 horas respecto a UTC.

Para otras definiciones de zona horaria, consulta el Posix Timezones Database. Solo copia la cadena que encuentres allí y cambia la constante TIMEZONE en consecuencia.

También creamos instancias de las clases Timezone y DS3231. La variable loc contendrá la información de la hora local, mientras que rtc gestionará el módulo RTC.

Timezone loc;
DS3231 rtc;

Función setup

En la función setup() inicializamos la comunicación serial a 9600 baudios para depuración. Luego inicializamos el RTC y lo configuramos a una fecha y hora específicas (4 de diciembre de 2024, 03:16:30 UTC). Finalmente, establecemos la zona horaria usando la constante definida anteriormente.

void setup() {
  Serial.begin(9600);
  rtc.begin();
  rtc.setDateTime(2024,12,4,3,16,30);  // UTC
  loc.setPosix(TIMEZONE);
}

Función loop

La función loop() se ejecuta continuamente. Primero, recuperamos la fecha y hora actuales del RTC usando rtc.getDateTime(). Luego establecemos la hora UTC usando los valores recuperados.

  RTCDateTime dt = rtc.getDateTime();
  UTC.setTime(dt.hour, dt.minute, dt.second, dt.day, dt.month, dt.year);

A continuación, imprimimos la hora UTC actual en el monitor serial en una cadena formateada. Esto incluye año, mes, día, hora, minuto y segundo.

  Serial.printf("RTC: %4d-%02d-%02d %02d:%02d:%02d\n",
                dt.year, dt.month, dt.day, 
                dt.hour, dt.minute, dt.second);

También imprimimos la hora local usando la variable loc, que ha sido ajustada para la zona horaria y el horario de verano.

  Serial.printf("LOC: %4d-%02d-%02d %02d:%02d:%02d\n",
                loc.year(), loc.month(), loc.day(), 
                loc.hour(), loc.minute(), loc.second());                

Finalmente, añadimos un salto de línea para mejor legibilidad en la salida serial e introducimos un retardo de 5000 milisegundos (5 segundos) antes de que el bucle se repita.

  Serial.println();
  delay(5000);

Ejemplo de salida

Si subes el código y abres el Monitor Serial, deberías ver la hora UTC del RTC y la hora local (LOC) impresas:

UTC and local time of RTC on Serial Monitor
Hora UTC y local del RTC en el Monitor Serial

Sincronizar el RTC DS3231 con un servidor SNTP

Aunque el código anterior ahora maneja automáticamente el ajuste para el horario de verano, aún requiere que configures manualmente la hora del RTC al iniciar el ESP32. Peor aún, requiere que conectes el ESP32 a un ordenador, cambies el código y reprogrames el ESP32. ¡Esto es molesto!

Podrías añadir botones para editar la hora y fecha mientras el ESP32 está en funcionamiento. Si quieres hacer eso, echa un vistazo al tutorial Arduino and RTC Module DS3231, donde usamos dos botones para configurar la hora.

La mejor opción, sin embargo, es sincronizar automáticamente el RTC con un proveedor de tiempo por Internet (SNTP). Para más información, consulta el tutorial How to synchronize ESP32 clock with SNTP server.

Si tienes acceso constante a internet y no te importa el consumo de energía, no necesitarías un RTC, ya que puedes sincronizar regularmente el reloj interno del ESP32. Esto ajustaría automáticamente el reloj y también manejaría el horario de verano. Consulta los tutoriales Automatic Daylight Savings Time Clock y Digital Clock on e-Paper Display.

Sin embargo, para un proyecto alimentado por batería quieres evitar usar WiFi con demasiada frecuencia, ya que consume mucha energía. Un caso común es un registrador de datos, por ejemplo para temperatura, que quieres que funcione con batería el mayor tiempo posible pero que también necesite marcas de tiempo precisas.

El siguiente código te muestra cómo hacer esto. Usa WiFi solo cuando el ESP32 se reinicia para sincronizar el RTC. De lo contrario, el ESP32 está en modo deep-sleep para conservar energía y solo se despierta ocasionalmente para obtener la hora del RTC e imprimirla:

#include "WiFi.h"
#include "esp_sntp.h"
#include "Wire.h"
#include "DS3231.h"
#include "ezTime.h"

const char* TIMEZONE = "AEST-10AEDT,M10.1.0,M4.1.0/3";  // Melbourne
const char* SSID = "SSID";
const char* PWD = "PASSWORD";
const int SLEEP = 10; // sec
 
DS3231 rtc; 
Timezone loc;

void syncTime() {
  WiFi.begin(SSID, PWD);
  while (WiFi.status() != WL_CONNECTED)
    ;
  configTzTime("UTC", "pool.ntp.org");
  setRtcTime();
}

void setRtcTime() {
  struct tm t;
  getLocalTime(&t);
  rtc.setDateTime(t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
}

void printTime() {
  RTCDateTime dt = rtc.getDateTime();
  UTC.setTime(dt.hour, dt.minute, dt.second, dt.day, dt.month, dt.year);

  Serial.printf("RTC: %4d-%02d-%02d %02d:%02d:%02d\n",
                dt.year, dt.month, dt.day, 
                dt.hour, dt.minute, dt.second);

  Serial.printf("LOC: %4d-%02d-%02d %02d:%02d:%02d\n",
                loc.year(), loc.month(), loc.day(), 
                loc.hour(), loc.minute(), loc.second());                
               
  Serial.println();

}

bool isReset() {
  return esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TIMER;
}

void setup() {
  Serial.begin(9600);
  rtc.begin();
  loc.setPosix(TIMEZONE);

  if (isReset()) {
    syncTime();
  }   
  printTime();

  esp_sleep_enable_timer_wakeup(SLEEP * 1000000);                
  esp_deep_sleep_start();
}

void loop() {
}

Vamos a desglosar el código en sus componentes para entenderlo mejor.

Librerías y constantes

Comenzamos incluyendo las librerías necesarias para Wi-Fi, SNTP (Protocolo simple de tiempo en red), comunicación I2C y el RTC DS3231. También definimos algunas constantes para la zona horaria, credenciales Wi-Fi y duración del sueño.

#include "WiFi.h"
#include "esp_sntp.h"
#include "Wire.h"
#include "DS3231.h"
#include "ezTime.h"

const char* TIMEZONE = "AEST-10AEDT,M10.1.0,M4.1.0/3";  // Melbourne
const char* SSID = "SSID";
const char* PWD = "PASSWORD";
const int SLEEP = 10; // sec

Obviamente, tendrás que reemplazar las credenciales Wi-Fi por las tuyas propias.

Objetos RTC y zona horaria

Creamos instancias de la clase DS3231 para el RTC y la clase Timezone para manejar los cálculos de hora local.

DS3231 rtc; 
Timezone loc;

Función de sincronización de hora

La función syncTime() conecta a la red WiFi y configura la zona horaria para el servidor NTP. Luego llama a setRtcTime() para actualizar el RTC con la hora actual.

void syncTime() {
  WiFi.begin(SSID, PWD);
  while (WiFi.status() != WL_CONNECTED)
    ;
  configTzTime("UTC", "pool.ntp.org");
  setRtcTime();
}

Función para establecer la hora del RTC

En la función setRtcTime(), recuperamos la hora local y configuramos la fecha y hora del RTC en consecuencia. El año se ajusta sumando 1900 porque el campo tm_year devuelve el número de años desde 1900.

void setRtcTime() {
  struct tm t;
  getLocalTime(&t);
  rtc.setDateTime(t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
}

Ten en cuenta que también tenemos que sumar 1 a tm_mon para obtener el mes correcto, ya que la estructura de datos struct tm usa rangos inconsistentes. Por ejemplo, el día del mes comienza en 1 pero el mes del año comienza en 0:

  Member    Type  Meaning                   Range
  tm_sec    int   seconds after the minute  0-61*
  tm_min    int   minutes after the hour    0-59
  tm_hour   int   hours since midnight      0-23
  tm_mday   int   day of the month          1-31
  tm_mon    int   months since January      0-11
  tm_year   int   years since 1900
  tm_wday   int   days since Sunday         0-6
  tm_yday   int   days since January 1      0-365
  tm_isdst  int   Daylight Saving Time flag

Función para imprimir la hora

La función printTime() recupera la fecha y hora actuales del RTC y las imprime en el Monitor Serial. También imprime la hora local usando el objeto de zona horaria.

void printTime() {
  RTCDateTime dt = rtc.getDateTime();
  UTC.setTime(dt.hour, dt.minute, dt.second, dt.day, dt.month, dt.year);

  Serial.printf("RTC: %4d-%02d-%02d %02d:%02d:%02d\n",
                dt.year, dt.month, dt.day, 
                dt.hour, dt.minute, dt.second);

  Serial.printf("LOC: %4d-%02d-%02d %02d:%02d:%02d\n",
                loc.year(), loc.month(), loc.day(), 
                loc.hour(), loc.minute(), loc.second());                

  Serial.println();
}

Función para comprobar el reinicio

La función isReset() comprueba si el ESP32 se despertó del deep sleep por un temporizador u otra causa. Esto ayuda a determinar si se debe sincronizar la hora o no.

bool isReset() {
  return esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TIMER;
}

Función setup

En la función setup() inicializamos la comunicación serial, el RTC y establecemos la zona horaria. Si el ESP32 está arrancando desde cero (no despertando del deep sleep), sincronizamos la hora. Finalmente, imprimimos la hora y ponemos el ESP32 en modo deep sleep por la duración especificada.

void setup() {
  Serial.begin(9600);
  rtc.begin();
  loc.setPosix(TIMEZONE);

  if (isReset()) {
    syncTime();
  }   
  printTime();

  esp_sleep_enable_timer_wakeup(SLEEP * 1000000);                
  esp_deep_sleep_start();
}

Función loop

La función loop() está vacía porque el ESP32 no ejecutará código mientras esté en deep sleep. Solo se despertará para ejecutar la función setup() nuevamente tras la duración del sueño.

void loop() { }

Mostrar la hora del RTC en OLED

Como ejemplo final, quiero mostrarte cómo añadir un OLED para mostrar la hora y fecha del RTC en una pantalla. Esto es solo una extensión simple del código anterior.

Conectar el OLED es fácil, ya que también es un dispositivo I2C. Simplemente conecta SDA, SCL, VCC y GND del OLED en paralelo con el DS3231 como se muestra abajo

Connecting OLED and DS3231 to ESP32 lite
Conexión de OLED y DS3231 al ESP32 lite

Abajo está el código que muestra la hora y fecha en el OLED. Ten en cuenta que usa la librería Adafruit_SSD1306, que puedes instalar vía Library Manager como de costumbre.

#include "WiFi.h"
#include "esp_sntp.h"
#include "Wire.h"
#include "DS3231.h"
#include "ezTime.h"
#include "Adafruit_SSD1306.h"

const char* TIMEZONE = "AEST-10AEDT,M10.1.0,M4.1.0/3";
const char* SSID = "SSID";
const char* PWD = "PASSWORD";
const int SLEEP = 10; // sec
 
DS3231 rtc; 
Timezone loc;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

void syncTime() {
  WiFi.begin(SSID, PWD);
  while (WiFi.status() != WL_CONNECTED)
    ;
  configTime(0, 0, "pool.ntp.org");
  setRtcTime();
}

void setRtcTime() {
  struct tm t;
  getLocalTime(&t);
  rtc.setDateTime(t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
}

void displayTime() {
  RTCDateTime dt = rtc.getDateTime();
  UTC.setTime(dt.hour, dt.minute, dt.second, dt.day, dt.month, dt.year);
  oled.clearDisplay();
  oled.setCursor(10, 15);
  oled.println(loc.dateTime("H:i:s"));  
  oled.setCursor(2, 45);
  oled.println(loc.dateTime("d/m/Y"));  
  oled.display();
}

bool isReset() {
  return esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TIMER;
}

void setup() {
  rtc.begin();
  loc.setPosix(TIMEZONE);
  oled_init();

  if (isReset()) {
    syncTime();
  }   
  displayTime();

  esp_sleep_enable_timer_wakeup(SLEEP * 1000000);                
  esp_deep_sleep_start();
}

void loop() {
}

Las únicas adiciones y cambios al código son la función oled_init(), que inicializa el OLED, y la función displayTime(), que muestra la hora y fecha en el OLED. Si subes el código a tu ESP32 deberías ver lo siguiente en el OLED:

Time and date displayed on OLED
Hora y fecha mostradas en OLED

¡Y eso es todo! Ahora deberías poder usar el RTC DS3231 junto con un ESP32.

Conclusiones

En este tutorial aprendiste cómo usar un módulo de reloj en tiempo real (RTC) DS3231 con un ESP32.

El ESP32 lite con un reloj en tiempo real es especialmente adecuado para proyectos alimentados por batería que necesitan mantener la hora precisa sin consumir mucha energía. Usos comunes son data loggers o relojes electrónicos. Para estos últimos, recomiendo pantallas e-Paper, ya que consumen casi nada de energía. Consulta nuestros tutoriales, Analog Clock on e-Paper Display y Digital Clock on e-Paper Display.

Si quieres aprender un poco más sobre relojes con diferentes tipos de pantalla y sincronización de tiempo, echa un vistazo al Digital Clock on e-Paper Display,

Si tienes alguna pregunta, no dudes en dejarla en la sección de comentarios.

¡Feliz bricolaje ; )