Módulo de reloj RTC DS3231

Módulo de reloj RTC DS3231

El módulo RTC DS3231 que les presento es uno de varios que resuelve la necesidad de tener un reloj de tiempo real conectado a nuestro Arduino. El RTC (de sus siglas en Inglés “Real Time Clock” o reloj de tiempo real), es un recurso muy útil en algunos proyectos. Generalmente vienen con la opción de ponerles una pila que en mi caso puede ser recargable o no (de litio), y que le permite al módulo mantener la hora aun cuando le desconectemos a nuestro Arduino la energía.

El RTC DS3231 incorpora el chip DS3231 que es uno de los dos más comunes para estas aplicaciones. El otro es el DS1307 y la mayoría de las explicaciónes son válidas para ambos chips.

El módulo RTC DS3231

Nuestro módulo posee varias caracteríasticas (algunas muy asombrosas) de las cuales solo veremos las básicas en esta página, pero prometo armar otra página para explicar el resto. Por ahora nos concentraremos en el reloj, como configurar la hora y como leerla, aunque les dejo un enlace al datasheet (hoja de datos) de nuestro chip aqui.

Módulo DS 3231 visto de arriba  Módulo DS 3231 visto de abajo

Conectando nuestro módulo

Mi versión del RTC DS3231 posee en un extremo un conector a 90 grados con 6 pines y en el otro la opción de soldar otro de 4 pines. Esos 4 pines serán los que conectaremos aunque en mi caso los conecté en los pines que ya tenía para simplificar (los 4 de la derecha en la foto también se encuentran entre los 6 de la izquierda). La conexión a nuestro Arduino debería hacerse asi:

Módulo -> Arduino
GND -> GND
VCC -> 5V
SDA -> A4 (en Arduino UNO)
SCL -> A5 (en Arduino UNO)

Aclaración: si usan MEGA 2560 los pines para SDA y SCL son diferentes (20 y 21 respectivamente) y en otros Arduinos puede variar por lo que deberán consultar la documentación o pueden pregunrme sobre alguno específico si quieren.

El módulo usa I2C

Nuestro módulo se conecta y comunica con nuestro Arduino usando I2C que es un sistema para interconectar dispositivos electronicos y se basa en una comunicación serial (en serie, con datos uno detras del otro). No explicaremos a en profundidad I2C pero debe saber que el sistema de interconexión permite varios dispositivos conectados al mismo tiempo, todos usando los mismos pines, por lo que la manera de diferenciar uno del otro es mediante un valor o dirección que en nuetro módulo es 104 o 0x68 (en hexadecimal).

Para simplificar nuestro trabajo, el proyecto Arduino provee de una librería que ya viene disponible con el Arduino IDE y se llama Wire. Esta librería provee de una interface simple de conexión y uso de dispositivos y módulos que usan I2C.

Pasemos directo al Sketch

El Sketch o programa que les dejo para probar el módulo requiere una librería llamada bcdlib. Si están interesados en la misma, hay una página que explica como hacer librerías y pueden construirla ustedes mismos. La página es esta: http://www.arduinohobby.com/como-crear-una-libreria-arduino/

Y el Sketch es el siguiente:

// Librería para convertir de BCD a decimal y viceversa
#include <bcdlib.h>

// Incluimos la librería del proyecto Arduino para I2C
#include "Wire.h"

// Esta es la dirección de nuestro módulo
#define DS3231_I2C_ADDRESS 0x68

void setup() {
  // Inicializamos el Monitor Serial para nuestras pruebas
  Serial.begin(9600);

  // Inicializamos nuestra librería
  Wire.begin();
  
  // Opcional: configuramos la hora
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  
  Wire.write(0x00); // El primer byte es la dirección en la que escribiremos
  
  // Para nuestro ejemplo usé Junio 8, 2017 a las 18:25:30
  Wire.write(bcdlib::dec2bcd(30)); // Segundos 0-59
  Wire.write(bcdlib::dec2bcd(25)); // Minutos 0-59
  Wire.write(bcdlib::dec2bcd(18)); // Hora 0-23 en formato de 24 horas (aunque soporta formato 12h no lo veremos)
  Wire.write(bcdlib::dec2bcd(5));  // Día de la semana 1-7
  Wire.write(bcdlib::dec2bcd(8));  // Dia 1-31
  Wire.write(bcdlib::dec2bcd(6));  // Mes 1-12
  Wire.write(bcdlib::dec2bcd(17)); // Anio 0-99
  Wire.endTransmission();
}

void loop() {
  int x;
  byte buffer[7];
  
  // Para leer el reloj simplemente iniciamos una transmision y enviamos un 0 solamente
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  
  // Solo leeremos 7 bytes ya que nos alcanza para la fecha y hora
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); 
  
  // Leemos 7 bytes
  for (x=0; x<7; x++) {
    buffer[x] = Wire.read();
  }

  // Mostramos la fecha y hora leida
  Serial.println(String("Fecha (D/M/Y) ") + bcdlib::bcd2dec(buffer[4]) + "/" + bcdlib::bcd2dec(buffer[5])
    + "/20" + bcdlib::bcd2dec(buffer[6]) + ", Hora " + bcdlib::bcd2dec(buffer[2])
    + ":" + bcdlib::bcd2dec(buffer[1]) + ":" + bcdlib::bcd2dec(buffer[0]));
  Serial.println("");
  
  // Leeremos la hora cada 5 segundos
  delay(5000);  
}

En la sección setup() del programa les dejo una manera simple de inicializar la hora que pueden ajustar a sus necesidades. También podrían hacer algo más elaborado que mediante el Monitor Serial permita configurar la hora, pero les dejo esa tarea a ustedes para que jueguen un poco con su módulo.

El truco de la librería bcdlib es que el módulo RTC DS3231  trabaja en BCD, por lo que para configurar la hora debemos convertir todo a BCD antes de enviarlo al módulo, y cuando leemos del mismo, tenemos que convertir de regreso de BCD a decimal.

Llevando el módulo al máximo

Acá les dejo 2 páginas más que les darán más funcionalidades que éste módulo posee y podrán sacarle todo el poder al mismo:

Módulo de reloj RTC DS3231 – Avanzado: incluye manejo de centuria, formato de hora 12/24 y alarmas

Midiendo la temperatura con DS3231 (y extras): incluye medición de temperatura y acceso a la EEPROM de 4Kbytes

13 comentarios en “Módulo de reloj RTC DS3231”

  1. Hola, tengo una duda: Se pueden cambiar las conexiones de los pines A4 y A5 que vienen por defecto en el DS3231 por otros (por ejemplo a los A1 y A2)?? Porque tengo conectado a parte del DS3231, el I2C (que también tiene la misma configuración de los pines por defecto) y a alguno de los dos tengo que cambiarle pero no sé cuál de los dos sea mejor.

    • No se pueden cambiar los pines ya que A4 y A5 con los pines del Arduino UNO para I2C. Sin embargo, podes conectar 2 o más dispositivos a los mismos pines siempre que se comuniquen en direcciones diferentes. Por ejemplo: no podrias conectar 2 módulos DS3231, pero si podrias conectar un DS3231 y un acelerómetro.

  2. Hola,

    Cuando utilizo tu codigo me sale lo siguiente:

    Fecha (D/M/Y) 165/165/20165, Hora 165:165:165
    Fecha (D/M/Y) 165/165/20165, Hora 165:165:165
    Fecha (D/M/Y) 165/165/20165, Hora 165:165:165

    Alguna idea de ue puede estar pasando?

    Gracias.

    Esteban A.

    • Si te fijas el hecho de que siempre sea el numero 165 te da una pista de que el valor leido no es valido. Probaste con otro módulo para descartar que esté malo el módulo que usaste?

      • Hola Roger. Los códigos no simplemente funcionan por un rato y luego no… los módulos si hacen eso. El código funciona o no funciona. Si funciona, y luego de un rato deja de funcionar es muy posible que sea el módulo y no el código el que deja de funcionar (o tu Arduino). Deberás agregar código de prueba para verificar que pasa. Por ejemplo, comandos que puedas ejecutar por monitor serie, y verificar la integridad de tu Arduino, la comunicacion con el módulo, etc. También sirve si por ejemplo reseteas el módulo, quitándole la energía y luego conectandolo de nuevo, sin desconectar el Arduino. Eso te dirá si el módulo se desconectó o que ocurrió. El I2C es un puerto muy estable y confiable, pero a altas velocidades no se comporta muy bien, puedes verificar eso tambien. La energía de los módulos debe ser lo más estable posible, si estan usando los módulos sin baterías eso es un riesgo. Les sugiero siempre usarlos con una bateria de litio. Intentaré replicar el problema que comentan en mi laboratorio para ver si puedo explicar las condiciones en las que este problema ocurre. Gracias por compartirlo aquí!

  3. hola buenas
    Podrias ayudarme porfavor, nose como ajustar la hora. Ya que tengo un programa para imprimir “x” cosa pero la hora me sale una hora atrasada con respecto a mi pais.
    Como deberia proceder, muchas gracias de antemano.

    • Para configurar la hora solo sigue el ejemplo. La parte que hace eso es la que dice:


      // Opcional: configuramos la hora
      Wire.beginTransmission(DS3231_I2C_ADDRESS);

      Wire.write(0x00); // El primer byte es la dirección en la que escribiremos

      // Para nuestro ejemplo usé Junio 8, 2017 a las 18:25:30
      Wire.write(bcdlib::dec2bcd(30)); // Segundos 0-59
      Wire.write(bcdlib::dec2bcd(25)); // Minutos 0-59
      Wire.write(bcdlib::dec2bcd(18)); // Hora 0-23 en formato de 24 horas (aunque soporta formato 12h no lo veremos)
      Wire.write(bcdlib::dec2bcd(5)); // Día de la semana 1-7
      Wire.write(bcdlib::dec2bcd(8)); // Dia 1-31
      Wire.write(bcdlib::dec2bcd(6)); // Mes 1-12
      Wire.write(bcdlib::dec2bcd(17)); // Anio 0-99
      Wire.endTransmission();

    • Hola Andres. Los modulos I2C (como el de este reloj) pueden conectarse todos en un BUS o linea de comunicación. En ella puede haber más de un Arduino y más de un módulo. En general los módulos estan preparados para contestar cuando se les habla en una dirección específica (0x68 hexa en este caso) y solo responde en ese caso. Por lo tanto la respuesta corta es que si puedes hacerlo. Todo debe ir conectado en paralelo por lo que los dos Arduino también estarán conectados por I2C y tal vez puedas aprovechar esa conexión para comunicarlos entre sí de necesitarlo. Espero te sirva la respuesta y gracias por visitarnos!

Deja un comentario