¿Por qué armar un reloj con 6 displays cuando hay módulos OLED de $2.000?
Hacer un reloj digital es uno de esos proyectos que parecen obsoletos hasta que entiendes lo que hay debajo. Un módulo OLED te resuelve la pantalla en 4 cables y dos líneas de código, pero esconde todo lo interesante: multiplexado, manejo de interrupciones, control directo de pines, y debugging real cuando algo no enciende. Este tutorial te lleva por el camino largo a propósito. Al final vas a tener un reloj con presencia física (6 dígitos brillantes en rojo) y un dominio sólido de técnicas que sirven para mucho más que mostrar la hora.
El proyecto controla 6 displays de 7 segmentos de cátodo común multiplexados por software, con un módulo RTC DS3231 como base de tiempo (mantiene la hora con batería incluso desconectado), y dos botones para ajustar fecha y hora. Está basado en el proyecto publicado por Geek Factory, reorientado a componentes del stock chileno y con explicaciones extras sobre la técnica de multiplexado.
Concepto clave: ¿qué significa "multiplexar"?
Un display de 7 segmentos necesita 8 pines de control (7 segmentos más el punto). Si quisieras prender 6 displays independientes necesitarías 48 pines, imposible en un Arduino Nano que tiene apenas 22 GPIO útiles. La solución: multiplexar.

La idea es conectar los 7 segmentos de los 6 displays en paralelo (todos los "A" juntos, todos los "B" juntos, etc.), y agregar un transistor por display que controla qué cátodo común se conecta a tierra en cada instante. Si enciendes los dígitos uno a la vez a más de 50 Hz, el ojo humano los percibe como si estuvieran todos encendidos simultáneamente: el mismo principio que usa una TV para mostrar fotogramas.
Resultado: con 7 pines para segmentos más 6 pines para selección de dígito = 13 pines controlas los 6 displays. Cabe holgado en cualquier Arduino.
Hardware: lista de componentes y por qué cada uno
| Componente | Cantidad | Para qué sirve |
|---|---|---|
| Arduino Nano | 1 | Controlador principal |
| Módulo RTC DS3231 | 1 | Base de tiempo (≤2 min/año de deriva) |
| Display 7 segmentos cátodo común | 6 | Mostrar dígitos |
| Transistor 2N2222 NPN | 6 | Switching del cátodo de cada display |
| Resistencia 1 kΩ | 6 | Base del transistor (limitar corriente desde Arduino) |
| Resistencia 220 Ω (o 120 Ω) | 7 | En serie con cada segmento (limitar corriente del LED) |
| Pushbutton 4 pines | 2 | Botones SET y UP |
| Protoboard 830 puntos | 2 | Espacio para todos los cables |
| Cables macho macho | 1 pack | Conexiones |
El DS3231 es el corazón temporal del proyecto: trae cristal compensado por temperatura y batería de respaldo, así que sigue contando la hora aunque desconectes el Arduino y se desvía menos de 2 minutos al año.

Cada display se enciende a través de un transistor 2N2222 que actúa como interruptor del cátodo común. El Arduino no entrega corriente suficiente para iluminar los 7 segmentos directamente, por eso el transistor hace el trabajo pesado y el pin solo gobierna la base a través de una resistencia de 1 kΩ.

Nota chilena: en el catálogo MS están las resistencias de 220 Ω (no 120 Ω). La diferencia es marginal: con 220 Ω los displays se ven un ~30% menos brillantes pero protege más al Arduino. Si quieres brillo máximo y tienes pulso firme, puedes combinar dos 220 Ω en paralelo para obtener ~110 Ω.
Mapa de pines
El diagrama esquemático del proyecto resume todo el cableado: los segmentos en paralelo hacia los displays, los 6 transistores con su resistencia de base, el DS3231 por I²C y los dos botones de ajuste.

| Pin Arduino | Función |
|---|---|
| D2 | Interrupción 1Hz desde DS3231 (SQW) |
| D3 | Botón SET |
| D4 | Botón UP |
| D5 a D11 | Segmentos A, B, C, D, E, F, G |
| D12, D13 | Habilitación dígitos 1 y 2 |
| A0 a A3 | Habilitación dígitos 3, 4, 5, 6 |
| A4 (SDA) | I²C datos hacia DS3231 |
| A5 (SCL) | I²C reloj hacia DS3231 |
Software: librerías y patrón de diseño
El tutorial original usa cuatro librerías de la familia Geek Factory:
GFDisplay7S: abstracción para displays multiplexadosGFButton: debouncing de botones con detección de pulsación corta y largaGFRTC: wrapper de DS3231 con interrupción de 1 HzTimerOne: interrupciones por timer para refrescar el display sin bloquearloop()
Hay un patrón importante aquí que vale la pena entender: el refresco del display NO está en loop(). Si lo pusieras ahí, cualquier delay() o instrucción lenta haría parpadear los dígitos. En lugar de eso, Timer1.attachInterrupt(interrupt_display_refresh) corre la función de refresco cada 3 ms (333 Hz, muy por encima del umbral perceptible), liberando el loop() para manejar botones y leer el RTC.
El DS3231 genera además una señal cuadrada de 1 Hz por el pin SQW, que se conecta a la interrupción externa D2. Cada flanco de bajada (una vez por segundo) levanta un flag, y loop() solo lee el RTC cuando ese flag está activo, así no martillamos el I²C constantemente.
#include "GFDisplay7S.h"
#include "GFButton.h"
#include "GFRTC.h"
#include "TimerOne.h"
GFButton setButton(3);
GFButton upButton(4);
GFDisplay7S display(
(const uint8_t[]){ 5, 6, 7, 8, 9, 10, 11, 0xFF }, // segmentos A a G
(const uint8_t[]){ 12, 13, A0, A1, A2, A3 }, // seleccion de digitos
6
);
enum clock_modes { E_CLOCK_MODE_RUN = 0, E_CLOCK_MODE_ADJ };
enum clock_modes mode = E_CLOCK_MODE_RUN;
struct timelib_tm datetime;
volatile bool rtcflag = false;
void setup() {
display.begin();
Timer1.initialize(3000); // 333 Hz refresh
Timer1.attachInterrupt(interrupt_display_refresh);
GFRTC.begin(true);
if (!GFRTC.isPresent()) { display.print("E1"); for(;;); }
GFRTC.setIntSqwMode(E_SQRWAVE_1_HZ);
pinMode(2, INPUT);
attachInterrupt(digitalPinToInterrupt(2), interrupt_rtc, FALLING);
}
void loop() {
switch (mode) {
case E_CLOCK_MODE_RUN:
if (setButton.wasLongPress()) { // 5 s pulsado entra a ajuste
setButton.wasPressed();
mode = E_CLOCK_MODE_ADJ;
break;
}
if (rtcflag) { // 1 Hz desde DS3231
rtcflag = false;
if (GFRTC.read(datetime))
upButton.isPressed() ? clock_show_date() : clock_show_time();
}
break;
case E_CLOCK_MODE_ADJ:
// ... logica de ajuste con SET para cambiar variable y UP para incrementar
break;
}
}
void interrupt_display_refresh() { display.process(); }
void interrupt_rtc() { rtcflag = true; }
El código completo (~150 líneas) está en el repositorio del autor original, con el link al final.
Cómo se usa el reloj
Una vez cargado el sketch:
- Modo normal: muestra HH:MM:SS. Mantén apretado UP para ver la fecha (formato DD/MM/AA) mientras lo tengas pulsado.
- Entrar a ajuste: mantén SET pulsado 5 segundos. Empiezan a parpadear los dígitos de horas.
- Ajustar: con UP incrementas el valor. SET corto pasa al siguiente campo (minutos → segundos → día → mes → año).
- Guardar y salir: SET pulsado 5 segundos nuevamente. Vuelve a modo normal con la nueva hora guardada en el DS3231.
Si el RTC no se comunica al arranque (cableado mal o módulo malo), el display muestra "E1" y se cuelga. Es un buen ejemplo de falla inmediata (fallar rápido): mejor avisar al instante que correr con basura.
Variantes y mejoras
Tres formas concretas de extender el proyecto que el tutorial original no plantea:
Cambiar a displays de ánodo común: si compras displays de ánodo común, reemplaza los 2N2222 NPN por transistores PNP 2N2907 y reconecta el cátodo a GND fijo más el ánodo común al colector del PNP que va a VCC. La lógica del software se invierte (HIGH apaga, LOW prende), eso lo manejas con un define en la librería.
Brillo regulable según hora: agregar un LDR (fotorresistencia) en A6 y leerlo cada minuto. Si la luz ambiente baja (de noche), reduce el duty cycle del refresco: en vez de prender cada dígito por 3 ms de cada 18 ms, hazlo por 1 ms. Resultado: un reloj que no enceguece a las 3 AM.
Sincronización por WiFi: reemplaza el Arduino Nano por un ESP8266 NodeMCU o ESP32 (los segmentos van igual a los GPIO). Una vez por día, sincroniza el DS3231 contra pool.ntp.org y el reloj nunca más atrasa. El DS3231 queda como backup para cuando se corta el WiFi.
Personalización para Chile
Todos los componentes en MechatronicStore (precios mayo 2026):
- Arduino Nano V3 CH340 más cable (SKU N-302): $4.490 CLP
- Módulo Reloj RTC DS3231 (SKU G-101V2): $6.490 CLP
- Display 7 segmentos cátodo común 0.56" (SKU D-208): $490 CLP × 6 = $2.940 CLP
- Transistor 2N2222 NPN (SKU GA4-6): $200 CLP × 6 = $1.200 CLP
- Resistencia 1 kΩ 1/4W (SKU GK3-17): $100 CLP × 6 = $600 CLP
- Resistencia 220 Ω 1/4W (SKU GK1-18): $100 CLP × 7 = $700 CLP (el original usa 120 Ω, que no está en stock; con 220 Ω brilla algo menos pero protege más)
- Breadboard 830 puntos MB102 (SKU C-302): $3.790 CLP × 2 = $7.580 CLP
- Botón pulsador 4 pines 6×6×4.3mm (SKU GA1-3): $290 CLP × 2 = $580 CLP
- Pack 65 cables macho macho (SKU C-280): $3.490 CLP
Equivalencia: el tutorial original usa Arduino Nano Every (variante con ATMega4809). El Nano V3 con ATmega328P funciona idéntico para este proyecto: la diferencia entre ambas placas solo importa con código que use periféricos avanzados del 4809.
Total estimado: ~$28.150 CLP para armar el reloj completo desde cero.
Recursos
- Proyecto original (español, México): Reloj digital con Arduino y displays de 7 segmentos en Geek Factory
- Repositorio del autor con librerías GFDisplay7S, GFButton, GFRTC y código del reloj: enlace en la sección "Lecturas recomendadas" del proyecto original
- Librería TimerOne: PaulStoffregen/TimerOne
- Datasheet DS3231: Maxim DS3231
Versión chilena con componentes en stock local en MechatronicStore, inspirada en el proyecto de Geek Factory.



