¿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.

Display de 7 segmentos de un dígito, el bloque básico del reloj

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.

Módulo RTC DS3231 con batería de respaldo y bus I²C

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Ω.

Transistor 2N2222 en encapsulado TO-92 para el switching de cada dígito

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.

Diagrama esquemático del reloj con Arduino Nano, DS3231, 6 displays y transistores 2N2222

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 multiplexados
  • GFButton: debouncing de botones con detección de pulsación corta y larga
  • GFRTC: wrapper de DS3231 con interrupción de 1 Hz
  • TimerOne: interrupciones por timer para refrescar el display sin bloquear loop()

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.

C++
#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:

  1. 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.

  2. 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.

  3. 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

Versión chilena con componentes en stock local en MechatronicStore, inspirada en el proyecto de Geek Factory.