El Dado Electrónico: Implementación de Aleatoriedad en un Sistema

El desarrollo de sistemas electrónicos interactivos y portátiles es un pilar fundamental en la electrónica moderna. Este proyecto se centra en la creación de un dado electrónico digital utilizando la plataforma Arduino UNO como cerebro, una compacta pantalla OLED de 128×32 píxeles con protocolo I2C para la visualización, y un simple botón pulsador como mecanismo de activación. Este proyecto no solo sirve como una herramienta lúdica, sino que también es una excelente introducción a conceptos clave como la generación de números pseudoaleatorios, el manejo de interrupciones y la comunicación de bus serial (I2C).



🔩Funcionamiento

El Cerebro del Sistema: Arduino UNO

El Arduino UNO utiliza el microcontrolador ATmega328P de Atmel (ahora Microchip). Este chip opera típicamente a 16 MHz y ofrece una arquitectura sencilla pero potente con 32 KB de memoria Flash para el código.

  • Interrupciones: Para lograr que el dado responda instantáneamente al presionar el botón, se utiliza una Interrupción Externa. En el Arduino UNO, los pines digitales 2 y 3 están asignados para estas interrupciones. La interrupción permite que el microcontrolador suspenda temporalmente su tarea actual (el bucle loop()) para atender la solicitud crítica del botón, garantizando que ninguna pulsación se pierda debido al tiempo de ejecución del código principal.

La Comunicación I2C y la Pantalla OLED

La pantalla OLED (Organic Light-Emitting Diode) es ideal por su alto contraste, bajo consumo de energía y tamaño compacto. La mayoría de los módulos de 128 x 32 píxeles utilizan el chip controlador SSD1306 y se comunican a través del bus I2C.

  • Protocolo de Dos Hilos: I2C es un bus de comunicación serial que, de manera inteligente, requiere solo dos líneas para transferir datos entre el maestro (Arduino) y los esclavos (la pantalla):
    • SDA (Serial Data Line): Línea de datos.
    • SCL (Serial Clock Line): Línea de sincronización del reloj.

PINES del OLED 128×32(I2C)

Pin OLED 128×32(I2C)ProtocoloNotas Importantes
VCCAlimentaciónUso de 5V.
GNDTierraConexión de referencia.
SCLI2CLínea de Reloj Serial.
SDAI2CLínea de Datos Serial.

🔨Componentes

ComponenteCantidadEspecificaciónFunción
Placa Arduino1Arduino Uno, Nano, etc.Control de componentes(cerebro)
Pantalla OLED1128×32 (I2C)Mostrar información
Botón1PushActivar el dado
Resistencia110kΩPull-down para el botón
Cables de conexiónnUnir los componentes

🔌Conexiones

Conexión OLED 128×32

OLED 128×32(I2C) PinArduino Pin
GNDGND
VCC5V
SCLA5
SDAA4

Conexión del botón(Configuración Pull-Down):

Arduino PinArduino Pin
5vPin 2 (con resistencia de 10kΩ a GND)

0️⃣Código

El código se divide en secciones claras para la gestión de las librerías, la lógica del dado (incluyendo la simulación del “revolteo”) y la respuesta por interrupción.

Asegúrate de instalar las librerías necesarias desde el Gestor de Librerías del IDE de Arduino:

  1. Adafruit GFX Library (librería gráfica principal)
  2. Adafruit SSD1306 (driver específico para la pantalla)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <Arduino.h>

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// -------------------------------------------------------------
// DEFINICIÓN DE PINES Y PARÁMETROS DE PANTALLA
// -------------------------------------------------------------

// Definición de las dimensiones de la pantalla OLED
#define PANTALLA_ANCHO 128
#define PANTALLA_ALTO 32

// Definición del pin donde está conectado el botón
const int PIN_BOTON = 2;

// Variable de estado para el botón
volatile bool botonPulsado = false;

// Objeto de la pantalla. Usamos 0x3C como dirección I2C común
Adafruit_SSD1306 display(PANTALLA_ANCHO, PANTALLA_ALTO, &Wire, -1);

// -------------------------------------------------------------
// FUNCIÓN DE GESTIÓN DE INTERRUPCIÓN
// -------------------------------------------------------------
// Esta función se ejecuta inmediatamente cuando el botón es presionado
void activarTirada() {
  botonPulsado = true;
}

// -------------------------------------------------------------
// FUNCIÓN PARA DIBUJAR LOS PUNTOS DEL DADO
// -------------------------------------------------------------
void dibujarDado(int valor) {
  // Coordenadas centrales del dado (40, 16) y radio de los puntos
  int centroX = PANTALLA_ANCHO / 2; // 64
  int centroY = PANTALLA_ALTO / 2; // 16
  int radioPunto = 3;
  int margen = 12; // Margen para los puntos de las esquinas

  display.clearDisplay();
  display.drawRect(centroX - 28, centroY - 16, 56, 32, SSD1306_WHITE); // Dibuja el contorno cuadrado del dado (opcional)

  // Función interna para dibujar un punto
  auto dibujarPunto = [&](int x, int y) {
    display.fillCircle(x, y, radioPunto, SSD1306_WHITE);
  };

  // Posiciones predefinidas para los 7 puntos (Centro, Esquinas)
  int p[7][2] = {
    {centroX, centroY}, // Punto central (0)
    {centroX - margen - 10, centroY - margen}, // Superior Izquierda (1)
    {centroX + margen + 10, centroY - margen}, // Superior Derecha (2)
    {centroX - margen - 10, centroY + margen}, // Inferior Izquierda (3)
    {centroX + margen + 10, centroY + margen}, // Inferior Derecha (4)
    {centroX - margen - 10, centroY}, // Centro Izquierda (5)
    {centroX + margen + 10, centroY}  // Centro Derecha (6)
  };

  // Lógica para dibujar puntos según el valor del dado (1 a 6)
  switch (valor) {
    case 1:
      dibujarPunto(p[0][0], p[0][1]); // Centro
      break;

    case 2:
      dibujarPunto(p[1][0], p[1][1]); // Superior Izquierda
      dibujarPunto(p[4][0], p[4][1]); // Inferior Derecha
      break;

    case 3:
      dibujarPunto(p[0][0], p[0][1]); // Centro
      dibujarPunto(p[1][0], p[1][1]); // Superior Izquierda
      dibujarPunto(p[4][0], p[4][1]); // Inferior Derecha
      break;

    case 4:
      dibujarPunto(p[1][0], p[1][1]); // Superior Izquierda
      dibujarPunto(p[2][0], p[2][1]); // Superior Derecha
      dibujarPunto(p[3][0], p[3][1]); // Inferior Izquierda
      dibujarPunto(p[4][0], p[4][1]); // Inferior Derecha
      break;

    case 5:
      dibujarPunto(p[0][0], p[0][1]); // Centro
      dibujarPunto(p[1][0], p[1][1]); // Superior Izquierda
      dibujarPunto(p[2][0], p[2][1]); // Superior Derecha
      dibujarPunto(p[3][0], p[3][1]); // Inferior Izquierda
      dibujarPunto(p[4][0], p[4][1]); // Inferior Derecha
      break;

    case 6:
      dibujarPunto(p[1][0], p[1][1]); // Superior Izquierda
      dibujarPunto(p[2][0], p[2][1]); // Superior Derecha
      dibujarPunto(p[3][0], p[3][1]); // Inferior Izquierda
      dibujarPunto(p[4][0], p[4][1]); // Inferior Derecha
      dibujarPunto(p[5][0], p[5][1]); // Centro Izquierda
      dibujarPunto(p[6][0], p[6][1]); // Centro Derecha
      break;
      
    default: // En caso de un error o valor inicial no válido
      display.setTextSize(2);
      display.setTextColor(SSD1306_WHITE);
      display.setCursor(40, 10);
      display.print("ERROR");
      break;
  }
  display.display();
}


// -------------------------------------------------------------
// FUNCIÓN SETUP (CONFIGURACIÓN INICIAL)
// -------------------------------------------------------------
void setup() {
  // 1. Inicialización de la Comunicación Serial (para depuración, opcional)
  Serial.begin(9600);
  Serial.println("Dado Electronico - Iniciando...");

  // 2. Configuración del Pin del Botón
  pinMode(PIN_BOTON, INPUT);

  // 3. Configuración de Interrupción Externa
  // Asocia la función 'activarTirada' al Pin 2, detectando flancos de BAJO a ALTO (RISING)
  // Esto es para la configuración pull-down (al presionar pasa de 0V a 5V)
  attachInterrupt(digitalPinToInterrupt(PIN_BOTON), activarTirada, RISING);

  // 4. Inicialización de la Pantalla OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Dirección 0x3C para la mayoría de los módulos
    Serial.println(F("Error: No se encontró la pantalla OLED."));
    for (;;); // Detiene el programa
  }

  // 5. Sembrado del Generador de Aleatorios (Anti-patrón)
  // Lee el ruido eléctrico del pin A0 para una semilla impredecible.
  randomSeed(analogRead(A0));
  Serial.print("Semilla Aleatoria: ");
  Serial.println(analogRead(A0));

  // 6. Mensaje de Bienvenida
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 5);
  display.println("Dado Electronico");
  display.setCursor(10, 20);
  display.println("Presione el Boton...");
  display.display();
}

// -------------------------------------------------------------
// FUNCIÓN LOOP (BUCLE PRINCIPAL)
// -------------------------------------------------------------
void loop() {
  // La variable 'botonPulsado' es cambiada por la Interrupción
  if (botonPulsado) {
    
    // ** SIMULACIÓN DE LA TIRADA DEL DADO (EL 'REVOLTEO') **
    for (int i = 0; i < 15; i++) { // 15 "revolcones"
      int valorTemp = random(1, 7); // Genera un número temporal entre 1 y 6
      dibujarDado(valorTemp); // Dibuja el número temporal
      delay(50 + i * 5); // El retardo se incrementa para simular que el dado se detiene
    }

    // ** RESULTADO FINAL **
    int resultado = random(1, 7); // Genera el resultado final (1 a 6)
    dibujarDado(resultado);
    Serial.print("Resultado: ");
    Serial.println(resultado);
    
    // Pequeño retardo para evitar rebotes o lecturas múltiples
    delay(500); 

    // Reinicia el estado para esperar la próxima pulsación
    botonPulsado = false;
  }
  // No hay más código aquí para ahorrar ciclos del CPU, la interrupción es la que activa la lógica.
}


🖌️Diseños


🎬Videos


📑Conclusión

El desarrollo del Dado Electrónico Digital sobre la plataforma Arduino UNO demuestra de manera práctica y didáctica la convergencia exitosa de la electrónica digital, la programación de sistemas empotrados y la interacción humano-máquina.

Este proyecto, aparentemente simple, constituye un modelo robusto para la implementación de funciones esenciales en microcontroladores:

  1. Respuesta Instantánea con Interrupciones: La implementación del botón pulsador mediante una interrupción externa (en el Pin 2) optimizó la eficiencia del sistema. Esto garantizó una respuesta inmediata a la acción del usuario, evitando el uso ineficiente del método de polling y demostrando una programación reactiva.
  2. Comunicación Serial Eficiente (I2C): Se estableció una comunicación fluida y de bajo cableado con la pantalla OLED 128 x 32 a través del protocolo I2C (pines A4 y A5), que es estándar en proyectos compactos. Las librerías de Adafruit permitieron una abstracción gráfica sencilla para dibujar los puntos del dado en lugar de solo texto.
  3. Experiencia de Usuario: Se añadió un valor estético significativo a través del efecto de desaceleración en la animación de la tirada, proporcionando una experiencia visual convincente que simula el movimiento real de un dado.

En resumen, el Dado Electrónico es más que una herramienta lúdica; es una excelente puerta de entrada al mundo del hardware y software integrado, sirviendo como una base sólida para futuros proyectos que requieran entradas de usuario de alta respuesta y salidas visuales compactas y claras.


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Carrito de compra