De cero a reloj: controla la hora con Arduino UNO y DS1307
Introducción
En esta práctica aprenderemos a utilizar un módulo de reloj de tiempo real RTC DS1307 junto con un Arduino UNO para obtener y mostrar la fecha y hora en tiempo real mediante el Monitor Serial.
El DS1307 es un circuito integrado diseñado para mantener información de tiempo: segundos, minutos, horas, día, mes y año. El módulo cuenta además con una batería que mantiene funcionando el reloj cuando el Arduino deja de recibir alimentación.
Nos comunicaremos con el RTC mediante el protocolo I2C, usando los pines SDA y SCL del Arduino UNO. La práctica tiene tres etapas: comprobar que el Arduino detecta el módulo con un escáner I2C, configurar la fecha y hora inicial, y leer continuamente el RTC para mostrar la hora actualizándose cada segundo.

Material necesario
- Arduino UNO.
- Módulo RTC DS1307 HW-111 (con memoria EEPROM AT24C32).
- Cables Dupont.
- Cable USB para Arduino UNO.
- Batería tipo botón: LIR2032 (recargable) o CR2032 (ver la advertencia siguiente).
Advertencia sobre la batería: muchos módulos HW-111 incluyen un pequeño circuito de carga pensado para baterías recargables LIR2032. Si instalas una pila CR2032 no recargable, el circuito intentará cargarla y puede provocar fugas o dañar la pila y el módulo. Con una CR2032 es necesario desactivar antes el circuito de carga (retirando el diodo o la resistencia correspondiente) o usar un módulo que no lo traiga. Si tienes dudas, usa una LIR2032.
Conexión del RTC DS1307 al Arduino UNO
El módulo RTC utiliza comunicación I2C. En el Arduino UNO, los pines de este bus son A4 (SDA) y A5 (SCL). Realiza las siguientes conexiones:
| Pin del RTC | Pin del Arduino UNO |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
Los demás pines del módulo (SQ, DS y BAT) no son necesarios para esta práctica: SQ es la salida de onda cuadrada, DS es la entrada para un sensor de temperatura DS18B20 opcional y BAT permite conectar una batería externa.


Conexión del Arduino UNO con el módulo RTC DS1307 mediante I2C.
1. Comprobación de la comunicación I2C
Antes de trabajar con el reloj, es recomendable comprobar que el Arduino UNO se comunica correctamente con el módulo. Para esto utilizaremos un escáner I2C: un programa que revisa las direcciones del bus I2C y muestra en el Monitor Serial los dispositivos que encuentra.
Copia el siguiente código en el Arduino IDE:
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin();
Serial.println("Escaneando I2C...");
}
void loop() {
byte encontrados = 0;
for (byte direccion = 1; direccion < 127; direccion++) {
Wire.beginTransmission(direccion);
byte error = Wire.endTransmission();
if (error == 0) {
Serial.print("Dispositivo encontrado en 0x");
if (direccion < 16) {
Serial.print("0");
}
Serial.println(direccion, HEX);
encontrados++;
}
}
if (encontrados == 0) {
Serial.println("NO se encontraron dispositivos I2C.");
}
Serial.println("----------------------");
delay(3000);
}
Abre el Monitor Serial y selecciona 9600 baudios. En nuestra prueba, el escáner detectó dos dispositivos:
- 0x68 → RTC DS1307.
- 0x50 → memoria EEPROM AT24C32 integrada en el módulo.
Resultado del escáner I2C: se detectan los dispositivos en las direcciones 0x50 y 0x68.
Para esta práctica utilizaremos la dirección 0x68, correspondiente al RTC.
¿Por qué es importante esta prueba?
Si el RTC no aparece, conviene revisar las conexiones antes de continuar con el programa: SDA en A4, SCL en A5, y VCC y GND bien conectados.
2. Configuración de la fecha y hora inicial
Antes de mostrar la hora debemos establecer una fecha y hora inicial en el DS1307. El siguiente programa escribe los valores indicados en los registros del RTC. Modifica la fecha y la hora antes de cargarlo.
Convención del día de la semana
El DS1307 solo guarda un número del 1 al 7 en el registro del día de la semana y no impone qué día corresponde a cada número. En este código usamos 1 = domingo, 2 = lunes, 3 = martes… 7 = sábado. Como el 28/09/2026 es lunes, el valor es 2.
#include <Wire.h>
#define RTC_ADDRESS 0x68
byte decToBcd(byte valor) {
return ((valor / 10) << 4) | (valor % 10);
}
void setup() {
Serial.begin(9600);
Wire.begin();
// =================================
// FECHA Y HORA DE INICIO
// =================================
byte segundos = 0;
byte minutos = 20;
byte horas = 9;
byte diaSemana = 2; // 1 = domingo, 2 = lunes ... 7 = sábado
byte dia = 28;
byte mes = 9;
byte anio = 26;
// =================================
Wire.beginTransmission(RTC_ADDRESS);
Wire.write(0x00);
Wire.write(decToBcd(segundos)); // bit 7 en 0 = el reloj queda en marcha
Wire.write(decToBcd(minutos));
Wire.write(decToBcd(horas)); // bit 6 en 0 = formato de 24 horas
Wire.write(decToBcd(diaSemana));
Wire.write(decToBcd(dia));
Wire.write(decToBcd(mes));
Wire.write(decToBcd(anio));
byte resultado = Wire.endTransmission();
if (resultado == 0) {
Serial.println();
Serial.println("Hora de inicio configurada:");
if (dia < 10) Serial.print("0");
Serial.print(dia);
Serial.print("/");
if (mes < 10) Serial.print("0");
Serial.print(mes);
Serial.print("/20");
Serial.println(anio);
if (horas < 10) Serial.print("0");
Serial.print(horas);
Serial.print(":");
if (minutos < 10) Serial.print("0");
Serial.print(minutos);
Serial.print(":");
if (segundos < 10) Serial.print("0");
Serial.println(segundos);
} else {
Serial.println("Error al configurar el RTC.");
}
}
void loop() {
}
Después de cargarlo, el Monitor Serial mostrará la hora de inicio que se escribió en el RTC. Por ejemplo:
Hora de inicio configurada:
28/09/2026
09:20:00
Importante: este programa escribe la hora dentro de setup(), que se ejecuta cada vez que el Arduino se reinicia o se conecta a la corriente. Si lo dejas cargado y desconectas el Arduino, al volver a conectarlo sobrescribirá la hora con los valores fijos del código y la prueba de la batería no servirá. Por eso:
- Carga el programa de configuración y comprueba que el Monitor Serial muestre la hora de inicio.
- Inmediatamente después, vuelve a cargar el programa de lectura (sección 3).
- Solo entonces realiza la prueba de la batería.
3. Mostrar la hora en tiempo real
Ahora utilizaremos el programa principal de la práctica. El Arduino UNO lee continuamente los registros del DS1307 y muestra la fecha y hora en el Monitor Serial. Realiza una lectura cada segundo, por lo que podrás ver cómo avanzan los segundos.
#include <Wire.h>
#define RTC_ADDRESS 0x68
// Convierte BCD a decimal
byte bcdToDec(byte valor) {
return ((valor >> 4) * 10) + (valor & 0x0F);
}
void setup() {
Serial.begin(9600);
Wire.begin();
Serial.println("Reloj en tiempo real");
Serial.println("--------------------");
}
void loop() {
// Seleccionar el registro inicial del DS1307
Wire.beginTransmission(RTC_ADDRESS);
Wire.write(0x00);
Wire.endTransmission();
// Solicitar 7 registros:
// segundos, minutos, horas, día semana,
// día, mes y año
Wire.requestFrom(RTC_ADDRESS, 7);
if (Wire.available() >= 7) {
// & 0x7F: el bit 7 de los segundos es CH (clock halt) y no es parte del valor
byte segundos = bcdToDec(Wire.read() & 0x7F);
byte minutos = bcdToDec(Wire.read());
// & 0x3F: conserva solo los bits de la hora en formato de 24 horas
byte horas = bcdToDec(Wire.read() & 0x3F);
// Día de la semana: se lee para avanzar al siguiente registro
// y se descarta porque la fecha ya identifica el día.
Wire.read();
byte dia = bcdToDec(Wire.read());
byte mes = bcdToDec(Wire.read());
byte anio = bcdToDec(Wire.read());
Serial.println();
Serial.print("Fecha: ");
if (dia < 10) Serial.print("0");
Serial.print(dia);
Serial.print("/");
if (mes < 10) Serial.print("0");
Serial.print(mes);
Serial.print("/20");
Serial.println(anio);
Serial.print("Hora: ");
if (horas < 10) Serial.print("0");
Serial.print(horas);
Serial.print(":");
if (minutos < 10) Serial.print("0");
Serial.print(minutos);
Serial.print(":");
if (segundos < 10) Serial.print("0");
Serial.println(segundos);
} else {
Serial.println("Error: no se pudo leer el RTC.");
}
delay(1000);
}
Resultado obtenido
En la prueba realizada, el Arduino UNO leyó correctamente la información almacenada en el RTC DS1307. El Monitor Serial mostró la fecha 28/09/2026 y la hora avanzando segundo a segundo:
Lectura de la fecha y hora en tiempo real mediante el Monitor Serial.
¿Qué hacen las máscaras & 0x7F y & 0x3F?
El DS1307 usa algunos bits de sus registros para funciones de control, así que antes de convertir el valor hay que descartarlos:
-
& 0x7Fen los segundos: el bit 7 del registro de segundos es CH (clock halt). Si vale 1, el oscilador está detenido y el reloj no avanza. La máscara elimina ese bit para que el valor leído sea solo el de los segundos. -
& 0x3Fen las horas: el bit 6 del registro de horas indica si el reloj usa formato de 12 o 24 horas. El programa de configuración lo deja en 24 horas, y la máscara conserva únicamente los bits de la hora.
¿Por qué se descarta el día de la semana?
El programa lee ese registro (con Wire.read();) porque los datos llegan en orden y hay que pasar por él para obtener el día, mes y año. No se muestra porque la fecha completa ya identifica el día. Si quieres mostrarlo, guarda el valor con byte diaSemana = bcdToDec(Wire.read()); y usa un arreglo con los nombres, respetando la misma convención del programa de configuración (1 = domingo).
Prueba de la batería
Una de las principales ventajas de un RTC es que sigue contando el tiempo aunque el Arduino se quede sin alimentación, gracias a la batería del módulo. Para comprobarlo (con el programa de lectura cargado, no el de configuración):
- Con el Arduino conectado, abre el Monitor Serial y anota la hora que muestra.
- Desconecta el cable USB.
- Espera 30 segundos (puedes usar el cronómetro del teléfono).
- Vuelve a conectar el Arduino y abre el Monitor Serial a 9600 baudios.
- Compara: la hora debe haber avanzado aproximadamente 30 segundos más el tiempo que tardaste en reconectar. Si es así, la batería está funcionando.
¿Cómo funciona la comunicación I2C?
El protocolo I2C permite que el Arduino se comunique con varios dispositivos usando dos líneas:
- SDA: línea de datos.
- SCL: línea de reloj.
Cada dispositivo tiene una dirección dentro del bus. El RTC DS1307 usa la dirección fija 0x68. La memoria EEPROM AT24C32 del módulo responde por defecto en 0x50, y esa dirección puede cambiarse entre 0x50 y 0x57 con los jumpers (puentes) A0, A1 y A2 del módulo. Como las direcciones son distintas, ambos dispositivos conviven en el mismo bus sin interferirse.
¿Qué información proporciona el DS1307?
El RTC almacena segundos, minutos, horas, día de la semana, día del mes, mes y año. En nuestro programa, el Arduino solicita estos siete registros, los convierte de BCD a decimal y los muestra de forma legible.
Precisión del DS1307 y una alternativa: el DS3231
El DS1307 usa un cristal de cuarzo externo cuya frecuencia varía con la temperatura, por lo que el reloj puede adelantarse o atrasarse algunos segundos por día. Para prácticas, relojes sencillos o registros donde no importa una deriva pequeña es suficiente, pero conviene volver a sincronizarlo de vez en cuando.
Si necesitas más precisión, el DS3231 incluye un oscilador compensado por temperatura con una exactitud de ±2 ppm, es decir, una deriva de aproximadamente un minuto al año. Los registros de hora y fecha del DS3231 están organizados igual, por lo que los programas de esta práctica normalmente funcionan también con ese módulo. Puedes encontrarlo en la sección de productos relacionados.
Alternativa: la librería RTClib
En esta práctica trabajamos directamente con los registros para entender cómo funciona el RTC. Si solo quieres usar el reloj en tus proyectos, la librería RTClib de Adafruit (disponible en el Administrador de Bibliotecas del Arduino IDE) lo simplifica mucho: ya incluye las conversiones BCD, el manejo de fechas y soporte para DS1307 y DS3231.
Solución de problemas
- El escáner no detecta ningún dispositivo: revisa que SDA esté en A4 y SCL en A5, que VCC y GND estén bien conectados y que los cables Dupont hagan buen contacto. Prueba cambiar los cables y confirma que el módulo tiene los pines soldados.
- El escáner solo detecta 0x50 y no 0x68: la EEPROM responde pero el DS1307 no. Verifica que el módulo reciba 5 V, porque el DS1307 necesita alimentación de 4.5 a 5.5 V para funcionar correctamente.
- La fecha aparece como 00/00/2000 o con valores extraños: el RTC no se ha configurado o perdió la hora por falta de batería. Carga el programa de configuración y después vuelve a cargar el de lectura.
- Los segundos no avanzan: el bit CH está en 1 y el oscilador está detenido. Ejecuta el programa de configuración, que lo pone en 0 y arranca el reloj. Si persiste, revisa la batería y el contacto del portabaterías.
- La hora se pierde o se reinicia al desconectar el Arduino: puede ser que la batería esté agotada, mal colocada (el lado + debe quedar hacia arriba) o con menos de unos 2 V. También verifica que no hayas dejado cargado el programa de configuración, que sobrescribe la hora en cada reinicio.
Aplicaciones
Una vez que sabemos usar el DS1307, podemos incorporarlo en proyectos como:
- Relojes digitales.
- Alarmas programables.
- Registradores de datos (dataloggers).
- Sistemas de automatización.
- Control de horarios.
- Programadores de eventos.
- Estaciones de monitoreo.
- Registro de eventos con fecha y hora.
Conclusiones
Aprendimos a detectar un dispositivo I2C con un escáner, a configurar la fecha y hora del DS1307 y a leerla desde el Arduino UNO, entendiendo cómo se guardan los datos en los registros del RTC. También comprobamos que el reloj sigue contando gracias a su batería y vimos sus límites de precisión.
Como siguiente paso, puedes mostrar la hora en una pantalla LCD u OLED, activar una salida a una hora determinada para crear una alarma, o guardar lecturas con fecha y hora usando la memoria EEPROM del módulo.
Productos utilizados en esta práctica
Arduino UNO
Placa de desarrollo utilizada como controlador principal de la práctica. Incluye cable USB.
RTC DS1307 HW-111
Módulo de reloj de tiempo real utilizado para mantener y consultar la fecha y hora.
Para mayor precisión
Módulo RTC DS3231
Reloj de tiempo real con oscilador compensado por temperatura, exactitud de ±2 ppm y alarmas programables. Ideal si necesitas una hora más precisa.
No comments
0 comments