Actualización 1.4 de la librería RTC para reloj Dallas DS1307 y DS3231

He aprovechado estos días para actualizar la librería, prácticamente rehaciéndola entera salvo el código de un par de métodos que he conservado.

Ahora la librería cambia automáticamente entre horario de verano e invierno, permite configurar cada dato del reloj de forma individual, o conjunta, y permite obtener sus datos desde objeto de datos o si se prefiere como una cadena de texto lista para imprimir.

A continuación una muestra de lo simple que es su uso:

 

 

 

 

Para que funcione el cambio de hora, debemos de pasar como parámetro al constructor la constante DST_ON o DST_OFF dependiendo de si queremos el cambio automático o no.

El cambio de hora esta pensado para España, si en otros países se cambia igual funcionara, si no sera necesario cambiar las condiciones del método checkDST()

No es necesario hacer nada mas, la librería automáticamente calcula el día en el que se ha de cambiar la hora mediante el algoritmo de Zeller.
Hay que recordar que este cambio de hora lo realiza la librería, no el reloj, por lo que para que el cambio tenga efecto sera necesario que el Arduino este encendido y hacer mínimo una lectura por hora, sobre todo en la hora en la que se hace el cambio, para que se calcule y se hagan los cambios necesarios.

La librería incluye 6 ejemplos, de entre ellos destacar el de configuración mediante el puerto Serial por su utilidad y comodidad

La nueva versión de la librería puede bajarse desde esta entrada, que contiene esta y las versiones anteriores.

Se agradecen los comentarios, desde la parte inferior, sobre posibles fallos o mejoras, o donaciones, desde el lado derecho 🙂

48 comentarios en “Actualización 1.4 de la librería RTC para reloj Dallas DS1307 y DS3231”

  1. Buenas noches,
    No he sabido ver la manera de configurarle al reloj el día de la semana. En algún ejemplo he visto que usas d.dayWeek pero no se en que lugar y con que formato va en el «registro» que usas para d.getdata ó setDateTime.

    ¿Puedo ver en algún sitio toda la información que guarda el reloj?. ¿Hay alguna manera de «cazar» la hora del sistema para una puesta en marcha más «puntual»?

    Gracias por tu trabajo.

    1. Hola Lluís,

      Mi librería no le permite al usuario configurar el día de la semana ya que lo calcula automáticamente mediante la congruencia de zeller cada vez que se establece una nueva fecha/hora.
      Si puedes obtener el valor de la estructura data en la variable dayWeek.

      Toda la información que guarda el reloj puedes verla en su datasheet.
      Hay alguna librería que «cazaba» la hora del sistema pero nunca me funciono a mi, lo ideal seria «cazarla» de un servidor NTP o un servidor web que te envié la hora al gusto.

      Saludos.

  2. La libreria RTC
    * Author: Alberto Gil Tesa
    * Website: http://giltesa.com
    * License: CC BY-NC-SA 3.0
    *
    * Project: RTC Dallas DS1307/DS3231
    * File: RTC.cpp
    * Date: 2016/02/10
    * Version: 1.4.6
    La función isBetween comete un error, si se está fuera del intervalo y el minuto actual coincide con el minuto del intervalo asume que esta dentro del intervalo durante todo el minuto.

    1. Hola Anakin,

      Mejor con lcd.print(), y sólo necesitas cambiar el cursor si quieres cambiar de línea ya que si quieres dejar muchos espacios entre fecha y hora solo tienes que incluir varios espacios en medio:

      Saludos.

  3. Hola,
    muy útil la librería y funciona perfectamente.
    Quería consultarte de como usar el reloj con otro sensor i2c, (por ejemplo el TSL2561) que también va por i2c a las patas A4 yA5. He conectado el reloj y solo ve la hora y el sensor marca cualquier dato,
    gracias.

    1. Hola Guilermo,

      Puedes conectar tantos sensores quieras a los pines I2C siempre y cuando cada sensor use una dirección de memoria de acceso distinta al resto de módulos, los RTC de esta entrada usan la dirección 0x68 (esta indicada en la librería).

      Si todos tus sensores funcionan con librerías cuando con cada librerías ejecutas el método «»»leer_datos»»» el bus I2C es ocupado por ese sensor y una vez obtenidos los datos se libera, como con Arduino no puedes ejecutar dos instrucciones al mismo tiempo si no una detrás de otra es perfecto para conectar muchos módulos e ir leyendo datos uno detrás de otro.

      Saludos.

  4. LLevo usando tu libreria desde hace bastante tiempo y me ha fucnionado bien los cambios de hora de primavera y otoño, pero en la pasada fecha del ultimo cambio de horario, el siguiente minuto a 26/3/2017 1:59, fue 2:00 y no 3:00 como deberia ocurrir. He probado el cambio de fechas del 29/10/ 2017 2:59 y pasa correctamente a 2:00 . He simulado las fechas del cambio de 2018 y pasa lo mismo: lo hace bien en otoño (28/10/2018) con el retraso de hora, pero mal en primavera (25/3/2018) con el adelanto.
    ¿Por que puede ser?

    1. Hola Jose,

      Pues no sé, he estado probandola ahora adelantando la hora hasta 10 segundos antes del cambio de hora varias veces hasta el año 2020 y siempre hace el cambio de hora correctamente.

      He usado este código:

      Y en la librería he modificado el método checkDST para imprimir el día que calcula que hay que cambiar la hora:

      Saludos.

    2. Primero de nada, gracias por tu interés y tu rápida contestación. Te comento:
      He estado haciendo pruebas de nuevo con el sketch que has usado tu (con los mínimos cambios para adaptarlo a mi hardware). Te lo adjunto, para que tu lo veas:

      Pues bien, sigue pasando lo mismo. No responde como debiera «en todos los casos probados». Curiosamente en alguna ocasión, de las muchas pruebas realizadas, observo que puntualmente si responde bien, sin tener una lógica clara: pruebas que en un momento funcionaban bien, con identica fecha luego lo hacen mal y al contrario. Despues de darle alguna pensada al asunto ¿puede ser por la inicialización «RTC rtc(DST_ON);», cuando se hace en una fecha en que debiera estar desactivado este parámetro y entonces devuelve un resultado erroneo?.
      Respecto al método checkDST que envias observo que es identico al que tienes en la libreria, salvo unas instrucciones para visualizar en pantalla y depurar el cambio de hora. Aún así, ¿tendría que cambiar el método?.
      Gracias por todo.

    3. Hola Jose,

      Yo no consigo reproducir el error, si me dices paso a paso lo que haces para detectarlo y consigo emularlo entonces podre arreglarlo.

      Lo único que he cambiado en checkDST son las dos lineas para depurar el código, el resto es igual.

      Saludos.

  5. Muy buenas.
    Trataré de comentarte con detalle las pruebas que he hecho:
    En el IDE de arduino tengo importada la libreria DS1307_DS3231 (version 1.4), que me instala RTC.h
    Cargo el sketch identico al tuyo (salvo los pequeños cambios introducidos como consecuencia de la comunicación I2C con la pantalla LCD, y añadir la libreria wire) en mi arduino Mega. Una vez cargado y cuando aparece la fecha-hora en el LCD abro la pantalla de comunicación serial (9600 baudios), para ir probando las siguientes fecha y horas ( en las que se han producido o se producirán los cambios de hora estacional):

    2017/03/26 1:59:50
    2017/10/29 2:59:50
    2018/03/25 1:59:50
    2018/10/28 2:59:50

    En cada fecha pruebo el comportamiento del reloj y espero 10 segundos para ver si en las fechas de primavera adelanta una hora (pasa de 1:59:59 a 3:00:00) y si en las de otoño la retrasa (pasa de 2:59:59 a 2:00:00), como debiera.

    Pues bien. Los resultados en la primera ronda de pruebas con las fechas anteriores (y en el mismo orden), fueron: mal, bien, bien, bien. Volví a repetir la prueba con las mismas fechas y orden y los resultados fueron todos mal. No he probado mas veces, porque con pruebas similares en otras ocasiones tuve también otras respuestas.
    Como ves, parece que hay un componente de aleatoriedad en la respuesta que no soy capaz de entender. Ensayando la misma fecha, unas veces el reloj responde correctamente y otras no.
    ¿Hay alguna explicación que justifique este comportamiento?
    Gracias, como siempre, por tu ayuda.

    1. Hola
      Cuando haces pruebas y retrocedes el tiempo haces un reset manual al Arduino? Debes hacerlo ya que al encenderlo calcula los dos cambios horarios del año y no vuelve a calcularlos hasta que cambia la hora.

      Saludos

  6. Hola Giltesa
    Primero de nada, puntualizar que es mi primer proyecto (Pardillo)
    Tengo tu librería funcionando perfectamente, pero necesitaría utilizar los dos métodos (DST_ON) y (DST_OFF)
    El primero para que aparezca en pantalla la hora actualizada y el segundo como base de hora para Arduino.
    El capricho es para comandar relés de encendido de acumuladores en tarifa eléctrica de doble horario (tarifa nocturna) que se mantiene en todo el año encendiendo a la misma hora «SOLAR»
    De antemamo muy agradecido por tu trabajo, me resultó muy útil
    Alguna idea ? Aclarar que todo el proceso de apagado y encendido se haría con DST_OFF (horario de invierno)
    El DST_ON, solo se utilizaría para tener la pantalla con la hora humana

    1. Hola Anton,

      Tendrás que duplicar al menos dos lineas, la que instancia(crea) el objeto RTC y también la lectura de datos.

      Te dejo un ejemplo completo:

      Saludos.

    2. Estimado Giltesa
      Antes de nada, agradecerte tu pronta respuesta
      Incluí, como tú me dices esas dos lineas, lo consigo, pero sólo el primer segundo, al siguiente las horas se actualizan con el cambio de hora.
      Enséñame el camino de la verdad
      Muchas gracias

      /*
      * Author: Alberto Gil Tesa
      * Website: http://giltesa.com
      * License: CC BY-NC-SA 3.0
      *
      * Project: RTC Dallas DS1307/DS3231
      * File: ex4_clock_print_large.ino
      * Date: 2014/10/15
      */

      #include
      #include

      RTC rtcOFF(DST_OFF); //Hora Arduino
      RTC rtcON(DST_ON); // Hora humana

      void setup()

      {
      Serial.begin(115200);
      while(!Serial);
      delay(1000);
      // PUESTA EN HORA
      //rtcOFF.setDate( 2018, 3, 25 ); // Year, Month and Day
      //rtcOFF.setTime( 1, 59, 40 ); // Hour24H, Minutes and Seconds

      pinMode (10, OUTPUT);

      }

      void loop()
      {

      Data dOFF = rtcOFF.getData();
      Data dON = rtcON.getData();

      // TIME:

      Serial.print(dOFF.hour24h);
      Serial.print(«:»);

      if( dOFF.minutes < 10 )
      Serial.print("0");
      Serial.print(dOFF.minutes);
      Serial.print(":");

      if( dOFF.seconds < 10 )
      Serial.print("0");
      Serial.print(dOFF.seconds);
      Serial.println(" Hora OFF");

      Serial.print(dON.hour24h); //

      Serial.print(":");

      if( dON.minutes < 10 )
      Serial.print("0");
      Serial.print(dON.minutes);
      Serial.print(":");

      if( dON.seconds =58)
      {digitalWrite(10,HIGH);}
      if (dOFF.hour24h==2&&dOFF.minutes>=59)
      {digitalWrite(10,LOW);}

      delay(1000);
      }

    3. Hola Anton,

      Tienes razón, no te va a ir porque ambas librerías leen la hora del mismo reloj.
      Puedes probar algo como el siguiente código, para mostrar siempre la hora sin DST se comprueba si esta activo y se resta una hora… pero el problema es cuando la hora sea 0 y se reste a -1 en vez de restar 1 día… pero claro al día 1 si le restas 1 no es 0 si no menos 1 mes… y 1 mes menos 1 no es 0 si no menos 1 año…
      Es complejo lo que quieres, otra solución seria tener dos relojes conectados pero para que eso funcionen tendrían que tener distinta dirección de memoria de acceso y habría que indicar en la librería la dirección a la que se tienen que conectar, como los relojes DS1307 y DS3231 no permiten cambiar la dirección esta hardcodeada en la propia librería.

      Saludos.

    4. Perfectamente entendido, algo así ya había razonado, pero a terco no me gana el nano.
      Le daré alguna vuelta mas y si consigo llegar a algo medianamente decente, te lo haré saber
      Muchas gracias por tu tiempo y paciencia

    5. Estimado Gil :
      La solución fué mas sencilla de lo aparente, creando una variable que se incrementa al ser d.minutes y d.seconds 00
      consigo tener una hora que no varia con el cambio de horario
      if (d.minutes==00&&d.seconds==00)
      {(ha++);};
      if (ha==24)ha=00;
      Muchas gracias por tu inestimable ayuda y conocimientos

  7. Gracias por la aclaracion.
    No hacia reseteo entre actualizaciones de fecha, pues pensaba que cada vez que se le hace un setDateTime calculaba el momento del cambio horario para la nueva situación.
    He vuelto a hacer pruebas con las fechas de cambio de hora, pero haciendo un reset del arduino cada vez que retraso la fecha y va todo correcto. Observo que si cambio el orden de las fechas de prueba (por ejemplo: despues de 2017/03/26, pruebo 2018/03/25) en la segunda fecha hace mal el cambio de hora. Para que no sea necesario resetear arduino y haga todos los cambios de fecha correctos hay que seguir siempre el orden cronologico ascendente, sin perderse ninguna conmutación.
    Sabiendo esto, a mi me es suficiente para tenerlo en cuenta.
    Un saludo y gracias de nuevo.

    1. Hola Jose,

      No lo puse pero tiene todo el sentido que cada vez que se cambien los datos del reloj con un setter se recalculen de nuevo los días de cambio de hora.

      Añade esto al código para que funcione así:

      Lo añadiré en versiones futuras.

      Saludos.

  8. Hola
    Soy novato total, quisiera saber que habría que agregar para utilizarlo como un programador horario para activar un relé a una cierta hora.

    1. Y una variable que contenga si estamos en horario de verano o invierno, para poder quitar una hora a la hora programada en un programador horario dependiendo si estamos en verano o invierno.

    2. Hola Manuel,

      La librería cuenta con ejemplos para eso que pides, el ejemplo 8. También puedes sacar el estado del horario de verano con atributo «dst» de la clase Data de la misma forma que se saca la fecha o la hora.

      Saludos.

    3. Ya lo tengo todo solucionado, solo me falta sacar el estado del horario que no se como se hace, para utilizarlo si estamos en horario de verano haz esto.

      Saludos y gracias

    4. Hola,

      Se hace así:

      Saludos.

  9. he vuelto hacer pruebas con el reloj ds1307 y esta libreria para el cambio de hora invierno verano y el problema que he visto que introduciendo la fecha y hora por el serial el dia de la semana no coincide con el que realmente es y por lo tanto en las pruebas del cambio de hora al introducir la fecha del cambio como el dia de la semana no es domingo y deberia serlo para el cambio de hora no lo hace bien y a veces no se ve el cambio, creo que hay un problema en la libreria con los dias de la semana

    1. Hola Carlos,

      Tienes razón, había algo raro en el código a la hora de recuperar los datos de la memoria del reloj ya que en algunos lados se estaba usando el rango 1-7 para los días de la semana y en otros 0-6. He modificado el código para que todo funcione con el rango 0-6 que es el nativo del reloj, luego el método toString de la clase Data permite recuperar el día de la semana en el rango 0-6 o 1-7 (ver comentarios de la librería/ejemplos para más info).

      Estos son los cambios:

      https://github.com/giltesa/RTC_DS3231/commit/3676684332627885276b9774134fed9b9d664a68#diff-473ff282927fd6b9c4914983ad5b35e1

      Puedes descargar la nueva versión desde aquí:

      https://github.com/giltesa/RTC_DS3231/archive/master.zip

      Saludos.

  10. HOLA AMIGO LLEVO MUCHO TIEMPO TRATANDO DE HACER EL CAMBIO AUTOMATICO TANTO EN MARZO COMO EN OCTUBRE, NO SE ATRASA LA HORA NI SE ADELANTA,

    LO QUE NO ENTIENDO ES ESTA PARTE:

    Para que funcione el cambio de hora, debemos de pasar como parámetro al constructor la constante
    DST_ON o DST_OFF dependiendo de si queremos el cambio automático o no. ESTE CAMBIO EN DONDE SE HACE?

    1. Hola Antonio,

      Pues has de cambiar la linea:

      RTC rtc(DST_ON);

      Eso es el constructor, ahí le facilitas una u otra constante/valor. De todas formas creo que el cambio horario difiere de tu país y el mio, quizás tengas que personalizar el método que hace ese cambio.

      Saludos.

  11. Hola Alberto ¿Qué tal? Mi nombre es Daniel y quería, lo primero, agradecerte el trabajo realizado para que todos tengamos las cosas mucho más claras con respecto a arduino y el uso de la librería. Me esta sirviendo muchísimo en el proyecto que estoy realizando, de nuevo mil gracias.

    De hecho, te escribo para preguntarte una duda que tengo acerca de su uso ahora que nos ha cambiado el horario, soy de España, Madrid.
    Tengo el constructor como tu indicas en la librería: RTC rtc(DST_ON); pero cuando recupero la información del sensor rtc.getData();, me sigue apareciendo con una hora de diferencia, lo he dejado un rato conectado para ver si según van pasando las horas se va actualizando pero de momento no tengo resultados positivos. Lo he conectado sobre las 20 horas española pero me sigue sacando las 19.
    ¿Hay algo que esté haciendo mal?¿Se te ocurre cual puede ser el problema?

    Mil gracias por tu ayuda.

    Un saludo,

    Daniel.

  12. Hola Daniel, gracias por tu comentario!

    Pues la libraría sabe en qué momento debe cambiar la hora mediante una operación matemática, entonces se apunta el momento exacto del cambio y cuando desde tu código lees la hora se aprovecha para comprobar si el momento ha llegado, en ese caso hace el cambio de hora y después te devuelve la nueva hora.

    Entonces, si cuando es el cambio de hora tu Arduino esta apagado, o tardas mas de una hora en hacer una lectura, no se cambiara automáticamente. Es decir, en marzo intenta hacer el cambio de 2:00 a 2:59, y en octubre de 3:00 a 3:59:

    Quizás habría que revisar ese comportamiento y pensar en cómo mejorarlo, eso y otras cosas, pero estoy algo distanciado del tema y no creo que vaya a suceder en bastante tiempo. No sé si alguien habrá creado una librería nueva que tenga esa función, la mía es de 2014 así que se me haría raro que eso no exista, ademas la mía no contempla que el cambio de horario sea distinto al de España!

    Saludos!

  13. Muy buenas.
    De nuevo me asomo a tu blog en busca de ayuda.
    Estoy usando tu libreria RTC con total exito desde hace años. Ahora queria introducir una mejora en mi proyecto: que consulte un servidor NTP para sincronizar la hora. El servidor me entrega un numero de 10 digitos que corresponde al numero de segundos desde 1/1/1970. Como puedo setear mi RTC con tu libreria?
    Muchas gracias anticipadas

    1. Hola Jose Manuel,

      Pues tendrás que partir el valor de fecha que lees de tu servidor NTP en trozos para sacar cada valor numérico por separado, y luego ejecutar el setter correspondiente.
      Es bastante parecido a lo que se hace en el ejemplo de la librería leyendo los datos por serial.

      Saludos.

  14. Muchas gracias. Quizas me precipité con la consulta pues fue realmente sencillo con algunos ejemplos que vi por internet. Partiendo de los segundos desde 1970 (formato UNIX) se calcula el número de años, meses, dias, horas, minutos y segundos actuales UTC. Se hace la comprobacion de si la fecha-hora corresponde a verano o invierno para aplicarle una corrección u otra a la hora local y se setea el RTC.
    Gracias.

  15. Buenas noches.
    Como puedo poner esto con su libreria.

    char myBuffer[9];
    sprintf (myBuffer, «%02d%02d%02d%02d», now.day(), now.month(), now.hour(), now.minute());

    Seria algo asi????: sprintf (myBuffer, «%02d%02d%02d%02d»,d.day(), d.month(), d.hour24h(), d.minutes());

    Necesito que me compare el dia, mes, hora y minuto con lo escrito en una tarjeta:
    if ((Tarjeta1 == atol(clave1SD)) ||(myBuffer[9]==atol(clave1SD))){

    localizado = true;

    Muchas gracias y Felices Fiestas 2019/2020

  16. que tal excelente trabajo quiero implementar tu libreria, tengo unas dudas, soy de mexico funciona para este pais, otra pregunta, como puedo modificar la libreria checkDTS ,para ajsutar a otra fecha diferente,

  17. Buenas noches Alberto, sensacional librería que lelvo usando hace tiempo, ahora pero, estoy en un proyecto dónde entre otros datos, los muestro por un TFT, he corregido el tema del solapamiento de carácteres mediante una funcion millis:

    unsigned long currentMillisT = millis();
    if(currentMillisT – previousMillisT > intervalo_lectura)
    {
    previousMillisT = currentMillisT;

    tft.setTextSize(1);
    tft.setTextColor(ST7735_RED, ST7735_BLACK);
    sprintf(TX,»%d», d.seconds);
    tft.setCursor(2,50);
    tft.print(TX);
    }

    Si lanzo sólo el valor d.seconds, se grafiquea bien y no se solapa, pero del 1 al 9 aparece a la izquierda…

    Eso era en fase de pruebas, realmente no se como hacerlo, es que si cojo todo el string d.toString(«d/m/Y H:i:s») aparece 8681, estoy seguro que es algo que estoy haciendo mal entre strings i demás… me puedes recomendar como hacerlo? o señalarme como podría hacerlo?

    si pongo tft.print(d.toString(«d/m/Y H:i:s») ); funciona y se muestra bien, pero con solapamiento, y dicha función la pongo dentro del bucle de millis, me aparece bien, pero duplicando los segundos…. raro raro…. sabrías decirme algo? trabajo sobre una mega con tft 1.8 mediante libreria Adafruit GFX con el ST7735. muchisimas gracias

    1. Hola Cesc,

      No puedo probar nada porque estoy viviendo en otro país ahora. Pero podrías comprobar que el código funcione correctamente primero por el puerto serial y después por la pantalla.

      Eso debería de imprimirte por serial algo parecido a esto: “2020/01/30 14:08:20”
      Si te funciona por serial, pero no por pantalla, prueba usando esto que te devuelve una cadena de caracteres.

  18. muchas gracias por tu atención, en Serial funciona, el problema creo que lo tengo en el tratamiento de strings o algo… y se me escapa… seguiré buscando a ver que puede ser, por lo poco que sé, es que la fecha tu librería me la presenta en un string, y si quiero mantener el «refresco» en la tft y obviamente que se vea la fecha correctamente, no se hacerlo… se me imprime por ejemplo 2181 en vez de la fecha con sus barras y horas y muntos… no se si me explico, en fin, gracias de nuevo

Escriba aquí su comentario