
¿Qué es un reloj de tiempo real RTC?
Un reloj de tiempo real (RTC) es un dispositivo electrónico que permite obtener mediciones de tiempo en las unidades temporales que empleamos de forma cotidiana.
El término RTC se creó para diferenciar este tipo de relojes de los relojes electrónicos habituales, que simplemente miden el tiempo contabilizando pulsos de una señal, sin existir relación directa con unidades temporales.
Por el contrario los RTC son más parecidos a los relojes y calendarios que usamos habitualmente, y que funcionan con segundos, minutos, horas, días, semanas, meses y años.
Los RTC normalmente están formados por un resonador de cristal integrado con la electrónica necesaria para contabilizar de forma correcta el paso del tiempo. La electrónica de los RTC tienen en cuenta las peculiaridades de nuestra forma de medir el tiempo, como por ejemplo el sistema sexagesimal, los meses con diferentes días, o los años bisiestos.
Anuncio:
Los RTC aportan la ventaja de reducir el consumo de energía, aportar mayor precisión y liberar a Arduino de tener que realizar la contabilización del tiempo. Además, frecuentemente los RTC incorporan algún tipo de batería que permite mantener el valor del tiempo en caso de pérdida de alimentación.
En el mundo de la electrónica casera y Arduino existen dos RTC habituales el DS1307 y el DS3231, ambos fabricados por Maxim (anteriormente Dallas Semiconductor). El DS3231 tiene una precisión muy superior y puede considerarse sustituto del DS1307.
En el modelo DS1307 las variaciones de temperatura que afectan a la medición del tiempo de los cristales resonadores se traducen en errores en un desfase acumulado. Esto hace que el DS1307 sufra de un desfase temporal, que puede llegar a ser 1 o 2 minutos al día.
Para solucionarlo, el DS3231 incorpora medición y compensación de la temperatura garantizando una precisión de al menos 2ppm, lo que equivale a un desfase máximo 172ms/día o un segundo cada 6 días. En el mundo real normalmente consiguen precisiones superiores, equivalente a desfases de 1-2 segundos al mes.
La comunicación en ambos modelos se realiza a través del bus I2C, por lo que es sencillo obtener los datos medidos. La tensión de alimentación es 4.5 a 5.5 para el DS1307, y 2.3 a 5.5V para el DS3231.
Frecuentemente estos módulos también incorporan una pequeña EEPROM AT24C32, que puede ser empleada para almacenar registros y mediciones. En el caso del DS3231, la medición de temperatura también está disponible, aunque tiene una precisión baja ±3ºC, y el tiempo de adquisición puede durar hasta 1 segundo.
También incorporan una batería CR2032 para mantener el dispositivo en hora al retirar la alimentación. Esta batería debería ser capaz de mantener alimentado durante varios años al DS1307, y durante meses al DS3231. La tensión de alimentación de batería es de 2.0 a 3.5 para el DS1307 y de 2.3 a 5.0 para el DS3231.
Los RTC son dispositivos ampliamente utilizados en electrónica. Todos los ordenadores personales, servidores, tablets, y smartphone incorporan uno. También son muy frecuentes en sistemas embebidos y, en general, en multitud de dispositivos que requieren realizar un registro del tiempo.
En nuestros proyectos de electrónica frecuentemente necesitáramos un RTC. Por ejemplo, podemos temporizar el encendido de luces o sistemas de riego, realizar un datalogger, o incluso encender y apagar el propio Arduino para ahorra batería.
Precio
Los RTC son dispositivos muy baratos. Podemos encontrar el DS1307 por 0.50€, buscando en vendedores internacionales en eBay o AliExpress.
El DS3231, el sustituto del DS1307 es actualmente incluso más barato. Podemos encontrarlo por 0.40€.
Dado que el DS3231 es superior en características y tiene un precio inferior lo lógico es que siempre preferiremos los modulos con DS3231 frente al DS1307.
Esquema de montaje
La conexión es sencilla y similar tanto para el DS1307 como el DS3231. Simplemente alimentamos el módulo desde Arduino mediante 5V y Gnd. Por otro lado, conectamos los pines del bus I2C a los correspondientes de Arduino.
La conexión de un módulo con DS1307 sería la siguiente,
Similar a la de un módulo que DS3213, que sería la siguiente,
En ambos casos la conexión, vista desde el lado de Arduino, es la misma, y quedaría así.
Ejemplos de código
Para realizar la lectura del DS1307 y del DS3231 usaremos la librería desarrollada por Adafruit válida para ambos modelos, disponible en este enlace. La librería proporciona ejemplos de código, que resulta aconsejable revisar.
Obtener la fecha y hora
El primer ejemplo emplea el RTC para obtener los datos de fecha y hora actual. Posteriormente se emplean estos valores para mostrarlos por puerto serie. También se muestra como fijar la fecha y la hora, y detectar la perdida de energía.
#include <Wire.h> #include "RTClib.h" // RTC_DS1307 rtc; RTC_DS3231 rtc; String daysOfTheWeek[7] = { "Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado" }; String monthsNames[12] = { "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre" }; void setup() { Serial.begin(9600); delay(1000); if (!rtc.begin()) { Serial.println(F("Couldn't find RTC")); while (1); } // Si se ha perdido la corriente, fijar fecha y hora if (rtc.lostPower()) { // Fijar a fecha y hora de compilacion rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Fijar a fecha y hora específica. En el ejemplo, 21 de Enero de 2016 a las 03:00:00 // rtc.adjust(DateTime(2016, 1, 21, 3, 0, 0)); } } void printDate(DateTime date) { Serial.print(date.year(), DEC); Serial.print('/'); Serial.print(date.month(), DEC); Serial.print('/'); Serial.print(date.day(), DEC); Serial.print(" ("); Serial.print(daysOfTheWeek[date.dayOfTheWeek()]); Serial.print(") "); Serial.print(date.hour(), DEC); Serial.print(':'); Serial.print(date.minute(), DEC); Serial.print(':'); Serial.print(date.second(), DEC); Serial.println(); } void loop() { // Obtener fecha actual y mostrar por Serial DateTime now = rtc.now(); printDate(now); delay(3000); }
Encendido y apagado programado
El siguiente ejemplo un proyecto habitual, emplear un RTC para activar o desactivar un dispositivo en un horario y fechas determinados. Por ejemplo, puede servir para controlar el riego de un jardín, encender las luces, la calefacción, desplegar un toldo, o controlar cualquier otro dispositivo mediante un relé.
La función IsScheduledON controla el encendido o apagado. En el ejemplo, está programado el encendido los miércoles, sábado, y domingo de 09:30 a 11:30 y de 21:00 a 23:00. Modificando el cuerpo de esta función, podéis programar la condición de encendido y apagado que necesitéis.
#include <Wire.h> #include "RTClib.h" const int outputPin = LED_BUILTIN; bool state = false; // RTC_DS1307 rtc; RTC_DS3231 rtc; void setup() { Serial.begin(9600); delay(1000); if (!rtc.begin()) { Serial.println(F("Couldn't find RTC")); while (1); } if (rtc.lostPower()) { rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } } // Comprobar si esta programado el encendido bool isScheduledON(DateTime date) { int weekDay = date.dayOfTheWeek(); float hours = date.hour() + date.minute() / 60.0; // De 09:30 a 11:30 y de 21:00 a 23:00 bool hourCondition = (hours > 9.50 && hours < 11.50) || (hours > 21.00 && hours < 23.00); // Miercoles, Sabado o Domingo bool dayCondition = (weekDay == 3 || weekDay == 6 || weekDay == 0); if (hourCondition && dayCondition) { return true; } return false; } void loop() { DateTime now = rtc.now(); if (state == false && isScheduledON(now)) // Apagado y debería estar encendido { digitalWrite(outputPin, HIGH); state = true; Serial.print("Activado"); } else if (state == true && !isScheduledON(now)) // Encendido y deberia estar apagado { digitalWrite(outputPin, LOW); state = false; Serial.print("Desactivar"); } delay(3000); }
Datalogger con RTC
El siguiente ejemplo muestra otro caso muy habitual, el empleo de un RTC para generar un Datalogger, es decir, un dispositivo que periódicamente registra la medición de un sensor. En el ejemplo, emplearemos una tarjeta SD para guardar los valores.
Simplemente, obtenemos la fecha, hora, y valor del sensor, que en el ejemplo simulamos con la función readSensor(), y guardamos los datos en la tarjeta con la función logValue(,,).
En un proyecto real podríamos guardar una o varias mediciones, separadas por comas, por ejemplo. También podríamos variar el momento de la medición, que en el ejemplo se realiza cada 10 segundos a, por ejemplo, cuando ocurra un evento, o en ciertas horas del día empleando el propio RTC.
#include <SPI.h> #include <SD.h> #include <Wire.h> #include "RTClib.h" File logFile; // RTC_DS1307 rtc; RTC_DS3231 rtc; void setup() { Serial.begin(9600); Serial.print(F("Iniciando SD ...")); if (!SD.begin(4)) { Serial.println(F("Error al iniciar")); return; } Serial.println(F("Iniciado correctamente")); } // Funcion que simula la lectura de un sensor int readSensor() { return 0; } void logValue(DateTime date, int value) { logFile.print(date.year(), DEC); logFile.print('/'); logFile.print(date.month(), DEC); logFile.print('/'); logFile.print(date.day(), DEC); logFile.print(" "); logFile.print(date.hour(), DEC); logFile.print(':'); logFile.print(date.minute(), DEC); logFile.print(':'); logFile.print(date.second(), DEC); logFile.print(" "); logFile.println(value); } void loop() { // Abrir archivo y escribir valor logFile = SD.open("datalog.txt", FILE_WRITE); if (logFile) { int value = readSensor(); DateTime now = rtc.now(); logValue(now, value); logFile.close(); } else { Serial.println(F("Error al abrir el archivo")); } delay(10000); }
Descarga el código
Todo el código de esta entrada está disponible para su descarga en Github.
Anuncio:
Buenas Luis,
En el programador en función del tiempo, ¿como se podría añadir otra restricción?
Me gustaría poder vincular el booleano estate a la función isScheduledON, para poder crear por ejemplo, otra función con su estate2 para que un segundo led parpadee en función de la temperatura .
Gracias de antemano, un saludo y enhorabuena por la web que esta muy currada.
Alvaro S. Proyecto de ingeniero.
Buenas tardes a todos, les quiero preguntar si me pueden pasar el enlace(o los enlaces) de donde descargaron las librerias, por favor.
Estuve descargando varias y me arrojan un error.
Saludos Cordiales
Hola. Efectivamente el enlace había dejado de funcionar (son enlaces externos, a veces pasa!)
Lo he cambiado para que apunte a la nueva dirección.
Gracias por el aviso!
Hola Luis. Antes de todo agradecerte el curro que te pegas porque te leo (y te copio :P) mucho. Esta vez el código no me acababa de funcionar. En concreto me refiero a la funcion isScheduledON. El problema es que cuando seleccionas la hora en hourCondition se ha de hacer en formato hora en vez de hora.minutos. ya que si no me generaba unos desajustes de 20-30 minutos. Me refiero a: // De 09:30 a 11:30 y de 21:00 a 23:00 bool hourCondition = (hours > 9.30 && hours 9.5 && hours < 11.5) Un usuario del foro de arduino… Read more »
Jajajaa, soy tonto como yo sólo XD. Tienes más razón que un santo, gracias por indicarme la errata.
Arreglado! Un saludo!
Hace referencia a que el RTC ha perdido la energía (lo que implica que se ha desconectado de alimentación, y además no tiene pila)
Por ejemplo, cambiando la definición de hours para que sea
float hours = date.hour() + date.minute() / 60.0 + date.seconds() / 3600;
Y por otro lado, la consiga, en tu caso entre 10, y 10 + 30 / 3600;
Aunque tienes otras opciones, como usar directamente hour(), minute() y seconds() en condicionales, y así te quitas problemas de precisión por la coma flotante
Hola Luis,
El código me ha sido de gran ayuda. Quiero conectar una LCD por I2C junto con el ds3231. Al escanear el código I2C de los diferentes objetos veo que el ds3231 tiene dos códigos, ¿tiene que ver por el lector de temperatura que incorpora?
Muchas gracias por tu trabajo!
¡Genial artículo, gracias Luis!
Por ponerle un pero, sería interesante comentar la posibilidad de incluir la corrección horaria por DST 😉
Buenos días. Gracias por estos tutoriales, gracias a ellos he conseguido hacer domótica en casa y va muy bien, pero tengo el siguiente problema con el ds3231:
conectado al mega tiene tensión mientras la tenga la placa, pero si quito tension a la placa pierde tensión el rtc (le puse la pila lir nueva), que se repone si desconecto los cables de alimentación rtc-mega, es cono si la tensión de la pila se la absorve el mega.
¿podeís ayudarme con esto? Gracias de antemano.
Hola. Yo estoy interesado en este proyecto, además le he puesto a mi arduino uno R3 una sonda de temperatura DS18b20 y el modulo microSD card adapter, con el objetivo de obtener en una tabla dentro de la microSD las temperaturas tomadas cada día y a intervalos de cada hora, pero aún no lo he conseguido, estoy a punto de abandonar.
Si abandonas seguro que no lo consigues! Animo, tienes la entrada del ds18b20 aquí https://www.luisllamas.es/temperatura-liquidos-arduino-ds18b20/ y la de las tarjetas SD aquí https://www.luisllamas.es/tarjeta-micro-sd-arduino/.
Si tienes alguna pregunta puedes usar los comentarios
Hola, Trate de probar el ejemplo de RTC con un DS3231, cuando lo compilo me entrega el siguiente mensaje “El Sketch usa 6558 bytes (20%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 670 bytes (32%) de la memoria dinámica, dejando 1378 bytes para las variables locales. El máximo es 2048 bytes.” y luego no me deja cargarlo a la placa Keystudio UNO. que puedo hacer, he probado muchos codigos y con todos tengo este problema.
sld
Alexis
Hola. Te aconsejaría que empezaras con los tutoriales básicos. Empieza leyendo “nuestro primer programa en Arduino” https://www.luisllamas.es/nuestro-primer-programa-en-arduino/
Buenos días Luís,
Tengo una duda que quizás puedas responderme.
Tengo un DS3231 que quisiera incorporar a un proyecto que estoy desarrollando.
Mi duda es la siguiente:
– El RTC usa la pila en todo momento o solo cuando el sistema no se encuentra alimentado externamente?
– Te refieres a que puede seguir dando servicio (La hora en este caso) varios meses sin alimentación externa?
-Puedo detectar el momento en que la pila está terminándose?
Gracias de antemano y un saludo! 🙂
Hola Josep, – El DS3231 se alimenta de Vin mientras está disponible. Cuando no, pasa automáticamente a la pila. – En teoría, en el datasheet dicen años con una pila. No me atrevería a decir tantos pero meses seguro. – Puedes detectar que se acaba la pila midiendo su voltaje desde Arduino. Pero para eso tiene que estar encendido Arduino, es decir, tener alimentación externa. Vamos, que no sé que montaje tienes en mente, pero ahí puedes tener un problema, al fin y al cabo si tienes Arduino enchufado para que necesitas la pila en el DS3231? Habría que ver… Read more »
Buenas Luis,
¿Existe la posibilidad de que nos aparezca la hora en el formato 00:00:00 y no en 0:0:0? Es decir, que cuando la hora, minuto o segundo tenga un solo caracter, ponga automáticamente el 0 delante. Se me ha ocurrido hacerlo con varios “if” pero aun siendo una tontería si tuviera fácil solución, me encantaría conocerla.
Un saludo y gracias de antemano
Hola Luis,
El RTC DS3231 cambia la hora automáticamente en primavera y otoño?
Gracias por tus tutoriales, me son muy útiles.
Dídac
tengo la misma duda
Buenas Luis.
Tengo un problema en el código, me sale estos errores *** CODE REMOVED ***
¿Cómo los soluciono?
Saludos
El código compila correctamente. Comprueba que lo has copiado bien
Muchas gracias Luis por compartir con nosotros y mas en mi caso que soy newbie en el tema Arduino y sus perifericos. Te mando un abrazo desde Argentina.
Hola Luis.
Al ejecutar tu código obtengo unos datos de fecha/hora incorrectos:
2165/165/165 (Sabado) 165:165:85
2165/165/165 (Sabado) 165:165:85
2165/165/165 (Sabado) 165:165:85
2165/165/165 (Sabado) 165:165:85
2165/165/165 (Sabado) 165:165:85
2165/165/165 (Sabado) 165:165:85
….
¿Sabes porqué podría ser?. Uso un módulo DS3231 con una pila nueva, pero cada vez que lo ejecuto, entra por la condición del rtc.lostPower
Gracias.
Hola Luis, buenas noches. Necesito me digas como hacer para que me aparezca el nombre de los meses del año, de la misma manera en la que aparecen los nombres de los días. Solamente me aparecen en formato numérico. Muchas gracias.
Hola que tal luis, una pregunta, quiero utilizar tu código para adaptarlo a mi programa de consumo eléctrico, eh igual guardar los datos en una micro sd, mi pregunta aquí es, eh tratado de adaptar mi código con el tuyo, y yo utilizo la linea “myFile” para todo los procesos con la microSD, en este caso utilizas “LogFile” , como puedo adaptarlo para que guarde los demás datos segun tu codigo, si me pudieras ayudar estaria muy agradecido … exelente pagina por cierto, me a ayudado en muchísimas cosas para la escuela.
Hola, que tal, disculpa me he hecho de un RTC pero es el DS1302, hay algo sobre esto o igual puede funcionar con esto? Saludos!
Hola, el DS1302 no tiene I2C y los comandos son diferentes. No es compatible con los que aparecen en esta entrada
hola, estoy colocando el código de encendido y apagado programado tal cual esta en el tengo un DS3231, y me dice que el código no es compatible con arduino genuino uno, alguna ayuda que me puedas dar? muchas gracias
Buenas tardes,
Muy interesante y bien explicado el artículo, como todos los suyos, Luis.
Veo que SDA y SCL del bus I2C se conectan a A4 y A5 respectivamente, cuando esperaba que se conectasen a los pines SDA y SCL del Arduino UNO.
Y no solo en este artículo, el fabricante del RTC también recomienda el mismo conexionado.
Entiendo que la biblioteca “wire.h” utiliza estos pines
¿Pero, por qué no usar las SDA y SCL que incorpora el UNO?
¡Muchas gracias!
Santiago
Un saludo Luis:
Entiendo que el ejercio segundo (programación de enecendido y apagado) los minutos se deben dividir entre 100, (no 60) para que genere la parte fracionaria (minutos) del número a sumar a la hora y entrege un valor que se pueda comparar con las horas de encendido o apagado.
Hola Francisco. No, tienes que dividir por 60. Estamos pasando los minutos a “tanto por 1”. Por lo que debes dividir por 60. Ejemplo, media hora = 0.5 horas = 30 min / 60 min/h
Hola buenas noches!!:
Me parece muy interesante tu pagina y me has ayudado mucho, gracias.
Tengo una duda no puedo compilar la linea ” bool isScheduledON(DateTime date )”, descargué la misma librería que pones en el link me cercioré que estuviese usando esa pero no me funciona.
Tienes alguna idea de por qué?
Buenas,
quisiera saber el formato utilizado por las funciones now.hour(), now.minute() …
y como convertirlos a enteros
Buenas Luis Hola a todos, Un gusto comunicarme con uds. Soy nuevo en esto, y estoy haciendo un proyecto (pequeño, de control de temperatura y humedad, de un habitaculo, con un arduino uno, un DHT 22, (para temperatura y humedad), y un DS3231 para temperatura ambiente y reloj y calendario. Mostrado todo en una pantalla NEXTION BÁSICA HMI Mod, NX3224T024. En el monitor serie del sketch de arduino leo perfectamente todo (las dos temperatura por separado la humedad y calendario y reloj), pero en la pantalla no logro ver la fecha día y hora. (el resto si) si alguien me… Read more »
[…] Reloj en tiempo real […]
Buenas, Tus artículos son geniales y me encanta probar cosillas de vez en cuando. En este caso, me esta dando unos quebraderos terribles el tema de las bibliotecas, veo que es antiguo pero sólo encuentro versiones nuevas. El último error que me escupe es “a function-definition is not allowed here before ‘{‘ token” en la parte de ” void loop() { DateTime now = rtc.now();” Quizá sea una tontería, o venga de tener que haber utilizado la libreria DS3231 y DS3231 rtc; (en lugar de RTClib y RTC_DS3231 rtc;) o de haber eliminado los init de rtc.powerlost y begin (todo… Read more »
buen aporte, en el segundo código yo modificaría
hours = date.hour() + (date.minute() /100.0);
así pueda darme los segundos correctos.
[…] el aire acondicionado o la calefacción, este tiempo se captura por software, no es necesario un módulo RTC ya que no importa la hora exacta sino el tiempo transcurrido, que se puede conocer por el reloj, […]