Reloj en tiempo real, Real Time Clock RTC, para Arduino con Dallas DS1307

Arduino RTC giltesa

Debido a que nuestro Arduino no cuenta con reloj en tiempo real para saber la hora, dia, año, etc. no podremos hacer proyectos como un reloj-despertador con una pantalla LED/LCD, programar tareas a determinadas horas, y por lo que he leído también es necesario para algunos protocolos de comunicación.

Por ello en esta entrada vamos a ver como crear nuestro reloj, si bien estos se encuentran fácilmente en ebay por menos de 10€, he preferido hacerlo a mano debido a que necesito dos unidades y los materiales totales salen más baratos que comprar 2 relojes ya construidos, ademas aprenderemos más que si lo compramos hecho 😉

El primero lo integrare en mi prototype shield junto a un buzzer, un vibrador y dos switch DIP para liberar los pines de todo lo anterior si lo necesitase.
El segundo lo construiré en un PCB aparte para usarlo de forma independiente en cualquier proyecto.

Materiales necesarios para construir 1 unidad:

  • 1 PCB 30*16mm.
  • 4 Pines macho para la conexión entre el PCB y el Arduino.
  • 1 PIC Dallas DS1307  *
  • 1 Cristal de cuarzo de 32.768 kHz.
  • 2 Resistencias de 2200Ω  *
  • 1 Resistencia de 220Ω  *
  • 1 Led *
  • 1 Pila de botón de 3V y su correspondiente portapilas CR1220  *

* Los componentes son en formato SMD.

El Dallas DS1307 es un reloj que nos proporciona la hora, minutos y segundos así como el día, mes y año. Además cuenta con un calendario que le permite ajustar automáticamente la fecha en meses con menos de 31 días o años bisiestos hasta fin de siglo, 2100. También cuenta con una pequeña memoria SRAM de 64 bytes de los cuales los 8 primeros bytes (0x00 – 0x07) son usados por el reloj y el resto como memoria adicional.

El chip se comunica al Arduino mediante el protocolo  de comunicación en serie I²C, este es soportado por el IDE de Arduino y contamos con la librería Wire para ello.

Para realizar el conexionado debemos de hacerlo de la siguiente forma:

PIC DS1307

  • En el pin 1 y 2 del chip conectamos el cristal de cuarzo.
  • En el pin 3 el polo positivo de la pila y en el pin 4 la masa, GND.
  • El pin 5 lo uniremos por un lado a una de las resistencias de 2200Ω  que a su vez se unirá al pin de 5V del Arduino, por el otro lado lo uniremos al 4 pin analógico del Arduino.
  • El pin 6 es parecido, por un lado a la segunda resistencia de 2200Ω y a su vez a los 5V, y por el otro lado al pin 5 analógico.
  • El 7 se puede usar como salida (configurable por software), para por ejemplo tener un segundero luminoso.
    Por un lado lo uniremos a la resistencia de 220Ω y a su vez a los 5v, por el otro lado al led y este a masa.
  • Y el 8º y ultimo pin lo conectaremos a los 5V

El esquema eléctrico seria el siguiente:

Protoboard | Esquema | Fotolito (PSD)

Hay que tener en cuenta que  el esquema como el fotolito están pensados para componentes de superficie por lo que de usarlos deberemos usar componentes adecuados, el protoboard  sin embargo si muestra componentes THT.

Durante el montaje me dio por grabarlo con la cámara y así documentar un poco más el proyecto. El primer vídeo muestra el montaje de los componentes y el segundo la puesta en marcha del reloj y prueba mediante conexión serie, en los próximos proyectos mostrare la hora en matrices de leds y/o LCDs.

Y por ultimo el código el cual esta programado para mostrar la hora por el puerto serie. Para hacer funcionar el Led he necesitado usar la librería DS1307.h ya que sin ella no he sabido usarlo, es para lo único que la uso por lo que si se decide prescindir del Led se puede borrar el código señalado.

41 comentarios en “Reloj en tiempo real, Real Time Clock RTC, para Arduino con Dallas DS1307”

    1. Gracias, aunque me tendré que mirar lo de la librería DS1307.h, creo que usándola ira más fino que haciendo los cálculos “a mano”.
      Nos vemos por fc 😛

    1. Si usas otro cristal tendrás un reloj que no funcionara en tiempo real, que un minuto no serán 60 segundos, quizás sean 80 segundos o 20 segundos, y un segundo no serán mil milisegundos…

      De hecho los cristales nunca son de la frecuencia exacta que te indican, se aproximaran más o menos pero jamas son exactos, dependiendo de la calidad sera más exacto, y mientras más exacto sea mejor sera la hora, con un buen cristal quizás te atrasa/adelanta un segundo cada año o más, con uno malo quizás pierdes un par de minutos a la semana, al dia, a la hora…

      En resumen, el cristal ha de ser de 32.768 kHz y de calidad.

      Saludos.

  1. Hola, antes que nada felicitaciones por tu trabajo, en mi caso compre el circuito ya hecho, lo conecte como indicas y logre obtener los datos en el monitor solo que todos en 0, necesito poner el reloj a la hora y no logro hacerlo, he seguido al pie de la letra tu codigo, tienes algun comentario al respecto. Saludos.

    1. Si lo tienes todo configurado aunque no lo hayas puesto en hora deberías de ver la hora por defecto, creo que empieza a contar en el año 2000…
      Mira de todas formas en el setup que hayas descomentado las variables que modifican la hora, tienes que grabar el código con las variables descomentadas para poner el reloj en hora y después grabarlo de nuevo con las variables descomentadas para que no se ponga en esa hora cada vez que enciendes el arduino.

      [c]
      /* PUESTA EN HORA DEL DS1307.
      La primera vez que enchufemos el reloj lo deberemos de poner en hora, de igual modo si la batería se agotase o si conectásemos incorrectamente los pines del reloj al Arduino, esto ultimo podría causar un bloqueo del reloj solucionable mediante una actualización de la hora.
      Para ello se debe descomentar las siguientes líneas de código, editar los valores de las variables por la hora y fecha actual. Después grabaremos el programa en el Arduino, comentaremos de nuevo el código siguiente y lo volveremos a grabar en el Arduino. Esto es así debido a que si lo dejáramos descomentado cada vez que encendiésemos el reloj este actualizaría sus registros con una hora y fecha, ahora ya, obsoleta.
      */
      /*
      segundos = 00; // 0-59
      minutos = 18; // 0-59
      hora = 07; // 1-23
      diaDeLaSemana = 7; // 1-7
      diaDelMes = 18; // 1-28/29/30/31
      mes = 9; // 1-12
      anio = 11; // 0-99

      // Ejecuta la función setDateDs1307 encargada de actualizar la hora.
      setDateDs1307(segundos, minutos, hora, diaDeLaSemana, diaDelMes, mes, anio);
      */
      [/c]

      Si has hecho eso se me hace raro que no te funcione, prueba por si acaso lo siguientes:
      De mi código, borra las lineas:

      [c]
      // La siguiente librería es opcional, es la que normalmente se usaría para controlar el DS1307, en este código se pretendía no usarla, sin embargo el Led azul de la placa solo he podido usarlo como segundero mediante la librería. Si no se usa el pin 7 del reloj se puede obviar el código siguiente y el del VOID SETUP()
      #include <DS1307.h> //Libreria
      DS1307 rtc(A4, A5); //Pines de datos
      [/c]

      Y también borra:

      [c]
      // Esta es la otra parte del código encargada del Led como segundero, comentar si no se usase.
      rtc.halt(false);
      rtc.setSQWRate(SQW_RATE_1); // Solo se puede variar por los valores: SQW_RATE_1 , SQW_RATE_4K , SQW_RATE_8K , SQW_RATE_32K
      rtc.enableSQW(true);
      [/c]

      Saludoss

    2. Gitesa muchas gracias por responder, todo lo que tu me indicas ya lo he probado, es verdad que me indica hora 00.00 año 2000, si esta leyendo el reloj debería tambien grabar, te cuento que mi profesion es programador de computadoras por lo cual se me hace mas facil entender los codigos, pero en la electronica algo entiendo, me apasiona poder desarrollar proyectos en arduino, este es mi primer proyecto debo activar y desactivar dos switch, dependiendo de la hora y el dia de la semana, ademas debo considerar los festivos de mi pais, esto lo tengo muy claro como hacerlo solo me falta poner el reloj a la hora.

      Saludos desde La Serena-Chile.

    3. Estamos igual pues, yo también soy(seré) programador y en la electrónica se lo básico. Como te comento se me hace raro que no funcione, el código es bastante simple y el modulo que estas usando usa el mismo chip que use yo, vamos es todo igual.

      Puedes probar a usar la librería DS1307.h. En mi caso la use solo para poder usar el pin de salida del ds1307 como segundero con un led. Pero la librería te permite usar el reloj por completo, quizás mi código (que esta basado en otros códigos…) no sea perfecto, seguramente la librería que te comento si lo este. Si aun así no te funcionase prueba con otro Arduino, o quizás el modulo de reloj este en mal estado :-/

      [c]
      // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235070596/all
      #include <WProgram.h>
      #include <Wire.h>
      #include <DS1307.h>

      int rtc[7];

      void setup()
      {
      Serial.begin(9600);
      /*
      RTC.stop();
      RTC.set(DS1307_SEC,1);
      RTC.set(DS1307_MIN,57);
      RTC.set(DS1307_HR,17);
      RTC.set(DS1307_DOW,4);
      RTC.set(DS1307_DATE,18);
      RTC.set(DS1307_MTH,2);
      RTC.set(DS1307_YR,9);
      RTC.start();
      */
      }

      void loop()
      {
      RTC.get(rtc,true);

      for(int i=0; i<7; i++)
      {
      Serial.print(rtc[i]);
      Serial.print(" ");
      }
      Serial.println();

      delay(1000);

      }
      [/c]

      Saludos desde españa 😉

    4. Giltesa, colega, no sabes cuanto me sirve tu ayuda, tengo la librería DS1307.h pero no se en que carpeta debo ponerla pues al compilar no la encuentra, sabes donde debo ubicar dicha libreria.

      Mil gracias..

    5. En el directorio de instalacion de Arduino tienes una carpeta llamada “libraries”, copias dentro el fichero.h y ya esta.
      Si estas usando linux entones lo tienes en el directorio: /usr/shares/arduino/libraries
      Y a una muy mala, puedes añadir la librería mediante una ruta relativa así:
      #include “DS1307.h” //Y la libraría colocada en el directorio del .pde/.ino

      Saludoss

    6. Gitesa nuevamente gracias, sabes que efectivamente tengo el DS1307.h en libraries incluso en una carperta DS1307, pero a pesar de esto no encuentra el archivo y me arroja los siguientes errores:

      sketch_mar19a.cpp:4:20: error: DS1307.h: No such file or directory
      sketch_mar19a.cpp: In function ‘void loop()’:
      sketch_mar19a:25: error: ‘RTC’ was not declared in this scope

      Esto es muy extraño, te informo te utilizo Windows 7, Arduino version 0023, necesito programar en encendido/apagado de dos reles, dependiendo de la hora y el día de la semana.

      Saludos

  2. Hola,

    Prueba usando la versión 1.0 del IDE, o a poner la librería DS1307.h con una ruta relativa y no desde las libreras del IDE.
    [c]#include "DS1307.h"[/c]
    O a bajarte de nuevo el IDE, quizás se hayan mezclado algunos ficheros y por eso los errores.

    Saludos.

    1. Hola, instale la version 1.0 rc2, al parecer ahora si tomo la librería solo que me da otros errores de variables, debe ser que mi archivo DS1307.h fue cambiado, yo lo baje ya no se de donde, si fueses tan amable de enviarme tu archivo, te lo agradezco inmensamente, mi email es berty.cortes@intelsoft.cl.

      Estos son los mensajes de errores de compilacion:.

      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:65: error: ‘boolean’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:66: error: ‘boolean’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:67: error: ‘boolean’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:71: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:72: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:73: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:74: error: ‘byte’ does not name a type
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:75: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:76: error: ‘byte’ does not name a type
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:77: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:77: error: ‘byte’ has not been declared
      C:UsersBertyarduino-1.0-rc2librariesDS1307/DS1307.h:80: error: ‘byte’ does not name a type

    2. Justamente estaba en eso, el compilador funciona perfecto, pero no logro poner la hora y fecha, creo que existe algún problema con el hardware tratare de cambiarlo, Te agradezco tus respuestas.

      Saludos

    3. Les informo que solucione el problema de la puesta a la hora del reloj DS1307, resulta que yo estaba utilizando los pines 3 y 4, esto es para Arduino Uno, en mi caso tengo Arduino Mega por lño tanto utilice los pines 20 y 21 SDA y SCL respectivamente y funciona perfecto.

    4. Giltesa, necesito hacerte otra consulta, te cuento que yo estoy inscrito en el foro de Arduino pero no logro abrir un nuevo hilo como para hacer consultas, mira se trata que debo preguntar en el programa si el la hora es mayor a las 22:00 debo apagar el pin 1.

      if (Hora = 22) && (Minutos > 0) Aqui poner las instrucciones de apagar pin 1

      Pero resulta que el compilador me arroja error en el if, al parecer es por tipo de datos de las variables que son Byte, entonces debo convertir de Byte a Int, no encuentro como se hace, tienes alguna idea?.

      Saludos cordiales

    5. Hola, seria algo asi:

      [c]
      // Apagar la luz a las 22:00 PM
      if( estadoLuz == true && hora == 22 && minutos == 0 && segundos == 0 )
      {
      digitalWrite( pinLuz, LOW );
      estadoLuz = false;
      }
      [/c]

      Saludos.

    6. Ahora funciona bien, solo me faltaba utilizar doble = (==) en la setencia if, me parece que se debe al tipo de variable (Byte). Saludos

    7. No, el signo de comparación es ese en Arduino (Procesign) y otros muchos lenguajes: C, C++,Java, Javascript, PHP. Solo, de los que conozco, en Ada es un = y no dos, claro que el de asignación no es =, si no :=

      Y todas las condiciones se ponen dentro del paréntesis, nada de poner varios paréntesis y en cada uno de ellos una condición…

      Saludoss

    1. Hola, molestia ninguna!

      Tienes adjunto el fichero PSD, lo abres con el Photoshop y lo tienes listo para imprimir.

      Te podría facilitar también el fichero del esquema pero lo hice con otro programa distinto de eagle, concretamente con Sprint Layout.

      Pero ya te digo que con el PSD debería de poder imprimir el fotolito en el tamaño adecuado. Si tienes cualquier problema solo tienes que preguntar!

      Saludoss

  3. muy buenas saludos desde el salvador =D necesitaba hacerles algunas consultas mi caso es contrario al de ustedes, el hardware lo manejo a la perfección pero el firmware aun estoy como en un 50% quería saber si me puedes ayudar con algunas pequeñas dudas

  4. Lo primero felicidades por esta pedazo de web y todo el conocimiento que comprates desinteresadamente aqui y en FC.

    Estoy planteandome en comprar un RTC como el que comentas, pero tengo duda si es estrictamente necesario en proyectos “horarios”. Me explico, en mi proyecto quiero programar la activación de ciertos relés a horas concretas.
    He hecho pruebas con los ejemplos que existe usando NTP, es decir, que coja la hora de Internet de los servidores de hora. NTP funciona bien en Arduino (aunque coge la hora GMT y aqui es GMT +1, algo sencillo de corregir), y me pregunto si merece la pena incluir otro shield más, me refiero, que aunque sea barato hay que comprarlo, tener que incluir librerías y bastante código solo para eso, mientras existe NTP.

    ¿Con cual de los dos métodos resulta más sencillo o necesita menos líneas a la hora de comparar horas para por ejemplo actuar dependiendo de esas comparaciones?

    Gracias

    1. Hola,

      Me alegro de que te sirva el contenido que publico.

      Pues si te funciona bien obtener la hora por NTP yo me quedaría con esa opción, porque vas a tener siempre la hora sincronizada y ahorras en módulos como dices.

      Porque el DS1307 de esta entrada y un modulo comprado, ambos se retrasan unos minutos cada semana y es un coñazo la verdad. Si no tuvieras internet entonces podrías usar un modulo pero mejor otro mas preciso como el DS3231… pero teniendo internet mejor por NTP sin duda, bueno, si el proyecto es critico y necesita tener siempre la hora podrías poner un reloj por si se quedara sin internet y por tanto sin NTP.

      El NTP no lo he probado aun pero imagino que la librería de ethernet sera mas pesada que la del reloj, pero imagino que también usaras internet para mas cosas no solo para eso.
      Para comparar horas pues ya dependerá de como te de los datos el NTP, si te da cada dato suelto (como el DS1307) pues para comparar horas serán 3 condiciones en un if, no debería de ser complicado ni largo el código.

      Saludos!

    1. Hola,
      Se debe principalmente a los cambios de temperatura que afectan al resonador y hacen que la frecuencia no sea todo lo exacta que debería y con ello la hora se adelanta o atrasa.
      Bueno, a eso y a que el reloj es de los mas baratos 😉

      Si necesitas algo muy preciso es mejor que uses un DS3231 ya que tiene su propio resonador interno y también un sensor de temperatura para poder autocompensarse él mismo.

      Saludos!

  5. Perdona pero al correr el programa en arduino me informa que falta la libreria RTC.h y ya me descargue todas las de la pagina que me pasaste las copie en la carpeta de arduino en librerias y nada sigue faltando la rtc.h

    1. Hola Berak,

      Mi librería no es compatible con ese reloj ya que solo es para modelos con comunicación I2C como el DS1307 o el DS3231, el tuyo usa otro tipo de comunicación.

      Saludos.

  6. Hola soy nuevo con esto de Arduino, ya estuve leyendo tus tutoriales muy buenos por cierto.
    tengo este código y deseo habilitar una salida a varios tiempos.

    Pudieras auxiliarme..

    #include
    #include
    #include “RTClib.h”

    LiquidCrystal lcd(1, 2, 4, 5, 6, 7);//pines del arduino al LCD (RS E D4 D5 D6 D7) RESPECTIVAMENTE
    RTC_DS1307 RTC;

    void setup()
    {
    Wire.begin(); //configura el bus I2C estableciendo arduino como MASTER
    RTC.begin();
    if (! RTC.isrunning()) // se verifica si el modulo rtc esta en funcionamiento, de lo contrario, se imprime: RTC is NOT running!
    {
    lcd.println(“RTC is NOT running!”);
    delay(10000);
    }
    RTC.adjust(DateTime(__DATE__, __TIME__)); //esta funcion establecera en el modulo la fecha de creación del archivo .hex generado al compilar el sketch.

    lcd.begin(16,2);
    lcd.clear();
    }

    void loop()

    {
    Data d = rtc.getData();
    Serial.println( d.toString(“Y/m/d H:i:s”) );// Puede borrarse

    // Evento que se repite cada 15 segundos:
    if( d.seconds % 15 == 0 )
    }
    mostrarRTCLCD(); //Se manda a llamar la funcion “mostrarRTCLCD” y despues se espera un tienpo de 1seg
    delay(1000);

    void mostrarRTCLCD() //Funcion que lee los datos de modulo RTC y despues los imprime en el display
    {
    DateTime now = RTC.now(); //obtiene datos del modulo RTC
    lcd.clear();
    lcd.setCursor(3,0);
    if(now.day() < 10)
    {
    lcd.print("0");
    }
    lcd.print(now.day(), DEC); //imprime dia
    lcd.print('/');
    if(now.month() < 10)
    {
    lcd.print("0");
    }
    lcd.print(now.month(), DEC); //imprime mes
    lcd.print('/');
    lcd.print(now.year(), DEC); //imprime el año
    lcd.setCursor(4,1);
    if(now.hour() < 10)
    {
    lcd.print("0");
    }
    lcd.print(now.hour(), DEC); //imprime hora
    lcd.print(':');
    if(now.minute() < 10)
    {
    lcd.print("0");
    }
    lcd.print(now.minute(), DEC); //imprime minutos
    lcd.print(':');
    if(now.second() < 10)
    {
    lcd.print("0");
    }
    lcd.print(now.second(), DEC); //imprime segundos
    }

Escriba aquí su comentario