El módulo DS3231, un reloj para Arduino

37
7739
El módulo DS3231 permitirá que podamos llevar un registro detallado del transcurso del tiempo en nuestro microcontrolador. Los proyectos que podemos llevar a cabo con este módulo van desde estaciones de sensores hasta alarmas y sondas de registro de datos.

En múltiples ocasiones vamos a necesitar que nuestros proyectos lleven un conteo estricto sobre el tiempo transcurrido. Esto es imposible de conseguir con nuestro Arduino debido a que el mismo no está capacitado para ello. Necesitamos un circuito que sea capaz de mantener el conteo del tiempo aún cuando el microcontrolador esté apagado.

Afortunadamente existe el módulo DS3231.

Este módulo incluye un circuito integrado, el DS3231, además de un regulador de tensión, una batería de 3.6 voltios (de las que se encuentran en los motherboard de las computadoras), entre otras cosas (es capaz de medir temperatura).

Se comunica con Arduino utilizando el protocolo I2C, por lo que encontraremos los pines VCC, GND, SCL y SDA.

DS3231_front

 

DS3231_back

 

Buscando por Internet me he encontrado con una librería muy útil para comunicarse con este dispositivo. Ha sido desarrollada por alguien que tiene un blog llamado Hardware Hacks.

La librería la podemos encontrar en el siguiente enlace.

DS3231

Una vez se ha descargado e instalado la librería podemos proceder a probar nuestro módulo. Como siempre, cada vez que se vaya a utilizar la interfaz I2C los pines A4 y A5 deben ser reservados para conectar el SDA y SCL, respectivamente.

Las conexiones con Arduino se deben realizar de la siguiente manera.

DS3231

 

Con las conexiones hechas, se procede a la configuración inicial del módulo. Es necesario llevar a cabo un proceso de asignación de fecha y hora. Esta información será almacenada en el circuito integrado y se mantendrá en el tiempo gracias a la pila con la que cuenta el dispositivo.

El código para setear la hora es el siguiente:

 

No estoy considerando el día de la semana ya que no me parece relevante. Esta librería me ha dado problemas cuando la seteo en 24 horas debido a que luego de las 15 horas regresa a 10. Supongo que algo tiene que ver con los 5 bits que requeriría ir mas allá del 16. En fin, utilizándola en 12 horas trabaja muy bien.

La hora que he establecido en este ejemplo es las 8:11 PM, del 22 de mayo de 2014.

Ahora les presentaré el código que se utiliza para rescatar la hora de nuestro dispositivo.

 

El resultado que se obtiene debe ser similar a lo que se muestra a continuación.

monitor serial

 

La librería cuenta con algunas otras opciones interesantes como alarmas y funciones de oscilador. Dentro del paquete se pueden encontrar algunos ejemplos.

Espero que la información suministrada sea de utilidad para todos y todas. Saludos.

 

 

  • Antony García González

    No debe haber problemas

  • M. J. Beltrán

    Perdona mi ignorancia pero son dos códigos distintos?
    O un código con los dos programas uno detrás de otro?

    • Antony García González

      Hay un código para setear la hora y el otro es para poner un ejemplo en funcionamiento

  • Antony García González

    Estas haciendo algo mal. O la batería de tu módulo está muerta

  • Alberto B

    Buenas noches monte el programa y cuando lo subo da la hora pero me la cambia se mantiene si tengo conectado el pin vin del arduino al pin de sqw del ds3231y al desconectarlo se desconfigura ya que vuelve a la hora inicial que hago este es: como hago para mantener la hora cuando no haya suministro de energia.
    #include
    #include
    #include
    // el rtc se conecta a 3.3v con scl-A5 y sda en A4-el tm1637 se conecta a 5.v
    #include
    #include
    #include

    #define CLK 6
    #define DIO 7

    TM1637Display display(CLK, DIO);
    DS3231 Clock;
    bool h12, PM;
    byte year, month, date, DoW, hour, minute, second;

    void setup() {
    display.setBrightness(0x0f);
    Wire.begin();
    // Se inicial la interfaz I2c
    Wire.begin();
    // Se inicia la Comunicación Serial
    Serial.begin(9600);
    //Se establece el modo horario en 12 horas (false = 24h)
    Clock.setClockMode(true);
    //Se establece el año
    Clock.setYear((byte)(17));
    //Mes
    Clock.setMonth((byte)03);
    //Dia de la semana (no lo estoy considerando)
    //Clock.setDoW((byte)dia);
    //Día
    Clock.setDate((byte)9);
    //Hora
    Clock.setHour((byte)6);
    //Minutos
    Clock.setMinute((byte)44);
    //Segundos
    Clock.setSecond((byte)0);

    }

    void ReadDS3231()
    {
    int second,minute,hour;
    uint8_t segto;
    second=Clock.getSecond();
    minute=Clock.getMinute();
    hour=Clock.getHour(h12, PM);
    display.showNumberDec(hour*100+minute, true);
    delay(500);
    segto = 0x80 | display.encodeDigit(hour%10);
    display.setSegments(&segto, 1, 1);
    delay(500);
    }

    void loop() {
    ReadDS3231();
    delay(1000);
    //Se rescata la información
    Clock.getTime(year, month, date, DoW, hour, minute, second);
    //Se imprime
    Serial.print(date, DEC);
    Serial.print(“/”);
    Serial.print(month, DEC);
    Serial.print(“/”);
    Serial.print(year, DEC);
    Serial.print(” “);
    Serial.print(hour, DEC);
    Serial.print(“:”);
    Serial.print(minute, DEC);
    Serial.print(“:”);
    Serial.println(second, DEC);
    }

    • Antony García González

      Verifica la pila del módulo

  • Charles

    Muchísimas gracias. Me la he pasado leyendo diferentes explicaciones y todas las que encontré resultan ser muy complicadas. Tu explicación es fácil y práctica, y sobretodo te permite utilizar la información del reloj para que el microcontrolador efectúe tareas a horas específicas.

    • Antony García González

      Gracias amigo por tus comentarios

  • hiddenotebook rules

    Hola lo primero agradezco la explicación gracias por el gran trabajo.

    Mi problema es que cuando los segundos cambian de 60 a 1 me lo imprime por un lcd i2c mal osea imprime un 1 y un carácter extraño.

    • Antony García González

      Verifica con el Serial el dato que se está enviando al LCD para ver qué debería imprimir

  • Paco Jesus L

    Hola, oye como puedo imprimir en el LCD, por que intente utilizar el siguiente formato, pero me marca error.
    lcd.write(minute, DEC);

    me dice que minute no puede ser utilizada como función.

    • Paco Jesus L

      Para solucionar el problema coloqué:
      lcd.write(“”);
      lcd.write(minute,DEC);
      lcd.write(“:);

      etc… etc…

      y con la primera linea se soluciona el problema.
      GRACIAS.

      • Antony García González

        Gracias por el aporte amigo

  • Antony García González

    Verifica las conexiones

  • Antony García González

    Verifica las conexiones del sensor

  • Jesus Zanelli

    al momento de imprimir/mostrar la fecha hay que hacer que se muestre de esa forma.

  • Danni Gallegos

    Disculpa, muy buena informacion la verdad, no sabia muy bien el funcionamiento de arduino hasta que me encontré con esta tu pagina.
    podrias ayudarme? necesito que enciende un led (que representa un foco) cuando
    8am=<tiempo<=1pm AND 4pm <= tiempo =< 7pm …..encerio seria de mucha ayuda porfavor, no conosco el lenguaje :s

    • Antony García González

      Lee la hora y usa un IF

  • Juan Carlos Irigoyen

    El error que se produce para leer en modo 24 horas se debe a un bug en dicha función de la librería.
    Solo hay que cambiar la línea incorrecta
    tempBuffer = bcdToDec(Wire.read());
    por la correcta
    tempBuffer = Wire.read();

    Dejo aquí la función corregida completa, que hay que cambiar en el archivo DS3231.cpp

    void DS3231::getTime(byte& year, byte& month, byte& date, byte& DoW, byte& hour, byte& minute, byte& second) {

    byte tempBuffer;

    bool PM;

    bool h12;

    Wire.beginTransmission(CLOCK_ADDRESS);

    Wire.write(uint8_t(0x00));

    Wire.endTransmission();

    Wire.requestFrom(CLOCK_ADDRESS, 7);

    second = bcdToDec(Wire.read());

    minute = bcdToDec(Wire.read());

    tempBuffer = Wire.read();

    h12 = tempBuffer & 0b01000000;

    if (h12) {

    PM = tempBuffer & 0b00100000;

    hour = bcdToDec(tempBuffer & 0b00011111);

    } else {

    hour = bcdToDec(tempBuffer & 0b00111111);

    }

    DoW = bcdToDec(Wire.read());

    date = bcdToDec(Wire.read());

    month = bcdToDec(Wire.read() & 0b01111111);

    year = bcdToDec(Wire.read());

    }

    • Jesus Zanelli

      hola. Lo que dices es cierto, ahora me funciona en 24 horas. Lo gracioso es que ya no me va en 12 horas pero no fue por cambiar si el código sino que desde antes no leía bien, no sé por qué porque hace tiempo las 12 horas funcionan bien.

      Saludos y gracias.

  • Kevin Luis B. Ocaña

    MI error es este, lo hago todo tal cual, me compila perfecto, pero en el monitor me sale esto, ayuda porfavor!

    165/85/165 25:165:165

    165/85/165 25:165:165

    165/85/165 25:165:165

    165/85/165 25:165:165

    165/85/165 25:165:165

    165/85/165 25:165:165

    • Antony García González

      usaste el mismo código?

      • Kevin Luis B. Ocaña

        Si, el mismo codigo vaya, lo seguí paso a paso y me pone eso :S, que puede ser??

      • Kevin Luis B. Ocaña

        sí, use el mismo codigo, ayuda porfavor ;(

        • Antony García González

          Compartenos el código

    • Daniel Navarro Moral

      Si estas usando un Arduino mega debes usar los pines 21 para SCL y 20 SDA

      • Kevin Luis B. Ocaña

        Estoy usando arduino uno….

  • Carlos Alarcon

    Arduino:1.6.7 (Windows 10), Placa:”Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)”

    Opciones de compilación cambiadas, reconstruyendo todo

    reloj1:1: error: #include expects “FILENAME” or

    #includeÂ

    ^

    reloj1:2: error: #include expects “FILENAME” or

    #includeÂ

    ^

    exit status 1

    #include expects “FILENAME” or

    Sugerencia de que pasa? Segui el montaje y el primer codigo , instale la libreria

  • Que tal Anthony está muy buena tu información, quiero ocupar el Arduino como timmer y me surgen estas dudas: Cuando recupero la info de la hora, cómo puedo hacerle para que dependiendo de esta se ponga en 1 un puerto? siendo más específico, si fueran las 6 am quisiera que encienda un foco y cuando sean las 6 pm que se apague. Ya se cómo tengo que decir que se ponga de 1 y en 0 un pin, lo que no logro hacer funcionar es que la lectura de la hora, minuto o segundo las compare con un valor numérico. Cuando pongo la condición If (hora>=6; hora<=12;){….. con el valor que toma de hora ya no hace nada, tengo la ecuación hora=(now.hour(),DEC); hora está declarada como un entero. Alguna idea? Saludos

    • Farameo

      con un rele. es lo que estoy intentando hacer, pero me surge un problema que cuando desconecto el reloj del arduino y lo conecto a las 2 o x horas las horas estan totalmente mal (ejemplo: hoy puse en hora el DS3231 a las 5:50 ahora son las 20:55 y el reloj me mostro 28 horas y 47 minutos) ya medi la pila del reloj y esta todo ok. no se que puede ser.

      • Antony García González

        Es un error en la librería. Necesito cambiar esa versión. En Internet se encuentra la versión corregida

      • Con el relé se puede, mi problema no es tanto con qué encender el foco, sino más bien el tratamiento que se le da a la lectura del rtc y en función de eso llevar a cabo una acción o una sub rutina. Algo no estoy haciendo bien que cuando pregunto por la hora la lee muy bien e imprime el valor de la hora pero después no la actualiza, algo no estoy haciendo bien. Pero no doy con el “que”.

        • Farameo

          Adrian, te mande mensaje mp por facebook. gracias.

          • Que tal amigo, muchas gracias. He recibido tu mensaje y ya te lo contesté, cualquier ayuda en cuanto al tema me sirve de mucho. Estamos en contacto por el facebook. Saludos.

      • Antony García González

        Probablemente es un error de la librería del reloj

    • Antony García González

      Recuerda que Arduino posee la función loop que se ejecuta infinitas veces. Eso quiere decir que siempre que el Arduino esté encendido podrás verificar el estado de la hora y tomar decisiones en base a ello

    • Antony García González

      Necesitas colocar la condición dentro de un IF y declarar una salida digital que se colocará en HIGH si la condición se cumple