Uso de pantalla 2.8″ TFT ILI9341 con Arduino Nano

Radar iRoX

Por: Julio Cesar Sandria Reynoso, David Rojas Bosada y Fernando Méndez Reyes
4 de octubre de 2026

Arduino Nano Genérico

Desde hace unos meses, nuestro alumno del Instituto de Robótica de Xalapa (iRoX), David, nos trajo el reto de hacer funcionar unas pantallas de 2.8 pulgadas TFT con chip ILI9341 para su proyecto del robot BB8. Nuestro alumno Fernando, llevó a cabo las primeras investigaciones, la hizo funcionar y le proporcionó a David el esquema para hacer una placa PCB muy sencilla. En las últimas semanas, llegamos al punto de ya requerir instalar las pantallas en la unidad BB8 y retomamos el tema de las pantallas.

En este artículo publicamos lo necesario para replicar el inicio del uso de la pantalla 2.8″ TFT 240xRGBx320 V1.1 con circuito integrado ILI9341 en PCB roja, con Arduino Nano (genérico) programado en Arduino IDE 2.3.10.

En una placa de prototipos PCB se soldaron los componentes para colocar Arduino Nano y la Pantalla 2.8 TFT, haciendo las divisiones de voltaje de 5V a 3.3V con resistencias de 2.5 y 5 Kohms.

Como se menciona al principio, empezamos a trabajar con esta pantalla algunos meses atrás (4 ó 5), por lo que al retomar el proyecto, usando la placa PCB ya soldada, y colocándole el Arduino Nano y la pantalla, los ejemplos de código en C++ en Arduino IDE que sabíamos que ya habían funcionado, pues no funcionaban. Dado que ya no teníamos a la mano el diagrama original, rehicimos el esquema electrónico para analizar bien las conexiones entre Arduino Nano y la Pantalla.

NOTA: Para probar los programas de ejemplo de Adafruit hay que instalar en Arduino IDE las librerías Adafruit ILI9341 y Adafruit GFX.

Una vez analizado cómo se había soldado la placa PCB y algunos ejemplos de programas disponibles de Adafruit para una pantalla 2.8 TFT con chip ILI9341, llegamos al siguiente programa para mostrar un «Hola iRoX» en la pantalla.

/*
Instituto de Robótica de Xalapa - 4-Octubre-2026
Programa: Pantalla-2.8-TFT_Hola_iRoX.ino (C++)
Basado en: Simple "Hello World" for ILI9341 LCD
https://wokwi.com/arduino/projects/308024602434470466
y complementado con ejemplos de Adafruit ILI9341
Autor: Julio César Sandria Reynoso
Colaboradores: David Rojas Bosada, Fernando Méndez Reyes
Hardware:
+ Pantalla 2.8" TFT 240xRGBx320 V1.1 (PCB Roja) chip ILI9341
+ Arduino NANO
+ PCB propio con divisores de voltaje de 5V a 3.3V
*/

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// Asegura las siguientes conexiones al Arduino NANO:
// Pines 8 a 13 con divisores de voltaje de 5V a 3.3V
// NOTA: las macros (#define) tienen los nombres de pin
// de la pantalla y pueden variar respecto a los
// ejemplo originales de ADAFRUIT.
// PIN TFT VCC 5V Arduino
// PIN TFT GND GND Arduino
#define TFT_RESET 8
#define TFT_DC 9
#define TFT_CS 10
#define TFT_SDI 11
#define TFT_LED 12
#define TFT_SCK 13
Adafruit_ILI9341 tft = Adafruit_ILI9341(
TFT_CS, TFT_DC, TFT_SDI, TFT_SCK, TFT_RESET, TFT_LED);

void setup() {
tft.begin();
}

void loop(void) {
for(uint8_t rotacion=0; rotacion<4; rotacion++) {
tft.setRotation(rotacion);
texto(rotacion);
delay(1000);
}
}

void texto(uint8_t rotacion) {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 20);
tft.setTextColor(ILI9341_RED);
tft.setTextSize(3);
tft.println("Hola iRoX!");

tft.setCursor(10, 60);
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(2);
tft.println("Julio Sandria");

tft.setCursor(10, 100);
tft.setTextColor(ILI9341_YELLOW);
tft.setTextSize(1);
tft.print("rotacion: ");
tft.println(rotacion);
}

Este programa ejecuta un ciclo for(…) dentro de la función loop(), imprimiendo el texto de la función texto(…) en cuatro orientaciones de la pantalla, que seguimos llamando rotaciones para conservar la terminología que usa la librería Adafruit ILI9341, con el método setRotation() del objeto tft.

Y ya habiendo dominado las conexiones y algunos programas ejemplos de Adafruit ILI9341, nos pusimos a jugar un rato haciendo programas con ayuda de una inteligencia artificial generativa, cargando el programa al Arduino Nano y obteniendo algunas imágenes como la siguiente:

El programa funciona como un radar simulando que detecta objetos y mostrándolos como círculos rojos. A continuación está el programa que trabajamos Deepseek, David Rojas y Julio Sandria.

/*
  Instituto de Robótica de Xalapa - 4-Octubre-2026
  Programa: BB8_pant-2.8_radar_horizontal.ino (C++)
  Desarrollado por Julio César Sandria Reynoso, David Rojas Bosada y DeepSeek.
  Basado en: Pantalla-2.8-TFT_Hola_iRoX.ino

  Hardware:
  + Pantalla 2.8" TFT 240xRGBx320 V1.1 (PCB Roja) chip ILI9341
  + Arduino NANO
  + PCB propio con divisores de voltaje de 5V a 3.3V
*/

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// Asegura las siguientes conexiones al Arduino NANO:
// Pines 8 a 13 con divisores de voltaje de 5V a 3.3V
// NOTA: las macros (#define) tienen los nombres de pin
//       de la pantalla y pueden variar respecto a los
//       ejemplo originales de ADAFRUIT.
// PIN TFT VCC    5V Arduino
// PIN TFT GND    GND  Arduino
#define TFT_RESET 8
#define TFT_DC    9
#define TFT_CS   10
#define TFT_SDI  11
#define TFT_LED  12
#define TFT_SCK  13
Adafruit_ILI9341 tft = Adafruit_ILI9341(
  TFT_CS, TFT_DC, TFT_SDI, TFT_SCK, TFT_RESET, TFT_LED);

// ---- Colores ----
#define RADAR_BG      0x0000   // Negro
#define RADAR_GRID    0x0320   // Verde oscuro
#define RADAR_RING    0x0640   // Verde medio
#define RADAR_TEXT    0x07E0   // Verde brillante
#define RADAR_BLIP    0xF800   // Rojo
#define RADAR_BLIP2   0xFFE0   // Amarillo
#define PANEL_BG      0x0000   // Fondo del panel
#define PANEL_LINE    0x0640   // Línea separadora (verde)
#define PANEL_WHITE   0xFFFF   // Blanco
#define HUD_COLOR     0x07E0   // Verde brillante para el HUD

// ---- Layout horizontal (320x240) ----
const int16_t SCREEN_W = 320;
const int16_t SCREEN_H = 240;

const int16_t PANEL_W  = 70;
const int16_t RADAR_AREA_X0 = PANEL_W;
const int16_t RADAR_AREA_W  = SCREEN_W - PANEL_W;  // 250 px

// Centro del radar dentro del área disponible
const int16_t CX = RADAR_AREA_X0 + RADAR_AREA_W / 2;  // ≈195
const int16_t CY = SCREEN_H / 2 + 6;                  // ≈126
const int16_t R  = 95;

// ---- Barrido ----
int16_t angle = 0;
const int16_t SWEEP_STEP = 3;
const int16_t TRAIL = 20;

// ---- Objetivos ----
struct Target {
  int16_t angle;
  int16_t dist;
  uint16_t color;
};

Target targets[] = {
  {  35,  85, RADAR_BLIP  },
  { 120,  55, RADAR_BLIP2 },
  { 200,  70, RADAR_BLIP  },
  { 275,  40, RADAR_BLIP2 },
  { 320,  90, RADAR_BLIP  },
};
const uint8_t NUM_TARGETS = sizeof(targets) / sizeof(targets[0]);
int16_t targetLastHit[NUM_TARGETS];

// ---- HUD ----
int16_t lastHudAngle = -1;   // Para no redibujar si no cambia

// ============================================================
// Utilidades
// ============================================================
float deg2rad(int16_t deg) { return deg * PI / 180.0; }

int16_t polarX(int16_t deg, int16_t radius) {
  return CX + (int16_t)(cos(deg2rad(deg)) * radius);
}
int16_t polarY(int16_t deg, int16_t radius) {
  return CY + (int16_t)(sin(deg2rad(deg)) * radius);
}

// Devuelve el ancho en píxeles de una cadena con el tamaño de texto actual.
// Útil para alinear a la derecha sin depender del font.
int16_t textWidthPx(const char* s, uint8_t size) {
  return strlen(s) * 6 * size;  // fuente estándar Adafruit: 6x8 px por carácter
}

// ============================================================
// Panel lateral izquierdo
// ============================================================
void drawSidePanel() {
  // Fondo del panel
  tft.fillRect(0, 0, PANEL_W, SCREEN_H, PANEL_BG);

  // Línea separadora vertical
  tft.drawFastVLine(PANEL_W - 1, 0, SCREEN_H, PANEL_LINE);

  // Encabezado
  tft.setTextSize(1);
  tft.setTextColor(RADAR_TEXT);
  tft.setCursor(6, 6);
  tft.print("== iRoX ==");

  tft.drawFastHLine(4, 18, PANEL_W - 8, PANEL_LINE);

  // Etiquetas con línea en blanco entre "Rojas" e "iRoX"
  struct Row { const char* text; uint16_t color; uint8_t gap; };
  Row rows[] = {
    { "BB8",     RADAR_TEXT, 0 },
    { "David",   RADAR_TEXT, 0 },
    { "Rojas",   RADAR_TEXT, 6 },   // <-- espacio extra (línea en blanco) después
    { "iRoX",    RADAR_TEXT, 0 },
    { "Julio",   RADAR_TEXT, 0 },
    { "Sandria", RADAR_TEXT, 0 },
  };
  const uint8_t n = sizeof(rows) / sizeof(rows[0]);

  int16_t y = 28;
  for (uint8_t i = 0; i < n; i++) {
    tft.setTextColor(rows[i].color);
    tft.setTextSize(1);
    tft.setCursor(6, y);
    tft.print(rows[i].text);
    y += 14 + rows[i].gap;
  }

  // ---- Después de "Sandria": línea separadora + fecha ----
  y += 2;                                     // pequeño respiro
  tft.drawFastHLine(4, y, PANEL_W - 8, PANEL_LINE);
  y += 6;

  tft.setTextColor(RADAR_TEXT);
  tft.setTextSize(1);
  tft.setCursor(6, y);
  tft.print("Octubre");
  y += 12;

  tft.setCursor(6, y);
  tft.print("3, 2026");

  // Pie del panel
  tft.drawFastHLine(4, SCREEN_H - 14, PANEL_W - 8, PANEL_LINE);
  tft.setTextColor(RADAR_GRID);
  tft.setCursor(6, SCREEN_H - 10);
  tft.print("v1.0");
}

// ============================================================
// HUD: indicador de ángulo dentro del panel
// ============================================================
void drawHudFrame() {
  // Etiqueta "AZ" y línea base; el valor lo actualiza updateHudAngle()
  tft.setTextSize(1);
  tft.setTextColor(HUD_COLOR);

  // Zona del HUD (parte baja del panel, encima del pie)
  int16_t yHud = SCREEN_H - 46;

  // Título del HUD
  tft.setCursor(6, yHud);
  tft.print("AZIMUTH");

  // Caja del valor
  tft.drawRect(4, yHud + 12, PANEL_W - 8, 20, HUD_COLOR);
}

void updateHudAngle(int16_t a) {
  if (a == lastHudAngle) return;
  lastHudAngle = a;

  int16_t yHud = SCREEN_H - 46;
  int16_t boxX = 4;
  int16_t boxY = yHud + 12;
  int16_t boxW = PANEL_W - 8;
  int16_t boxH = 20;

  // Borra el interior de la caja
  tft.fillRect(boxX + 1, boxY + 1, boxW - 2, boxH - 2, PANEL_BG);

  // Formatea "137" + símbolo de grado. El símbolo ° se dibuja como un pequeño círculo
  char buf[8];
  snprintf(buf, sizeof(buf), "%3d", a);

  tft.setTextSize(2);
  tft.setTextColor(HUD_COLOR);

  // Centrar el número dentro de la caja
  int16_t numW = textWidthPx(buf, 2);
  int16_t tx = boxX + (boxW - numW) / 2 - 2;  // -2 para dejar sitio al símbolo °
  int16_t ty = boxY + (boxH - 16) / 2 + 1;

  tft.setCursor(tx, ty);
  tft.print(buf);

  // Dibujar el símbolo de grado como un pequeño círculo
  int16_t degX = tx + numW + 2;
  int16_t degY = ty + 2;
  tft.drawCircle(degX, degY, 2, HUD_COLOR);
}

// ============================================================
// Fondo estático del radar
// ============================================================
void drawRadarBackground() {
  // Borra solo el área del radar
  tft.fillRect(RADAR_AREA_X0, 0, RADAR_AREA_W, SCREEN_H, RADAR_BG);

  // Círculos concéntricos
  for (int r = 25; r <= R; r += 25) {
    tft.drawCircle(CX, CY, r, RADAR_RING);
  }

  // Líneas radiales cada 30°
  for (int a = 0; a < 360; a += 30) {
    tft.drawLine(CX, CY, polarX(a, R), polarY(a, R), RADAR_GRID);
  }

  // Etiquetas de grados cada 30°
  tft.setTextSize(1);
  tft.setTextColor(RADAR_TEXT);
  for (int a = 0; a < 360; a += 30) {
    int16_t x = polarX(a, R + 10);
    int16_t y = polarY(a, R + 10);
    char buf[5];
    snprintf(buf, sizeof(buf), "%d", a);
    tft.setCursor(x - 6, y - 4);
    tft.print(buf);
  }

  // Cruz central
  tft.drawFastHLine(CX - 4, CY, 8, RADAR_TEXT);
  tft.drawFastVLine(CX, CY - 4, 8, RADAR_TEXT);

  // Título "RADAR" alineado a la DERECHA del área del radar
  tft.setTextSize(2);
  tft.setTextColor(RADAR_TEXT);
  const char* title = "RADAR";
  int16_t titleW = textWidthPx(title, 2);
  int16_t titleX = SCREEN_W - titleW - 6;   // 6 px de margen derecho
  int16_t titleY = 6;
  tft.setCursor(titleX, titleY);
  tft.print(title);
}

// ============================================================
// Barrido
// ============================================================
void drawSweep(int16_t currentAngle) {
  tft.drawLine(CX, CY, polarX(currentAngle, R), polarY(currentAngle, R), RADAR_TEXT);

  for (int i = 1; i <= TRAIL; i++) {
    int16_t a = currentAngle - i * SWEEP_STEP;
    if (a < 0) a += 360;

    uint16_t c;
    if      (i < TRAIL / 3)     c = 0x07E0;
    else if (i < 2 * TRAIL / 3) c = 0x03E0;
    else                        c = 0x01A0;

    tft.drawLine(CX, CY, polarX(a, R), polarY(a, R), c);
  }
}

void eraseSweep(int16_t currentAngle) {
  int16_t a = currentAngle - TRAIL * SWEEP_STEP;
  if (a < 0) a += 360;
  tft.drawLine(CX, CY, polarX(a, R), polarY(a, R), RADAR_BG);
  redrawOverlayAtAngle(a);
}

void redrawOverlayAtAngle(int16_t deg) {
  for (int r = 25; r <= R; r += 25) {
    tft.drawPixel(polarX(deg, r), polarY(deg, r), RADAR_RING);
  }
  for (int a = 0; a < 360; a += 30) {
    int16_t diff = abs(deg - a);
    if (diff < 3 || diff > 357) {
      tft.drawLine(CX, CY, polarX(a, 25), polarY(a, 25), RADAR_GRID);
      break;
    }
  }
}

// ============================================================
// Blips
// ============================================================
void drawBlips() {
  for (uint8_t i = 0; i < NUM_TARGETS; i++) {
    int16_t deg = targets[i].angle;
    int16_t r   = targets[i].dist;
    int16_t x   = polarX(deg, r);
    int16_t y   = polarY(deg, r);

    int16_t diff = abs(angle - deg);
    if (diff > 180) diff = 360 - diff;
    if (diff < SWEEP_STEP * 2) targetLastHit[i] = angle;

    if (targetLastHit[i] >= 0) {
      int16_t age = angle - targetLastHit[i];
      if (age < 0) age += 360;

      if (age < 60) {
        tft.fillCircle(x, y, 3, targets[i].color);
      } else if (age < 120) {
        tft.drawCircle(x, y, 3, targets[i].color);
      } else {
        tft.fillCircle(x, y, 3, RADAR_BG);
        for (int rr = 25; rr <= R; rr += 25) {
          if (abs(r - rr) < 3) tft.drawPixel(x, y, RADAR_RING);
        }
        targetLastHit[i] = -1;
      }
    }
  }
}

// ============================================================
// Setup / Loop
// ============================================================
void setup() {
  Serial.begin(9600);
  Serial.println("Radar ILI9341 horizontal iniciando...");

  tft.begin();
  tft.setRotation(1);   // 1 = apaisado (320x240)

  drawSidePanel();
  drawHudFrame();
  drawRadarBackground();
  updateHudAngle(0);

  for (uint8_t i = 0; i < NUM_TARGETS; i++) targetLastHit[i] = -1;

  Serial.println("Radar listo.");
}

void loop() {
  eraseSweep(angle);
  drawSweep(angle);
  drawBlips();
  updateHudAngle(angle);

  angle += SWEEP_STEP;
  if (angle >= 360) angle -= 360;

  delay(20);
}

Si tienes un proyecto por hacer con Lego Mindstorms, Arduino, Esp32, Raspberry Pi, Jetson Nano o necesitas ayuda con la programación en C/C++, Python, Java, JavaScript, o con el uso de herramientas de inteligencia artificial, no dudes en contactarnos en el Instituto de Robótica de Xalapa a través del sitio web www.irox.mx.

Matriz de 11×2 LEDs controlada con Arduino para un R2D2

Autor: Julio César Sandria Reynoso
Fecha: 9 de noviembre de 2024

Robot tipo R2D2

En este artículo se presenta un proyecto de creación de una matriz de 11×2 LEDs que se controlan con Arduino para colocarlos en una ranura de un robot similar al R2D2 de las películas Star Wars.

Semanas atrás, uno de los alumnos del Instituto de Robótica de Xalapa (iRoX) llevó su robot R2D2 para hacerle algunas mejoras. Una de esas mejoras consiste en ponerle LEDs en algunas de las ranuras de la cabeza.

Una de esas ranuras es rectangular de 9 cm X 1.2 cm, donde se puede colocar una matriz de 11×2 LEDs por dentro de la cabeza para que se pueda ver su encendido desde el exterior.

Cabeza de R2D2

La idea de poner varios LEDs fue para emular un tanto la forma en que trabaja el robot de las películas, encendiendo de diversas formas los LEDs de esa ranura.

Algunos de los alumnos participaron en el diseño de la sección rectangular para la colocación de los LEDs, inicialmente se consideró una tabla de MDF de 3mm cortada en láser para colocar allí los LEDs, pero se descartó porque con una placa fenólica perforada fue suficiente.

La disposición de los 22 LEDs, con resistencias, transistores y conexiones a Arduino se diseñó en Tinkercad. De hecho, en esta plataforma se hizo también la programación inicial y simulación de su funcionamiento, lo cual se muestra en el artículo Arreglo de 22 LEDS (11×2) con encendido aleatorio con Arduino en Tinkercad.

Arreglo de LEDs en 11 columnas y 2 filas conectados con transistores a Arduino UNO

Después del diseño del circuito en Tinkercad, se procedió a soldar los componentes en la placa fenólica. El material usado es el siguiente:

  • Placa fenólica perforada
  • 22 LEDs de diferentes colores
  • 11 resistencias de 220 Ohms
  • 2 transistores 2N2222
  • 2 resistencias de 1 KOhm
  • Cable UTP
  • Tira de pines macho 90° (14 conectores)
Componentes soldados a la placa fenólica

Una vez soldados todos los componentes como se ve en la imagen «Componentes soldados a la placa fenólica», se conectaron cables Dupont hembra-macho del circuito al Arduino UNO de la siguiente forma:

  • Los primeros 11 cables de izquierda a derecha se conectan a los pines digitales 10 a 0 de Arduino respectivamente.
  • El antepenúltimo cable (amarillo) se conecta al pin analógico A0.
  • El penúltimo cable (naranja) se conecta al pin analógico A1.
  • El último cable (rojo) se conecta a GND.

Una vez conectado todo, se cargó el siguiente programa C++ desde Arduino IDE al Arduino UNO.

// Programa C++ para Arduino
// Autor: Julio César Sandria Reynoso
// Fecha: Noviembre 2024
// Arreglo de LEDs de 11 columnas X 2 filas,
// enciende LEDs de forma aleatoria o con ciertos patrones
#define columnas 11
#define filas 2
int Columnas[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int Filas[] = {A0, A1};
int ledColumna[columnas];
int ledFila[columnas];

void setup() {
  for (int col = 0; col < columnas; col++)
    pinMode(Columnas[col], OUTPUT); 
  for (int fila = 0; fila < filas; fila++)
    pinMode(Filas[fila], OUTPUT);
}

void loop() {
  // Enciende un led iniciando en la primera fila de 
  // izquierda a derecha y terminando en la segunda 
  // fila a la izquierda
  for(int t=100; t>=40; t=t-20)
    ledPorFila(t,0);

  // Enciende de 1 a 5 leds de forma aleatoria durante un tiempo
  // de 100 + i*50 ms y apagándolos 0 ms
  for(int i=1; i<6; i++)
    ledsAleatorios(i,100+i*50,0);

  // Enciende 6 leds de forma aleatoria durante 50 iteraciones
  for(int i=0; i<50; i++)
    ledsAleatorios(6,350,0);
}

void ledPorFila(int tEncendido, int tApagado) {
  for(int i=columnas-1; i>=0; i--) {
    digitalWrite(Filas[0], HIGH);
    digitalWrite(Columnas[i], HIGH);
    delay(tEncendido);

    digitalWrite(Filas[0], LOW);
    digitalWrite(Columnas[i], LOW);
    delay(tApagado);
  }
  for(int i=0; i<columnas; i++) {
    digitalWrite(Filas[1], HIGH);
    digitalWrite(Columnas[i], HIGH);
    delay(tEncendido);

    digitalWrite(Filas[1], LOW);
    digitalWrite(Columnas[i], LOW);
    delay(tApagado);
  }
}

void ledsAleatorios(int nLeds, int tEncendido, int tApagado) {
  // Los arreglos ledFila[] y ledColumna[] tienen <columnas> elementos,
  // de los cuales solo se usan <nLeds> elementos en esta función.
  // Es posible que de forma aleatoria se repita un led a encender,
  // pero es imperceptible o poco notorio durante la ejecución.
  // Encendemos los nLeds indicados, durante <tEcendido> milisegundos
  for(int i=0; i<nLeds; i++) {
    ledFila[i] = random(0, filas);
    ledColumna[i] = random(0, columnas);
    digitalWrite(Columnas[ledColumna[i]], HIGH);
    digitalWrite(Filas[ledFila[i]], HIGH);
  }
  delay(tEncendido);
  // Apagamos todos los leds encendidos
  for(int i=0; i<nLeds; i++) {
    digitalWrite(Columnas[ledColumna[i]], LOW);
    digitalWrite(Filas[ledFila[i]], LOW);    
  }
  delay(tApagado);
}

Las siguientes fotografías son del circuito funcionando.

Al probar el programa se detectó que algunos LEDs no encendían, por lo que se hizo una revisión exhaustiva, encontrando algunos errores de soldadura, que se fueron resolviendo.

Con este tipo de proyectos, donde los alumnos practican los temas que se van viendo en el iRoX, los alumnos se sienten motivados a aprender aún mucho más.

Si te interesa aprender más sobre programación en C++, Arduino, robótica u otros lenguajes de programación, visita el sitio web del Instituto de Robótica de Xalapa (www.irox.mx) y contáctanos. Si estás en una región cercana a Xalapa, como Veracruz, Boca del Río, Córdoba, Martínez de la Torre, etc., puedes visitar las instalaciones del iRoX entre semana o un sábado y hablar con nuestros profesores sobre proyectos de robótica o tecnología.

Agradecemos a los alumnos que están participando en este proyecto: David, Germán, Fernando, Carlo y Max.

Arreglo de 22 LEDS (11×2) con encendido aleatorio con Arduino en Tinkercad

Instituto de Robótica de Xalapa - iRoX

Autor: Julio César Sandria Reynoso
Fecha: 19 de octubre de 2024

En este artículo se presenta un proyecto en Tinkercad (www.tinkercad.com) haciendo un circuito para conectar 22 LEDs en un arreglo de 11 columnas y 2 filas, con encendido aleatorio de los LEDs.

Lo interesante de este proyecto es mostrar cómo, teniendo únicamente 20 pines de entrada/salida en Arduino UNO (14 digitales y 6 analógicos), podemos conectar 22, 30 ó 45 LEDs y controlarlos fácilmente mediante programación C++ en Arduino.

Arreglo de LEDs en 11 columnas y 2 filas conectados con transistores a Arduino UNO

En la imagen se puede ver que en forma de columna, se conectan dos LEDs a cada uno de los pines digitales 0 a 10 de Arduino. Por ejemplo, viendo los LEDs de derecha a izquierda, en los primeros dos LEDs los ánodos (+) se conectan entre si, después a una resistencia de 220 Ohms y la resistencia se conecta al pin 0 de Arduino. Y así sucesivamente se conectan los demás LEDs.

En la primera fila de 11 LEDs (los de arriba), se conectan entre si sus cátodos (-), y todos ellos se conectan a la patilla C (colector) del transistor NPN de la derecha. La patilla E (emisor) se conecta a tierra (GND de Arduino) y la patilla B (base) se conecta a una resistencia de 1 KOhm y ésta al pin analógico A0 de Arduino.

De forma similar, la segunda fila de 11 LEDs se conectan sus cátodos (-) al transistor NPN de la izquierda y la patilla B (base) se conecta con una resistencia de 1 Ohm de por medio, al pin A1 de Arduino.

Para encender los primeros dos LEDs de la derecha, se activa el pin 0 de Arduino con digitalWrite(0,HIGH), pero esto por si solo no enciende ninguno de los dos LEDs. Para encender el primer LED de la derecha-arriba, se debe activar el pin A0 de Arduino con digitalWrite(A0,HIGH). Con esto, se envía el voltaje necesario a la base del transistor de la derecha, lo que cierra el circuito entre el colector y emisor de dicho transistor, permitiendo el flujo de corriente desde el pin 0 de Arduino, pasando por el LED (derecha-arriba), el transistor derecho, hasta el GND de Arduino.

El programa siguiente implementa el encendido de forma aleatoria de un LED durante 15 veces y después el encendido de dos LEDs de forma aleatoria durante 20 veces. Esto se repite mientras se ejecute la simulación en Tinkercad.

// Programa C++ para Arduino
// Arreglo de LEDs de 11 columnas X 2 filas,
// enciende un LED de forma aleatoria y
// después enciende dos LEDs de forma aleatoria
int Columnas[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int Filas[] = {A0, A1};
int columnas = 11;
int filas = 2;

void setup() {
  for (int col = 0; col < columnas; col++)
    pinMode(Columnas[col], OUTPUT); 
  for (int fila = 0; fila < filas; fila++)
    pinMode(Filas[fila], OUTPUT);
}

void loop() {
  // 15 veces encendemos un led de forma aleatoria
  ledAleatorio(15);
  // 20 veces encendemos dos leds de forma aleatoria
  ledAleatorio2(20);
}

void ledAleatorio(int n) {
  int aFila;
  int aColumna;

  for(int i=0; i<n; i++) {
    aFila = random(0, filas);
    aColumna = random(0, columnas);

    digitalWrite(Filas[aFila], HIGH);
    digitalWrite(Columnas[aColumna], HIGH);
    delay(300);

    digitalWrite(Filas[aFila], LOW);
    digitalWrite(Columnas[aColumna], LOW);
    delay(200);
  }
}

void ledAleatorio2(int n) {
  int aFila;
  int aColumna;
  int a2Fila;
  int a2Columna;
  
  for(int i=0; i<n; i++) {
    aFila = random(0, filas);
    aColumna = random(0, columnas);
    a2Fila = random(0, filas);
    a2Columna = random(0, columnas);

    digitalWrite(Filas[aFila], HIGH);
    digitalWrite(Columnas[aColumna], HIGH);
    digitalWrite(Filas[a2Fila], HIGH);
    digitalWrite(Columnas[a2Columna], HIGH);
    delay(300);

    digitalWrite(Filas[aFila], LOW);
    digitalWrite(Columnas[aColumna], LOW);
    digitalWrite(Filas[a2Fila], LOW);
    digitalWrite(Columnas[a2Columna], LOW);
    delay(200);
  }
}

Si te interesa aprender más sobre programación en C++, Arduino, robótica u otros lenguajes de programación, visita el sitio web del Instituto de Robótica de Xalapa (www.irox.mx) y contáctanos. Si estás en una región cercana a Xalapa, como Veracruz, Boca del Río, Córdoba, Martínez de la Torre, etc., puedes visitar las instalaciones del iRoX entre semana o un sábado y hablar con nuestros profesores sobre proyectos de robótica o tecnología.