¿Por qué armar un reloj con 6 displays cuando hay módulos OLED?
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
- Módulo Reloj RTC DS3231 (SKU G-101V2): $6.490
- Display 7 segmentos cátodo común 0.56" (SKU D-208): $490 × 6
- Transistor 2N2222 NPN (SKU GA4-6): $200 × 6
- Resistencia 1 kΩ 1/4W (SKU GK3-17): $100 × 6
- Resistencia 220 Ω 1/4W (SKU GK1-18): $100 × 7 (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 × 2
- Botón pulsador 4 pines 6×6×4.3mm (SKU GA1-3): $290 × 2
- Pack 65 cables macho macho (SKU C-280): $3.490
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.
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.













