Reloj en tiempo real, Real Time Clock RTC, para Arduino con Dallas DS1307
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 (0×00 – 0×07) 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:

- 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 y 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.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
/* * RELOJ EN TIEMPO REAL, REAL TIME CLOCK RTC, PARA ARDUINO CON DALLAS DS1307 * Código fuente, lista de materiales, esquema eléctrico, fotolito y video de fabricación en: http://giltesa.com/?p=6967 http://www.youtube.com/watch?v=qI9qF5UUJr4 * El siguiente código lee la hora proporcionada por el Dallas DS1307. * También se incluye el código de puesta en hora, para su correcto uso seguir sus anotaciones. * Proyecto inspirado en: http://hispavila.com/3ds/atmega/ds1307reloj.html http://yopero-tech.blogspot.com/2011/04/real-time-clock-para-arduinods1307.html http://www.bristolwatch.com/arduino/arduino_ds1307.htm http://picnote.blogspot.com/2009/01/square-wave-output-from-ds1307.html http://www.henningkarlsen.com/electronics/library.php?id=34 http://www.maxim-ic.com/app-notes/index.mvp/id/95 */ // Se carga la librería que permite realizar la comunicación de datos a través del protocolo I2C. Para ello se usa el pin A4 para datos y el A5 para sincronizar los ciclos de reloj. http://arduino.cc/es/Reference/Wire #include <Wire.h> // 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 // Se define una constante con el método de C en vez del de Arduino con: CONST NOMBRE = VALOR; Es lo mismo aunque es preferible usar la palabra clave CONST, El valor que se guarda, creo, es el tamaño de la memoria VRAM del DS1307. #define DS1307_I2C_ADDRESS 0x68 /* FUNCIONES ************************************************/ /* El DS1307 trabaja en binario decimal codificado BCD, esto quiere decir que toda la información que le mandemos o recibamos deberemos de tratarla antes. Con BCD podemos representar nuestros 10 números decimales usando 4 bits por número a representar, Por ejemplo si quisiéramos grabar el día 25 al reloj, deberemos de pasarlo a BCD: 25 > 0010 0101 , como se puede observar son dos grupos de 4 bits, un grupo por digito decimal pues esta en BCD, no confundir con binario real que seria: 11001 Tabla Decimal - BCD: 0 0000 1 0001 2 0010 3 0011 4 0100 5 0101 6 0110 7 0111 8 1000 9 1001 Las dos siguientes funciones se encargan de hacer esa traducción entre los sistemas de numeración mencionados por lo que no tenemos que preocuparnos de nada, lo anterior era meramente informativo ;) */ // De Decimal a BCD byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); }; // De BCD a Decimal byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); }; // La siguiente función al ser llamada recoge los datos del DS1307. void getDateDs1307( byte *segundos, byte *minutos, byte *hora, byte *diaDeLaSemana, byte *diaDelMes, byte *mes, byte *anio ){ // Se inicia la comunicación con el reloj, se preparan los bytes a transmitir, se transmiten además de cerrarse la conexión, y se recogen los 7 primero bytes. Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 7); //Ahora de forma consecutiva se guardan los datos recogidos y se almacenan en sus variables correspondientes. // Algunas de las variables se necesitan enmascarar porque ciertos bits son bits de control. *segundos = bcdToDec(Wire.receive() & 0x7f); *minutos = bcdToDec(Wire.receive()); *hora = bcdToDec(Wire.receive() & 0x3f); *diaDeLaSemana = bcdToDec(Wire.receive()); *diaDelMes = bcdToDec(Wire.receive()); *mes = bcdToDec(Wire.receive()); *anio = bcdToDec(Wire.receive()); }; // Esta otra función pone el reloj en hora con los datos que le hayamos pasado a mano desde el VOID SETUP() void setDateDs1307( byte segundos, byte minutos, byte hora, byte diaDeLaSemana, byte diaDelMes, byte mes, byte anio ){ Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.send(decToBcd(segundos)); Wire.send(decToBcd(minutos)); Wire.send(decToBcd(hora)); Wire.send(decToBcd(diaDeLaSemana)); Wire.send(decToBcd(diaDelMes)); Wire.send(decToBcd(mes)); Wire.send(decToBcd(anio)); Wire.endTransmission(); }; /************************************************ FUNCIONES */ void setup(){ // 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); // Se declaran las variables de tiempo: segundos, minutos, etc. byte segundos, minutos, hora, diaDeLaSemana, diaDelMes, mes, anio; // Se inicia la librería Wire y se configura el bus I2C. Wire.begin(); // Se ajusta la salida de datos del puerto serie a 9600 baudios, comentarlo si se usa con una pantalla. Serial.begin(9600); /* 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); */ }; void loop(){ // Se declaran las variables de tiempo: segundos, minutos, etc. byte segundos, minutos, hora, diaDeLaSemana, diaDelMes, mes, anio; // Ejecuta la función getDateDs1307 para recibir los datos actualizados. getDateDs1307(&segundos, &minutos, &hora, &diaDeLaSemana, &diaDelMes, &mes, &anio); // El siguiente código es opcional, pues sirve para mostrar la hora desde el puerto serie: // Serial.print(valor) Imprime la información. // Serial.println(valor, formato) Imprime la información e incluye un retorno de carro. // HORA Serial.print("Son las "); //if (hora < 10) Serial.print("0"); Serial.print(hora, DEC); Serial.print(":"); if (minutos < 10){ Serial.print("0"); }; Serial.print(minutos, DEC); Serial.print(":"); if (segundos < 10){ Serial.print("0"); }; Serial.print(segundos, DEC); Serial.print(" del "); // FECHA switch (diaDeLaSemana){ case 1: Serial.print("Lunes "); break; case 2: Serial.print("Martes "); break; case 3: Serial.print("Miercoles "); break; case 4: Serial.print("Jueves "); break; case 5: Serial.print("Viernes "); break; case 6: Serial.print("Sabado "); break; case 7: Serial.print("Domingo "); break; }; if (diaDelMes < 10){ Serial.print("0"); }; Serial.print(diaDelMes, DEC); Serial.print(" de "); switch (mes){ case 1: Serial.print("enero"); break; case 2: Serial.print("febrero"); break; case 3: Serial.print("marzo"); break; case 4: Serial.print("abril"); break; case 5: Serial.print("mayo"); break; case 6: Serial.print("junio"); break; case 7: Serial.print("julio"); break; case 8: Serial.print("agosto"); break; case 9: Serial.print("septiembre"); break; case 10: Serial.print("octubre"); break; case 11: Serial.print("noviembre"); break; case 12: Serial.print("diciembre"); break; }; Serial.print(" del "); Serial.print("20"); if (anio < 10){ Serial.print("0"); }; Serial.println(anio, DEC); // Parar el programa un segundo y repetir el Loop delay(1000); }; |



te ha quedado de lujo, felicidades… cuando me tenga que haceru uno ya se donde buscar como hacerlo
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
Muy útil, voy a implementarlo en una matriz de led
y que pasa si uso otro cristal?
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.
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.
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.
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:
Y también borra:
Saludoss
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.
Te dejo el link del reloj con el cual trabajo. http://www.olimex.cl/product_info.php?products_id=187&product__name=Reloj_de_Tiempo_Real
Saludos
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 :-/
Saludos desde españa
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..
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
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
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.
O a bajarte de nuevo el IDE, quizás se hayan mezclado algunos ficheros y por eso los errores.
Saludos.
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
Acabo de probar la librería y si, da muchos problemas tanto en un ide como en el otro. No se cual puede ser la causa.
Sin embargo tienes otra librería más, es la “RTClib.h”, la acabo de probar con la consola serial y va perfecta, prueba a ver si con esa consigues que funcione el reloj.
Código: http://www.ladyada.net/learn/breakoutplus/ds1307rtc.html
Librería: https://github.com/adafruit/RTClib
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
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.
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
Hola, seria algo asi:
Saludos.
Ahora funciona bien, solo me faltaba utilizar doble = (==) en la setencia if, me parece que se debe al tipo de variable (Byte). Saludos
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
Perdonoa por molestarte pero estoy con el relog para arduino y necesito el esquema para plancharlo en placa con su tamaño original no lo tendras por casualidad ,gracoias
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
[...] Reloj en tiempo real DS1307 [...]
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
por cierto la librería que utilizo es la misma del compañero bertifox
Hola,
Si tienes problemas con la librería yo cree una que hasta ahora me ha ido bien, aunque es para el IDE 0022.
http://giltesa.com/2012/09/02/libreria-gds1307-para-rtc/
Si es con algo concreto solo tienes que preguntar, a ver si te puedo ayudar.
Saludos!