Librería de Arduino para consultar fecha y temperatura del integrado DS3231 por I2C

publicado en: Portada | 62
ACTUALIZADA: Visita también la nueva librería para gestionar fecha y hora con el módulo RTC DS3231 y Arduino con mejoras como la hora estacional.

El funcionamiento de los IC de relojes en tiempo real (RTC) más populares que se controlan utilizando el bus I2C suele ser muy similar. Además, la librería Wire de Arduino simplifica mucho las comunicaciones con dispositivos Two-wire Serial Interface (TWI), I2C, en concreto.

A grandes rasgos, el proceso consiste en

  1. Iniciar las comunicaciones como esclavo (slave) o maestro (master, establecidas por defecto) con la función Wire.begin(dirección). Si se omite «dirección» se inician las comunicaciones siendo el μC el maestro del bus I2C.

  2. Activar la comunicación I2C con el dispositivo a través de la dirección de memoria en la que se encuentre, usando la orden Wire.beginTransmission(dirección).

  3. Escribir una orden en el bus I2C para indicar al dispositivo la operación que se desea que realice, usando Wire.write(orden), en la que «orden» es el código de la operacíon.

  4. Desactivar las comunicaciones para liberar el bus I2C con la función Wire.endTransmission().

  5. Solicitar al dispositivo el envío de cierta cantidad de datos que corresponden con la operación que se ha solicitado (en este caso, la fecha y la hora) con la función Wire.requestFrom(dirección,cantidad).

  6. Esperar a que estén disponibles para su lectura los datos solicitados con la función Wire.available(), que devuelve el número de datos que ya se han recibido y pueden leerse.

  7. Leer los datos enviados por el dispositivo (el reloj en tiempo real, en este caso) usando la función Wire.read() tantas veces como bytes indique Wire.available() que están disponibles.

  8. Normalmente los datos se envían en formatos muy compactos así que es muy probable que sea necesario interpretar los datos recibidos de manera que correspondan con la representación de los datos que se haga en el programa que usa el dispositivo.

En lo que se refiere al DS3231 (y a los compatibles de la misma serie, como el DS3232) y a la interpretación de los datos, según las especificaciones del integrado, por ejemplo, los valores de los distintos dígitos que representan la hora se representan en decimal codificado en binario (BCD) que será más cómodo expresar como un valor decimal (un byte) para usarlo en Arduino

En la misma línea, la temperatura se expresa como un byte en complemento a dos para la parte entera y dos bits para el paso, con una resolución de un cuarto de grado, de la parte decimal. En el código de la librería que se incluye a continuación se han comentado de forma exhaustiva estos y otros aspectos de la representación de los datos en el reloj DS3231

Para consultar la temperatura con esta librería basta con usar el método leer_temperatura() del objeto DS3231 instanciado al empezar. Para leer la fecha y la hora en primer lugar se cargan y después se solicita en uno de los formatos (compacto, humano…) disponibles para distintos usos, documentados en el documento de cabecera de la librería del código de abajo.

El siguiente es un código de ejemplo para mostrar cómo usar la librería. Como se decía más arriba, la temperatura se lee simplemente con la función leer_temperatura() del objeto de la clase DS3231 pero, para ignorar errores en la lectura, se utilizan dos constantes que almacenan, respectivamente, la temperatura máxima y mínima del dispositivo según la hoja de datos y que se leen con las funciones correspondientes.

La lectura de la temperatura se realiza en dos tiempos: en primer lugar se carga el valor, con lo que diferentes usos de la fecha o la hora serán coherentes (no mostrarán un valor mayor en casos desfavorables) y en segundo lugar se usa conforme al formato que se necesite. En el programa de ejemplo (que no es muy práctico, aunque explica todas las posibilidades) se muestran todos los formatos disponibles

  • La función valor_fecha_hora() que devuelve un puntero a una matriz de char (bytes) que contiene los siete valores numéricos que representan la fecha y la hora en un reloj DS3231 convertidos a decimal (están en BCD en el dispositivo)

  • Usando la función numero_dia_semana() se obtiene un valor que corresponde con el número del día de la semana empezando en domingo. Para mostrarlo como texto se utiliza una matriz y se resta uno para empezar en el índice cero, domingo.

  • Para consultar la fecha en un formato «local» (español) se usa la función fecha_humana(), que entrega un puntero a una cadena en la que se representa la fecha en formato DD/MM/AAAA, siendo DD el día representado con 2 dígitos, MM el mes con 2 dígitos y AAAA el año con 4 dígitos.

  • La función hora_humana() devuelve la hora en el formato hh:mm:ss, siendo hh la hora (en formato de 24) representada con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos.

  • Para usar fácilmente la fecha y la hora en archivos de registro (log) se ha programado la función fecha_hora_compacta(), que entrega el valor de la fecha y la hora en el formato AAMMDDhhmmss siendo AA el año representado con los 2 últimos dígitos, MM el mes con 2 dígitos, DD el día con 2 dígitos, hh la hora (en formato de 24) con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos. Este formato, aún siendo de texto, ocupa poco y permite una ordenación alfabética muy sencilla.

  • La función fecha_hora_MySQL() sirve para presentar la fecha y la hora en el formato que usa el gestor de bases de datos MySQL (o la nueva y más libre MariaDB) AAAA-MM-DD hh:mm:ss, siendo AAAA el año representado con 4 dígitos, MM el mes con 2 dígitos, DD el día con 2 dígitos, hh la hora (en formato de 24) con 2 dígitos, mm los minutos con 2 dígitos y ss los segundos con 2 dígitos.

Aunque son muchos formatos con los que representar la fecha y la hora, puede que no esté el que necesitas, pero seguro que basándote en alguno de los que hay y usándolo como ejemplo, será sencillo añadir un nuevo método conforme a otras especificaciones. Por favor, si añades nuevas funciones, comparte el código (¡libéralo!) y explícanos cómo funciona, así vamos haciendo mejor la librería poco a poco ¡Gracias!

La salida del anterior programa de ejemplo podría ser algo parecido a lo que se muestra en la siguiente imagen: una lista de 7 valores (segundos, minutos, hora, día de la semana, día del mes, mes y año) la fecha y la hora expresadas de forma «humana» (según el estilo español) la hora como un número entero en el formato de los relojes de cuatro dígitos, la fecha y la hora en formato de la base de datos MySQL, la fecha y la hora en formato compacto (para logs) y la temperatura interna del DS3231.

salida consola Arduino librería reloj tiempo real (RTC) y temperatura DS3231 por bus I2C

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

62 Respuestas

  1. mikael

    Siento la molestia pero al tratar de compilar el codigo de ejemplo que pones aqui me de error de compilacion.

    adjunto copia de los errores

    Arduino:1.6.5 (Windows Vista), Placa:»Arduino Uno»

    DS3231\DS3231.cpp.o: In function DS3231::DS3231()':
    C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire/Wire.h:73: multiple definition of
    DS3231::DS3231()’
    DS3231.cpp.o:C:\Users\Mikael\AppData\Local\Temp\build5789158021410268843.tmp/DS3231.cpp:5: first defined here
    DS3231\DS3231.cpp.o: In function DS3231::DS3231()':
    C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire/Wire.h:73: multiple definition of
    DS3231::DS3231()’
    DS3231.cpp.o:C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire/Wire.h:73: first defined here
    collect2.exe: error: ld returned 1 exit status
    Multiple libraries were found for «DS3231.h»

    Used: C:\Users\Mikael\Documents\Arduino\libraries\DS3231

    Not used: C:\Program Files (x86)\Arduino\libraries\DS3231

    Error de compilación

    This report would have more information with
    «Show verbose output during compilation»
    activala desde Archivo > Preferencias

    • Víctor Ventura

      Hola, Mikael.
      Parece que ya has cargado la librería Wire en tu programa (a lo mejor otra librería que también usas es la que lo hace
      De ser así puedes editar el documento «DS3231.h» y borrar (o mejor, comentar) la línea 9 en la que se carga Wire para comunicar con el DS3231.
      Saludos y suerte con tu proyecto.

  2. mikael

    muchas gracias pero sigue sin funcionar.

    comento la linea 9 como me dices anulando la carga de wire desde ds3221.h

    al comprobar me dice que wire no esta declarado en 3231.ccp

    Adjunto errores :

    Arduino:1.6.5 (Windows Vista), Placa:»Arduino Uno»

    DS3231.cpp: In member function ‘void DS3231::cargar_fecha_hora()’:
    DS3231.cpp:18: error: ‘Wire’ was not declared in this scope
    Wire.beginTransmission(DIRECCION_DS3231); // Comunicar con el DS3231 en la dirección correspondiente
    ^
    DS3231.cpp: In member function ‘void DS3231::grabar_fecha_hora(char*)’:
    DS3231.cpp:120: error: ‘Wire’ was not declared in this scope
    Wire.beginTransmission(DIRECCION_DS3231); // Comunicar con el DS3231 en la dirección correspondiente
    ^
    DS3231.cpp: In member function ‘double DS3231::leer_temperatura()’:
    DS3231.cpp:136: error: ‘Wire’ was not declared in this scope
    Wire.beginTransmission(DIRECCION_DS3231); // Preparar el dispositivo
    ^
    Multiple libraries were found for «DS3231.h»

    Used: C:\Users\Mikael\Documents\Arduino\libraries\DS3231

    Not used: C:\Program Files (x86)\Arduino\libraries\DS3231

    ‘Wire’ was not declared in this scope

    Arduino Version: 1.6.5-r2

    ¿puede ser problema de las direcciones I2C ?

    soy muy nuevo en esto lo siento

    • Víctor Ventura

      Hola, Mikael.

      Las direcciones I2C no tienen nada que ver con esto.
      Por el texto de error que mandas está claro que no era el problema que te decía, así que lo de comentar la línea que carga la librería Wire (línea 9) no es; toca «descomentarla» y volver a empezar.
      ¿Puedes dar alguna pista más de cómo es tu código y/o de cómo estás usando la librería? Así a ciegas nos podemos pasar meses hasta saber qué puede ser 🙂

      Saludos.

  3. mikael

    a ver te cuento
    copio el codigo de ejemplo tal cual y pego
    en la misma carpeta que guardo el .ino con el codigo tengo la libreria tanto .h como .ccp
    tambien estan en la carpeta de librerias de arduino
    el ide de arduino es el 1.6.5
    no se que mas datos darte

    • Víctor Ventura

      Lo de que lo usas con el programa de prueba y la versión del IDE parece relevante. Voy a descargar y probar, que normalmente trabajo con el IDE estable de la distribución, y te cuento.

  4. mikael

    por cierto saludos y muchas gracias
    que los lunes mi educacion esta de baja

    • Víctor Ventura

      De nada, y ánimo con ese lunes, en unas horas tu educación se recupera y ya te veo poniendo los tenedores y los cuchillos en su lado de la mesa y todo eso 😀

    • Víctor Ventura

      Hola, Mikael.

      Tengo una buena-mala noticia: he descargado el IDE 1.6.5 y he compilado el programa de prueba correctamente.
      Puedes descargar la prueba por si te aclara algo o hasta te funciona (avisa en tal caso, por favor)
      La verdad es que no se me ocurre qué problema puede ser (a ciegas…) Si me das alguna pista más a lo mejor puedo seguir investigando por otro lado.

      Saludos y otra vez suerte.

      • mikael

        he descargado la prueba y da el mismo error
        por si las moscas he desisntalado el ide he borrado manualmente las carpetas residuales y he vuelto a instalar

        sige igual 🙁

        ¿pudiera ser algun residuo de otras instalaciones ? ni idea

        • Víctor Ventura

          ¿Mismo-mismo error? A lo mejor no está claro (culpa mía) cómo usar lo que te he mandado: descárgalo, descomprímelo, graba el contenido en una carpeta que se llame «prueba_libreria_DS3231» (que no le gusta a Arduino que el sketch esté en una carpeta con distinto nombre) y ejecútalo. Es decir: no grabes la librería en la carpeta de librerías (para empezar a probar)

          • mikael

            asi lo he echo
            pero nada
            estoy pasando cleaner a ver

  5. D4n1

    Hola, muy buena la librería.

    El problema que tengo es que no he podido poner el reloj en hora la primera vez.
    Supongo que tengo que usar la función grabar_fecha_hora(*fecha) pero no lo consigo.

    ¿Como sería?

    Muchas gracias.

    un saludo

    • Víctor Ventura

      Hola, D4N1.

      En efecto, para «poner en hora» el DS3231 con esta librería hay que usar la función grabar_fecha_hora y pasarle como parámetro una matriz de char que represente la fecha y la hora en el formato que indico en la declaración de valor_fecha_hora_DS3231, es decir, el valor del índice 0 representa los segundos, el 1 los minutos, el 2 las horas (en formato de 24), el 3 el día de la semana empezando en el domingo que es 1, el 4 el día del mes, el 5 el número del mes y el 6 los dos últimos dígitos del año.

      Un error (típico) podría ser expresar el parámetro que representa la fecha y la hora como un texto en lugar de un vector (matriz) de valores, pero para poder decírtelo con seguridad necesitaría ver la parte del programa que no te funciona. Si con esta pista no te ayudo no tengas inconveniente en mandarme el código que te da problemas para que le eche un vistazo a ver si encuentro el error.

      ¡Gracias a ti por visitar el blog!

      • D4n1

        Gracias por contestar tan rápido.

        Estoy usando tu mismo código, la única modificación es:
        he declarado la variable con la fecha char setHora[]={0,52,16,2,4,1,16};
        en el setup llamo a la función reloj.grabar_fecha_hora(setHora);

        el resultado que muestra por el serial es:
        Contenido de la posicion 0 del buffer de la fecha -> -91
        Contenido de la posicion 1 del buffer de la fecha -> -91
        Contenido de la posicion 2 del buffer de la fecha -> 45
        Contenido de la posicion 3 del buffer de la fecha -> 7
        Contenido de la posicion 4 del buffer de la fecha -> 45
        Contenido de la posicion 5 del buffer de la fecha -> 25
        Contenido de la posicion 6 del buffer de la fecha -> -91
        El di­a 45/25/20-91, , a las 45:-91:-91
        (4409 en un reloj de 4 di­gitos y 20-91-25-45 45:-91:-91 segun MySQL o 45:-91 abreviadamente)
        la temperatura era de -127.75 grados centi­grados

        No se si es por la llamada a reloj.grabar_fecha_hora que la estoy haciendo mal o puede ser un problema con el reloj porque en la parte de leer la temperatura me da error aunque el led rojo del reloj se enciende cada vez que hace una lectura.

        Muchas gracias.
        Un saludo.

        • Víctor Ventura

          Hola, D4N1.

          Parece que el problema no está relacionado con el establecimiento de la fecha y la hora ¿Has verificado que la hora se va incrementando aunque empiece mal?

          Me da la impresión de que no está comunicando bien por I2C ¿En alguna parte del programa inicializas el bus con Wire.begin? Suele ser un problema habitual, por ejemplo, cuando se trabaja con varios componentes I2C.

          Otro problema podría ser la dirección del dispositivo I2C, normalmente se inicializa sin indicarla, con Wire.begin(), pero según cómo sea tu circuito (el módulo con el DS3231) puede ser necesario indicarla expresamente.

          ¿Eso te ayuda? No tengas inconveniente en seguir preguntando si te hace falta.

          • D4n1

            Hola Víctor,
            Me funciona perfectamente, el problema era que el cable GND no hacía contacto en la placa de prototipado. Ahora el led del reloj ya está fijo.

            Ya he trasladado la librería a mi proyecto y funciona muy bien haciendo un cast en el menú de configurar la hora.

            char setHora[]={0,(char)minute,(char)hour,(char)dayOfWeek,(char)dayOfMonth,(char)month,(char)year};
            reloj.grabar_fecha_hora(setHora);

            Muchísimas gracias por la librería y por la ayuda prestada.
            Un saludo

  6. David

    Hola, muy buena la librería del RTC, una pregunta, habría alguna manera con su libreria de hacer esto: if(Reloj.IsLater( 7,15 ) && Reloj.IsPrevious( 13,18 ));
    Un saludo y muchas gracias

    • Víctor Ventura

      Hola, David.

      La librería que explico en este artículo pretende principalmente controlar el DS3231 y explicar un poco su funcionamiento y su uso junto con la entrada sobre las comunicaciones I2C con el reloj en tiempo real DS3231.

      Como habrás visto, en los ejemplos he optado por incluir recursos para presentar la hora en un display o almacenarla en una base de datos MySQL, pero no he incluido otras para comparar fechas (lo que tú pides, si lo he entendido bien) ni otras para actualizar el cambio de horario en verano, por ejemplo (algo, por cierto, muy demandado también)

      Tomo nota tanto de tu sugerencia para comparar fechas y horas, como de la modificación de la hora estacional y como de otras (algunas muy interesantes, la verdad) y seguramente las desarrollaré y las publicaré (ojalá que pronto)

      Dicho lo anterior, aprovecho para comentar unas cuestiones que creo que no estoy dejando muy claro en mis artículos y que lleva a los lectores de polaridad.es a confusión.

      • Las librerías no pretenden ser una aportación completa y cerrada para usar un dispositivo sino ejemplos para explicar cómo hacerlo.
        Muchos lectores me preguntaban por la descarga de las librerías y me extrañaba ¿Por qué no copian y pegan lo que necesitan? Después entendí que buscaban soluciones finales y aunque ahora suelo facilitar las descargas, cosa que puede confundir en su objetivo, sigo con la misma filosofía, en general más didáctica que de explotación.
      • La memoria de las series más pequeñas de las placas Arduino es muy limitada y existe el riesgo cierto de agotarla innecesariamente. Yo mismo hago con frecuencia implementaciones ad hoc del código que se ve en las librerías de los diferentes artículos para usar sólo lo que necesito en cada caso (por no hablar de lo tacaño que soy en los programas de producción con las cadenas de texto) Así que mi consejo es no usar (siempre) toda la librería sin más sino hacer una nueva con las partes que el proyecto concreto demande. Algo que, si empiezas a programar microcontroladores después de haber programado ordenadores (microprocesadores), un entorno mucho más generoso en memoria, te puede parecer raro y poco productivo inicialmente.
      • Para programar los microcontroladores más básicos suele ser más eficaz, en términos de uso de memoria (yo lo hago así), tener una colección de recortes de código, más que una «súper-librería», que ir reutilizando para dar respuesta a los problemas comunes. Por supuesto, la caza de mosca con cañón está totalmente desaconsejada.

      Ni mucho menos digo que tu caso sea el del último punto pero, por si mi experiencia puede ayudarte con carácter general, en el contexto que he planteado es útil tratar de resolver primero el problema (ver si una fecha es mayor que otra o si está vigente el horario estacional) con los recursos disponibles (comparar año, comparar mes, comparar día…) y luego considerar si procede la generalización (incorporar una nueva función a una librería)

      Muchas gracias por tu aportación ¡Espero ver más por aquí! ¡Hasta pronto!

  7. Luis

    Hola, felicidades por el tutorial sobre las librerias.
    Lla verdad es que se aprende bastante viendo las distintas librerias que hay de cada RTC. Tengo una libreria (no creacion mia)que aporta algo similar a lo que David pide por asi decirlo, la unica pega es que por alguna razon no reconoce las horas comprendidas entre 00 y 10 y salta el programa. seria un buen aporte complementar una con la otra o adaptar su libreria a esa peticion, ya que actualmente hay muy pocas librerias para RTC con esa aportacion extra. Un saludo y siga asi compartiendo y enseñando. Mis felicitaciones

    • Víctor Ventura

      Hola, Luis.

      Pues si es os parece tan interesante, en cuanto tenga un rato libre publico algo al respecto y si es posible añado y/o comento los otros aspectos que sobre la fecha y hora están en el aire.

      Gracias por aportar tu opinión ¡Hasta pronto!

  8. gustavo

    Hola.
    Victor, tanto con esta libreria como otras que encontre por el google. cuando pasa 1 segundo a esta hora: 24:59:29 (h:m:s) el reloj pone: 25:0:0 (25 horas….) que estoy haciendo mal en todo este quilombete? la pila esta bien (ya le medi con un multimetro). gracias

  9. salva

    Hola me parece genial como esta Todo explicado.
    Pero tengo una duda.

    Puedo llamar directamente a la instrucción grabar _ hora o similar directamente por ejemplo grabar_hora (10,23,45,3,12,02,16);

    • Víctor Ventura

      Hola, Salva.

      Para llamar a grabar_fecha_hora hay que pasarle un vector de char con los datos en lugar de cada dato por separado (es decir, tu ejemplo no valdría)
      Como parece que es una petición bastante habitual voy a ver si saco un poco de tiempo y añado una función que lo haga como dices en tu comentario y de camino añado otras sugerencias como la hora estacional.

      ¡Gracias por visitar polaridad.es!

      • salvador

        gracias
        ya esta solucionado

        char setHora[]={0,06,10,7,19,3,16};
        reloj.grabar_fecha_hora(setHora);

        pero una pregunta bueno dos por una parte he visto la libreria cpp que es una libreria hecha en c++? y otra que el objeto reloj no encuentro donde lo has creado.

        bamos que la libreria al principio no me funcionaba por que no habia puesto reloj.etc

        lo demas he programado algo de c# y mas de c y lo entiendo pero estoy empezando en arduino que vengo de muchos años con el pic con el c de ccs y me gusta mas la interaccion de arduuino

        pero el objeto reloj me ha creado dudas

        DS3231 reloj;

        Y nuevamente enhorabuena por tu Pagina me parece maravillosa animo y publica mas cosas

        • Víctor Ventura

          Hola, Salvador.

          La librería está programada en C++ usando las librerías correspondientes de Arduino. Podríamos decir que está «programada en Arduino» XD
          El objeto reloj se crea (vacío) al declararlo en la línea 14 del ejemplo.

          Gracias por tus halagos. Claro que publicaré más cosas ¡y espero que te gusten!
          ¡Vuelve pronto!

          • salvador

            DE NADA despues de grabar la fecha_hora puede ser que se quede parado el reloj y haiga que ponerlo en podo run

          • Víctor Ventura

            Hola, Salvador.

            No, después de ponerlo en hora puede usarse inmediatamente. Lo que no necesariamente funciona al empezar a usarlo es la temperatura, que tarda un poco desde que se conecta (esto es por el DS3231, no por el programa)

            ¡Saludos!

  10. salva

    Hola Victor tengo un problema tengo el reloj funcionando pero cuando grabo la hora despues de 17 pasa a 10 si voy subiendo.
    Gasto Clock.setHour (hour)
    He probado a poner que fubcione en 12h y 24h y lo mismo lo que si lo dejas si que rebasa el mismo los 17 y narca 21, etc

    • Víctor Ventura

      Hola, Salva.

      La librería que yo he desarrollado no tiene ningún método setHour() No tengo la menor idea de lo que has probado. A lo mejor si nos das más información te podemos ayudar.

      Saludos.

  11. salvador

    DE TODAS FORMAS UNA PREGUNTA

    COMO PODRIA LEER EL BYTE DE LA DIRECCION 0X02 QUE CORRESPONDE A LA HORA PARA VER TODO EL DATO SOLO CON WIRE.

    Wire.begin();
    Wire.requestFrom(2, 1);

    while(Wire.available())
    {
    char Datos = Wire.read(); // Leemos un byte y lo pasamos a una variable de tipo char
    Serial.print(Datos); // Lo mostramos en el puerto serie
    }

    • Víctor Ventura

      Hola, Salvador.

      Creo que esto es lo que pides:

      Espero que te sirva.

      Saludos.

  12. salvador

    mira estoy modificando mi programa para tu libreria he tenido que borrar bastantes cosas pero lo he dejado para que solo muestre los datos por el lcd.

    pero me da error de libreria mira:
    C:\Users\PRESID~1\AppData\Local\Temp\buildcd51d280c9b80e87bc7b542d5b5b3525.tmp\sketch\PROGRAMADOR_LED.ino.cpp.o: In function REFRESCO()':

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:561: undefined reference to DS3231::cargar_fecha_hora()’

    C:\Users\PRESID~1\AppData\Local\Temp\buildcd51d280c9b80e87bc7b542d5b5b3525.tmp\sketch\PROGRAMADOR_LED.ino.cpp.o: In function loop':

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:449: undefined reference to DS3231::cargar_fecha_hora()’

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:408: undefined reference to DS3231::cargar_fecha_hora()'

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:482: undefined reference to DS3231::cargar_fecha_hora()’

    C:\Users\PRESID~1\AppData\Local\Temp\buildcd51d280c9b80e87bc7b542d5b5b3525.tmp\sketch\PROGRAMADOR_LED.ino.cpp.o: In function __static_initialization_and_destruction_0':

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:40: undefined reference to DS3231::~DS3231()’

    C:\Users\PRESID~1\AppData\Local\Temp\buildcd51d280c9b80e87bc7b542d5b5b3525.tmp\sketch\PROGRAMADOR_LED.ino.cpp.o: In function setup':

    C:\Users\Presidente\Documents\Arduino\PROGRAMADOR_LED/PROGRAMADOR_LED.ino:84: undefined reference to DS3231::cargar_fecha_hora()’

    collect2.exe: error: ld returned 1 exit status

    y el program,a es este

    #include
    #include // F Malpartida’s NewLiquidCrystal library
    #include «DS3231.h»
    #include
    #define I2C_ADDR 0x27 // Direccion I2C para PCF8574A que es el que lleva nuestra placa diseñada por MJKDZ

    #define INTERVALO_MEDICION 10000
    #define ESPERA_ERROR 1000
    #define LONGITUD_BUFFER_DS3231 7
    #define LONGITUD_FECHA_FORMATEADA 18

    //definimos las constantes para esta placa
    #define MENU 4
    #define ENTER 7
    #define SUBE 6
    #define BAJA 5
    //////////////////////////////////////////////////////////////////////////////////
    char buffer_fecha[LONGITUD_BUFFER_DS3231];
    char *puntero_fecha;
    char buffer_fecha_formateada[LONGITUD_FECHA_FORMATEADA];
    unsigned long cronometro;
    //////////////////////////////////////////////////////////////////////////////////
    float temperatura;
    bool subir,bajar,ON;
    bool ActualizaHora=false,ActualizaMinutos=false;
    bool ActualizaLCD =LOW;
    int ActualizacionLCD=9,escape=0;
    int INTERRUPCION1=0;
    byte var=0;
    byte act=0;
    String Dia;

    // addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
    LiquidCrystal_I2C lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
    DS3231 reloj;
    void DiaSemanal(void);
    void MENU_PULSADO(void);
    void REFRESCO(void);
    void setup()
    {
    Serial.begin(9600);
    lcd.begin (16,2);

    pinMode(MENU,INPUT);
    pinMode(ENTER,INPUT);
    pinMode(SUBE,INPUT);
    pinMode(BAJA,INPUT);
    attachInterrupt( 0,RELOJ,CHANGE);

    /*
    //Se establece el modo horario en 12 horas (false = 24h)
    Clock.setClockMode(true);
    //Se establece el año
    Clock.setYear((byte)(16));
    //Mes
    Clock.setMonth((byte)03);
    //Dia de la semana (no lo estoy considerando)
    //Clock.setDoW((byte)dia);
    //Día
    Clock.setDate((byte)22);
    //Hora
    Clock.setHour((byte)11);
    //Minutos
    Clock.setMINUTO((byte)07);
    //Segundos
    Clock.setSecond((byte)0);
    */
    // inicializar lcd
    // Activamos la retroiluminacion
    lcd.setBacklight(HIGH);
    lcd.clear();
    Wire.begin();
    Wire.beginTransmission(104);
    //select control register
    Wire.write(0x0e);
    //set square wave @ 1 Hz (setup square wavew at choice of 0=1Hz/8=1024Hz/16=4096Hz/24=8192Hz)
    // code shows 1 Hz selection ;
    Wire.write(0); // <======(code shows 1 Hz selection ; )(change value to "8" for 1khz)
    Wire.endTransmission();
    // Clock.setClockMode(false);

    puntero_fecha=reloj.cargar_fecha_hora();
    delay(100);
    ///////////////////////////ACTUALIZAMOS EL LCD CON LA FECHA Y HORA
    lcd.setCursor(0,0);

    lcd.print(HORA);
    lcd.print(":");
    lcd.print(MINUTO);
    lcd.print(" ");
    lcd.print(DIA);
    lcd.print("/");
    lcd.print(MES);
    lcd.print("/20");
    lcd.print(ANO);
    lcd.print(" ");
    delayMicroseconds(100000);
    }

    void loop()
    {
    if (digitalRead(MENU)==HIGH) {
    delay(200);
    while(digitalRead(MENU)==HIGH){

    }
    MENU_PULSADO();
    }
    //PROCEDEMOS A PROGRAMAR LA HORA

    while(ActualizaHora==true){

    puntero_fecha=reloj.cargar_fecha_hora();
    lcd.setCursor(0,0);

    if(HORA<10) lcd.print("0");
    lcd.print(HORA);
    lcd.print(":");
    if(MINUTO100){
    escape=0;
    break;
    }
    }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    if(act==2 && var==1){
    escape=0;
    REFRESCO();
    lcd.setCursor(0,2);
    lcd.print(«Set Minutos «);
    delay(1000);
    var = var+1;

    while(1){
    if(digitalRead(SUBE) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if(digitalRead(BAJA) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if (digitalRead(MENU)==HIGH) {
    delay(200);
    while(digitalRead(MENU)==HIGH){

    }
    MENU_PULSADO();
    break;
    }
    delay(100);
    escape++;
    if(escape>100){
    escape=0;
    break;
    }
    }
    }
    //////////////////////////////////////////////////////////////////////////////////////////////
    if(act==3 && var==2){
    escape=0;
    REFRESCO();
    lcd.setCursor(0,2);
    lcd.print(«Set Dia «);

    delay(500);
    var = var+1;

    while(1){
    if(digitalRead(SUBE) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if(digitalRead(BAJA) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();

    }
    if (digitalRead(MENU)==HIGH) {
    delay(200);
    while(digitalRead(MENU)==HIGH){

    }
    MENU_PULSADO();
    break;
    }
    delay(100);
    escape++;
    if(escape>100){
    escape=0;
    break;
    }

    }
    }
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    if(act==4 && var==3){
    REFRESCO();
    escape=0;
    lcd.setCursor(0,2);
    lcd.print(«Set Mes «);
    delay(1000);
    var = var+1;

    while(1){
    if(digitalRead(SUBE) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if(digitalRead(BAJA) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if (digitalRead(MENU)==HIGH) {
    delay(200);
    while(digitalRead(MENU)==HIGH){

    }
    MENU_PULSADO();
    break;

    }
    delay(100);
    escape++;
    if(escape>100){
    escape=0;
    break;
    }
    }
    }

    if(act==5 && var==4){
    escape=0;
    REFRESCO();
    lcd.setCursor(0,2);
    lcd.print(«Set Año «);

    delay(1000);
    var = var+1;

    while(1){
    if(digitalRead(SUBE) == HIGH) {
    delay(500);
    escape=0;

    REFRESCO();
    }
    if(digitalRead(BAJA) == HIGH) {
    delay(500);
    escape=0;

    lcd.setCursor(0,0);

    lcd.print(HORA);
    lcd.print(«:»);

    lcd.print(MINUTO);
    lcd.print(» «);

    lcd.print(DIA);
    lcd.print(«/»);

    lcd.print(MES);
    lcd.print(«/20»);
    if(ANO100){
    escape=0;
    break;
    }
    }
    }
    if(act==6 && var==5){
    escape=0;

    lcd.clear();
    lcd.setCursor(0,0);
    DiaSemanal();
    lcd.print(SEMANA);
    lcd.setCursor(0,1);
    lcd.print(«Set Dia semanal «);

    delay(1000);
    var = var+1;
    delay(100);

    while(1){

    if(digitalRead(SUBE) == HIGH) {
    delay(1000);
    escape=0;

    lcd.setCursor(0,0);
    DiaSemanal();
    lcd.print(SEMANA);
    lcd.print(» «);
    delay(100);
    }
    if(digitalRead(BAJA) == HIGH) {
    delay(1000);
    escape=0;

    lcd.setCursor(0,0);
    DiaSemanal();
    lcd.print(SEMANA);
    lcd.print(» «);
    delay(100);

    }
    if (digitalRead(MENU)==HIGH) {
    delay(200);
    while(digitalRead(MENU)==HIGH){

    }
    escape=0;
    MENU_PULSADO();
    break;
    }
    delay(100);
    escape++;
    if(escape>100){
    escape=0;
    break;
    }

    }
    }

    act=0;
    var=0;
    delay(1000);
    ActualizaHora=LOW;
    delay(1000);

    attachInterrupt( 0,RELOJ,CHANGE);

    ////////////////////////////////////////////////////////
    lcd.clear();
    lcd.setCursor(0,0);
    if(HORA<10) lcd.print("0");
    lcd.print(HORA);
    lcd.print(":");
    if(MINUTO3){
    ActualizaLCD=HIGH;
    ActualizacionLCD=0;
    }

    }

    void MENU_PULSADO(){
    INTERRUPCION1=1;
    detachInterrupt(0);
    delayMicroseconds(1000);
    ActualizaHora=true;
    act=act+1;

    }
    void REFRESCO(){

    puntero_fecha=reloj.cargar_fecha_hora();

    lcd.setCursor(0,0);
    //
    if(HORA<10) lcd.print("0");
    lcd.print(HORA);
    lcd.print(":");

    lcd.print(MINUTO);
    lcd.print(" ");

    lcd.print(DIA);
    lcd.print("/");

    lcd.print(MES);
    lcd.print("/20");

    lcd.print(ANO);
    lcd.print(" ");

    delay(100);

    }

  13. salvador

    joder con el tio pepe

    le he puesto formato pero el reloj no funciona siempre muestra lo mismo pero si que actua y me puedo comunicar

  14. Alfonso de Tavernes

    No sé quue mas decir de lo que ya se ha dicho, pero por mi parte MUCHÍSIMAS GRACIAS,por este supertrabajo que compartes con nosotros sin pedir nada a cambio.
    Todavía, no lo he probado, perogracias por adelantado y en cuanto lo pruebe te comento.

  15. Alfonso de Tavernes

    Hola Victor:
    He probado y no consigo que me funcione bien.
    Primero no me saca nada por el puerto serie, pero el puerto funciona que lo he probado.
    Comentando este trozo de código, ya me imprime en el puerto serie, pero esto es lo que me sale:
    Contenido de la posicion 0 del buffer de la fecha -> -91
    Contenido de la posicion 1 del buffer de la fecha -> -91
    Contenido de la posicion 2 del buffer de la fecha -> 45
    Contenido de la posicion 3 del buffer de la fecha -> 7
    Contenido de la posicion 4 del buffer de la fecha -> 45
    Contenido de la posicion 5 del buffer de la fecha -> 25
    Contenido de la posicion 6 del buffer de la fecha -> -91
    El dia 45/25/20-91, domingo, a las 45:-91:-91
    (4409 en un reloj de 4 digitos y 20-91-25-45 45:-91:-91 segun MySQL o -91254545-91-91 abreviadamente)
    la temperatura era de -127.75 grados centigrados

    H probado con dos ordenadores distintos, con dos arduinos distintos y con dos DS3231 y siempre me hace lo mismo.

    Si me puedes orientar, te lo agradezco.

    • Víctor Ventura

      Hola, Alfonso.

      La salida que me muestras tiene pinta de no tener un valor correcto en el DS3231, no está en hora o no se ha leído correctamente. Pueden ser muchas cosas, la más típica es un bus I2C mal configurado o mal conectado. Pero me haría falta más información para poder orientarte.

      ¿Qué parte del código has comentado? ¿Por qué la has comentado, es que daba algún error? De ser así ¿Qué error mostraba?

  16. Alfonso de Tavernes

    Ante todo gracias y perdón por la tardanza, el trabajo no me deja mas tiempo.

    El código comentado es este

    y lo comenté porque no me sacaba nada por el puerto serie.

    • Víctor Ventura

      Hola, Alfonso.

      Empezando por el final: no te salía nada por el puerto serie porque la temperatura es incorrecta. Como el DS3231 necesita unos segundos para estabilizarse y solamente después da lecturas correctas, el ejemplo verifica que la temperatura esté entre los márgenes correctos para verificar que sea correcta. Como las lecturas que estás obteniendo no son correctas, no las mostraba (ni la temperatura ni la fecha y la hora).

      Supongo que, por simplificar, no has incluido las líneas 58 y 59, que también deben estar comentadas o no compila. Lo incluyo corregido por si sirve de ayuda a alguien que nos lea, aunque no aconsejo que se utilice este código para nada que no sea experimentar.

      Por la salida que mostraba tu comentario anterior y por lo que ahora explicas de las líneas comentadas, tengo claro que el problema es el DS3231; puede que no esté en hora, pero lo que es casi seguro es que la comunicación I2C no está funcionando. Puede ser hardware (lo más probable) ya sea porque el módulo está averiado, ya sea porque está mal conectado (cables confundidos). Puede ser software (mucho más raro) porque la librería no sea la correcta (versión, placa usada…)

      Espero que esto te ayude un poco. Gracias por participar en polaridad.es

  17. Fernando

    Muy bueno tu blog. Saludos desde Chile.
    Por favor publica la libreria wire.h que no la he podido bajar.

  18. Hugo Nuñez Diaz

    Estimado.

    Agradezco tu valiosa ayuda para ir introduciéndose cada día más en el fascinante mundo de la programación de Arduino.
    Tengo una consulta : Cuando realizo la compilación del primer programa, me da el siguiente mensaje de error;
    C:\Users\EMPERA~1\AppData\Local\Temp\build1096300866751125727.tmp/core.a(main.cpp.o): In function main':
    C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:40: undefined reference to
    setup’
    C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:43: undefined reference to `loop’
    collect2: error: ld returned 1 exit status
    Error de compilación

    Me podrías indicar cual puede ser el problema.
    Gracias de Antemano.
    Saludos.

    • Víctor Ventura

      Hola, Hugo.

      El error que mandas es el típico de no estar compilando un programa de Arduino bien formado, no parece tener nada que ver con la librería para el DS3231.

      ¿Puede ser que estés intentando compilar la librería sin un programa de Arduino que la utilice?

      Saludos.

  19. Leovigildo

    Interesante blog pero,…¡Qué tipografía tan rara e incómoda de leer!

  20. RUDYARD BARCENA DIAZ

    HOLA VICTOR TU TRABAJO ES TREMENDO, YA DESCARGUE LA LIBRERIA DEL DS3231
    ¿QUE TENGO QUE HACER PARA QUE CAMBIE EL HORARIO DE VERANO Y DE INVIERNO EN FORMA AUTOMATICA?

  21. Jesus Corona

    Saludos, este website esta excelente. Mi pregunta es: ¿cómo eliminar los decimales de la temperatura en el DS3231?, por el momento los considero innecesarios ya que los datos los estoy mostrando en una LCD 1602 TWi/I2C y dichos decimales me quitan espacio para mostrar unidad de temperatura. Gracias de antemano por la ayuda que puedas prestar.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *