Una pantalla mas grande para el ESP32


En un post anterior vimos como usar una pequeña pantalla OLED con un ESP32. Ciertamente una pantalla pequeña consume menos y ocupa muy poco espacio, pero cuando no tenemos esos problemas, es mas interesante usar una pantalla algo mas grande, pues aunque pueda parecer elegante, en realidad con una pantalla tan pequeña apenas hay sitio para mostrar información (además de que posiblemente cueste lo mismo y además suelen usar los mismo pines de datos).

En este post vamos usar la AZ-Delivery 1.77″ ST7735 con ESP32 (comprado en Amazon en https://amzn.to/4pK0utQ ) y la librería de Adafruit donde solo tenemos que adaptar el constructor y asegurarnos de que el cableado coincide con los pines correctos (en nuestro caso 14,13,12,27,26).

Atención porque aunque el manual de Az-Delivery que nos ofrece este pantalla solo muestren como ejemplo un Arduino mega con un adaptador ( ver figura mas abajo), es posible conectar directamente la pantalla AZDelivery de 1.77 pulgadas ST7735 al ESP32 sin conversor de nivel lógico.

En caso de usar un Arduino Uno como hemos visto arriba, el cableado se complica dado que tenemos adaptar 4 líneas de datos a los niveles de 3.3v. Como vemos para configurar este adaptador, se debe conectar el pin VA del LCC a +3.3V y el pin VB a +5V. El pin OE debe unirse a +3.3V mediante una resistencia de arranque de 1 kΩ, mientras que el pin GND se conecta a tierra. En esta configuración, el lado “A” del LCC trabaja con señales de bajo nivel (3.3V) y el lado “B” con señales de alto nivel (5V), tal como se muestra en el diagrama de conexión.

Es muy importante destacar que como el ESP32 opera a niveles lógicos de 3.3V, compatibles con los requisitos de la pantalla (2.7V-3.3V) NO NECESITA UN SHIFTER , a diferencia del Arduino Uno o un ATMega328P que usan 5V y necesitan un shifter como el TXS0108E.

Aclarado este aspecto del conversor que NO NECESITAMOS usando un ESP32, en la imagen vemos las 8 conexiones dela pantalla , por cierto en el mismo orden que la pantalla pequeña que vimos en un post anterior:

Una vez vistas las conexiones, el cableado con los pines elegidos y funcionales debe mantenerse exactamente el mismo mapeo que usábamos en la pantalla de 0.96″:

  • SCL/SCK → GPIO14 (SCK del bus SPI)
  • SDA/MOSI → GPIO13 (MOSI)
  • RES/RST → GPIO12
  • DC/A0 → GPIO27
  • CS → GPIO26
  • VCC → 3.3V
  • GND → GND
  • LED/BL → 3.3V (o a un GPIO si quieres controlar el brillo)​

En el código también debemos ajustar el constructor de Adafruit. En lugar de:

Adafruit_ST7735 tft = Adafruit_ST7735(10, 8, 9);

Usa tus pines (CS, DC, RST):
#define TFT_CS   26
#define TFT_DC 27
#define TFT_RST 12

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

El resto del SPI (SCK=14, MOSI=13) lo maneja SPI por hardware. No hace falta pasarlos al constructor si usamos el SPI por defecto del ESP32.​

Inicialización correcta para 1.77″ 128×160

En setup() usaremos el inicializador recomendado para 1.77″ (Adafruit lo llama “INITR_BLACKTAB” o “INITR_GREENTAB”; muchas 1.77″ van bien con BLACKTAB):

void setup(void) {
SPI.begin(14, -1, 13, 26); // SCK=14, MISO sin usar (-1), MOSI=13, CS=26
tft.initR(INITR_BLACKTAB); // si ves colores raros, prueba INITR_GREENTAB
tft.fillScreen(ST77XX_BLACK);
delay(500);
show_page();
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.setTextSize(2);
tft.setFont(); // vuelve a la fuente por defecto
}

Fíjate que es setTextColor, no setTextcolour (esa grafía daría error de compilación).​

Se pueden utilizar cualquiera de los siguientes colores predefinidos:
ST77XX_BLACK
ST77XX_RED
ST77XX_BLUE
ST77XX_MAGENTA
ST77XX_ORANGE
ST77XX_WHITE
ST77XX_GREEN
ST77XX_CYAN
ST77XX_YELLOW

O también, se pueden utilizar números hexadecimales de 4-bits que representan un color específico (por ejemplo 0x2AFF)

Las fuentes se encuentran en la carpeta de la librería Adafruit_GFX: … > Arduino > libraries > Adafruit_GFX_Library > Fonts Cuando se importa una fuente específica, se debe importar la librería de fuentes después de la librería Adafruit_GFX, como en las siguientes líneas del código de ejemplo

4. Código adaptado para ESP32 y pines deseados

Aquí sin mas dilaciones un ejemplo de sketch funcional ajustado a un ESP32 con librerías Adafruit y usando los pines descritos ( y por supuesto probado en este humilde blog):

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Adafruit_ST7735.h>

#define TFT_CS 26
#define TFT_DC 27
#define TFT_RST 12

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

void setup(void) {
// SPI en los pines que quieres: SCK=14, MOSI=13
SPI.begin(14, -1, 13, TFT_CS);

tft.initR(INITR_BLACKTAB); // o INITR_GREENTAB si hace falta
tft.fillScreen(ST77XX_BLACK);
delay(500);
show_page();
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.setTextSize(2);
tft.setFont(); // fuente por defecto (bitmap)
}

void loop() {
for (uint8_t i = 0; i < 100; i++) {
changing_value(i);
// delay(100);
}
}

void show_page() {
tft.setFont(&FreeSansBold9pt7b);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setCursor(14, 22);
tft.print("AZ-Delivery");

tft.drawFastHLine(0, 35, 128, ST77XX_GREEN);

tft.drawTriangle(1, 45, 28, 70, 55, 45, ST77XX_WHITE);
tft.fillTriangle(78, 70, 104, 45, 127, 70, 0xA3F6);

tft.drawRect(1, 80, 50, 30, ST77XX_BLUE);
tft.fillRoundRect(78, 80, 50, 30, 5, 0x2D4E);

tft.fillCircle(25, 135, 15, 0x5BA9);
tft.drawCircle(102, 135, 15, ST77XX_GREEN);
tft.drawLine(45, 150, 80, 40, ST77XX_ORANGE);
}

void changing_value(uint8_t value) {
tft.setFont(&FreeSansBold9pt7b);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);

if (value < 10) {
tft.setCursor(15, 88);
tft.print("0");
tft.print(value);
} else {
tft.setCursor(15, 88);
tft.print(value);
}
}

Este código muestra cómo inicializar y manejar una pantalla TFT basada en el controlador ST7735 usando la librería Adafruit_ST7735 junto con Adafruit_GFX. Primero se definen los pines de conexión del display (CS, DC y RST) y luego se configura la comunicación SPI utilizando pines personalizados para SCK (14) y MOSI (13). En la función setup(), se inicializa la pantalla con un estilo determinado (INITR_BLACKTAB), se limpia con color negro y se llama a la función show_page(), que dibuja una página inicial con texto, líneas, triángulos, rectángulos y círculos de distintos colores, mostrando las capacidades gráficas de la librería.

En la función loop(), el programa recorre valores del 0 al 99 y los muestra en pantalla mediante la función changing_value(). Esta función actualiza una cifra en una posición fija de la pantalla usando una fuente más grande (FreeSansBold9pt7b) y color blanco sobre fondo negro. De esta forma, el código demuestra tanto cómo renderizar gráficos estáticos (formas y texto) como cómo actualizar valores dinámicos en la pantalla TFT, lo que resulta útil para interfaces visuales en proyectos con microcontroladores, por ejemplo, medidores o indicadores en sistemas embebidos.

Con esto mantenemos exactamente las mismas líneas SPI (14,13,12,27,26) que ya teníamos en la pantalla mas pequeña y aprovechamos la librería oficial de Adafruit para el ST7735 de la AZ-Delivery.​

Emulación de Zumo32u4 (puertos E/S y LCD)


El robot Zumo 32U4, un modelo compacto, programable y listo para usar, basado en el microcontrolador ATmega32U4 y compatible con Arduino. Mide menos de 10×10 cm, pesa unos 160 g sin baterías y está especialmente diseñado para competiciones Mini-Sumo. Incorpora motores con reductoraencoderspantalla OLEDsensores de línea y proximidad, una IMU (acelerómetro, giroscopio y magnetómetro), además de botones, LEDs y un buzzer para interacción.

El robot se programa directamente desde el entorno Arduino, sin necesidad de montaje previo, y se puede ampliar mediante sus líneas de E/S y alimentación, lo que lo hace ideal tanto para educación como para competición robótica.

En este blog nos hemos propuesto emular el Zumo 32U4 con hardware más sencillo y económico de un modo general https://soloelectronicos.com/2025/12/10/emulacion-de-zumo32u4-con-un-arduino/ (por ejemplo, con un Arduino Uno o Nano, controlador L298N, motores DC, pantalla LCD, LEDs y pulsadores).

También se ha tratado el sonido, un tema especialmente atractivo por su «sencillez» y resultados https://soloelectronicos.com/2025/12/11/emulacion-zumo-de-sonidos-con-atmega/

Esta emulación ofrece varias ventajas:

  • Económica y accesible, permitiendo disponer de más unidades para enseñanza o experimentación.
  • Formativa, ya que obliga a conectar y comprender cada componente (drivers, PWM, control de motor, entradas y salidas).
  • Compatible y útil para desarrollo de código, permitiendo probar lógicas de control sin necesitar el robot original.
  • Flexible y robusta, ideal para investigación o docencia, ya que se pueden introducir fallos o modificar el hardware sin riesgo.

Para emular el Zumo 32U4 con un ATmega328P y poder usar las clases de la librería Zumo32U4 (buttons, motors, buzzer, LEDs), como ya se ha hablado, necesitamos replicar su “interfaz lógica”: mismos pines Arduino que espera la librería, pero cableados a nuestro hardware equivalente.​ Hemos hablado de motores, pulsadores,leds y el sonido .

En este ultimo post vamos a resumir todos lo dispositivos fácilmente emulables ( leds, motores, pulsadores, buzzer ) a la vez que vamos a intentar sopesar el tema de la pantalla y su emulación con un Arduino Mega.

RESUMEN DE LA EMULACION DE ZUMO TRATADA EN POST ANTERIORES

1. Qué espera la librería Zumo32U4:La documentación indica, a nivel de pines Arduino:

  • Botón A → pin digital 14 (A0)
  • Botón B → pin digital 4
  • Botón C → pin digital 17 (A3)
  • LED amarillo usuario → pin 13
  • LED rojo usuario → mismo pin que botón C (17/A3)
  • Motores:
    • Motor derecho velocidad (PWM) → pin 9
    • Motor derecho dirección → pin 15 (A1)
    • Motor izquierdo velocidad (PWM) → pin 10
    • Motor izquierdo dirección → pin 16 (A2)
  • Buzzer → pin 6

Las clases de la librería (Zumo32U4ButtonA/B/CZumo32U4MotorsZumo32U4Buzzer, etc.) asumen estos números de pin.

2. Estrategia con ATmega328P (Uno “emulado”): como un ATmega328P no tiene el mismo mapeo interno, tenemos dos opciones:

  1. No tocar la librería y cablear tus periféricos a los mismos números de pin Arduino que usa el Zumo.
  2. Modificar la librería para cambiar números de pin a otros de nuestro gusto.

Lo más sencillo es la opción 1, es decir cablear de esta forma en una placa tipo Uno/Nano​

La asignación recomendada (para no tocar la librería), suponiendo que compilamos como si fuera un Zumo32U4 (core 32U4) es complicado en un 328P, así que la forma práctica es reusar los números de pin lógicos y adaptar el hardware:

Botones (normalmente abiertos a GND, INPUT_PULLUP)

  • Botón A:
    • Zumo: pin 14 (A0) → en tu 328P: usa A0.
  • Botón B:
    • Zumo: pin 4 → en tu 328P: usa D4.
  • Botón C:
    • Zumo: pin 17 (A3) → en tu 328P: usa A3.

Cableado:

  • Un terminal del pulsador → pin (A0, D4, A3).
  • Otro terminal → GND.
  • En código se usará INPUT_PULLUP, lógica: LOW = pulsado.

Motores (con L298N)

  • Motor derecho:
    • Velocidad (PWM): Zumo pin 9 → usa D9.
    • Dirección: Zumo pin 15 (A1) → usa A1 (o D3/D5 si prefieres digital puro).
  • Motor izquierdo:
    • Velocidad (PWM): Zumo pin 10 → usa D10.
    • Dirección: Zumo pin 16 (A2) → usa A2.

Ejemplo lógico:

  • L298N IN1/IN2 ← A1/D9 (derecha).
  • L298N IN3/IN4 ← A2/D10 (izquierda).

LEDs externos

  • LED amarillo:
    • Zumo: pin 13 → usa D13 (LED integrado + LED externo en serie o separado).
  • LED rojo:
    • Zumo: comparte pin con botón C (17/A3) → en una emulación es más cómodo usar otro pin y luego adaptar la librería, pero si quieres ser fiel:
      • LED rojo + resistor → A3.
      • Botón C comparte A3 y se detecta por lectura del pin.

Buzzer

  • Zumo: pin 6
  • Para compatibilidad con la clase Zumo32U4Buzzer, tendrías que:
    • O bien mover tu buzzer a D6.
    • O bien modificar la librería para que use pin 7.

3. Uso práctico con ATmega328P: la librería Zumo32U4 está pensada para un ATmega32U4 (Leonardo/Micro-like). Compilarla tal cual sobre un core Uno (328P) nos va a dar problemas porque internamente usa características específicas del 32U4 (USB, Timer4, etc.). Para nuestro objetivo (emulación docente):

  • Más viable:
    • Copiar solo las ideas/clases y escribir nuestras propias mini-clases equivalentes para 328P:
      • class ButtonA { pinMode(A0, INPUT_PULLUP); bool isPressed() { return !digitalRead(A0); } };
      • class Motors { … } que use los pines de L298N.
      • class Buzzer { tone(7, f); … } con el pin 7.
  • Si insistes en usar exactamenteZumo32U4.h:
    • Compila con un core de placa 32U4 (por ejemplo, seleccionar “Arduino Leonardo”) aunque el hardware real sea un 328P no es correcto eléctricamente.
    • O crea una “board definition” personalizada para 328P que imite los nombres de pines y timers del 32U4 (trabajo considerable).

4. Resumen de pines para una emulacion (versión directa 328P): para dejarlo claro, si ignoramos la librería y solo queremos el mismo comportamiento:

  • Botón A: A0 (NO a GND, INPUT_PULLUP).
  • Botón B: D4 (NO a GND).
  • Botón C: A3 (NO a GND).
  • Motor derecho: PWM D9, dirección A1.
  • Motor izquierdo: PWM D10, dirección A2.
  • LED amarillo: D13.
  • LED rojo: D12 (o A3 si quieres imitar el multiplexado).
  • Buzzer: D7 (y usas tone(7, f)).

La librería Zumo32U4 solo funciona con microcontroladores ATmega32U4 y no con ATmega328P (Arduino Uno u otros). Es recomendable por tanto seleccionar una placa basada en 32U4 (como A-Star 32U4) en el menú Boards para usar esa librería.

Opciones para seguir con un ATmega328P (Arduino Uno):

  1. No usar la librería Zumo32U4 directamente, porque está diseñada específicamente para 32U4 y usa características hardware exclusivas ( ES JUSTAMENTE LO QUE SE HA TRATADO EN ESTE POST Y POST ANTERIOES).
  2. Crear tu propia implementación “simulada” de las clases Button, Motor, Led y Buzzer usando pines ATmega328P (tal como definimos los mapeos) para emular la funcionalidad básica.
  3. Cambiar a usar una placa basada en ATmega32U4 (como Arduino Leonardo, Micro o la A-Star 32U4) si quieres usar la librería oficial.

DISPLAY EMULADO

Centrémonos a ahora en la emulación de un Display OLED Zumo32U4 con LCD I2C ATmega328P

El Zumo32U4 tiene un display OLED 1.3″ monocromo (128×64 píxeles) conectado por I2C. EL Típico u LCD I2C es perfecto para emularlo. Es cierto que en versiones posteriores se ha sustituido por una pantalla OLED, pero por simplificar nos centraremos en el LCD dado que requiere menos lineas GPIO.

Debemos en el entorno Arduino importar la librería correspondiente:

Librería Display Zumo32U4 → LiquidCrystal_I2C

Zumo32U4Tu LCD I2C
Zumo32U4OLEDLiquidCrystal_I2C
I2C: SDA A4, SCL A5Igual: A4, A5
Texto 21×4 caracteresTu LCD 16×2/20×4

Y respecto a los pines I2C (Fijos – No cambies)

Display I2C LCD:
SDA → A4 (todos Arduino)
SCL → A5 (todos Arduino) 
VCC → 5V
GND → GND

No debemos ante de nada olvidar la instalación de la Librería LCD I2C

Arduino IDE → Tools → Manage Libraries
Buscar: **"LiquidCrystal I2C"** → Frank de Brabander
Instalar → Reiniciar IDE

Asimismo, es crucial encontrar Dirección I2C de tu Display, para lo cual una vez todo conectado podemos usar el siguiente código en nuestro entorno Arduino:

// Scanner I2C - Ejecuta UNA vez
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("I2C Scanner");
}
void loop() {
for(byte i=8; i<120; i++) {
Wire.beginTransmission(i);
if (Wire.endTransmission() == 0) {
Serial.print("I2C: 0x"); Serial.println(i, HEX);
}
}
delay(5000);
}

Las direcciones típicas son 0x27 o 0x3F. Cambia en LiquidCrystal_I2C lcd(0x27, 16, 2);

Veamos ahora finalmente ver un ejemplo de código que usa un display con tres leds y dos pulsadores descritos estos últimos en post anteriores.

Código Completo: Emulación Display + LEDs + Botones

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Emulación Zumo32U4 display (16x2 típico)
LiquidCrystal_I2C lcd(0x27, 16, 2); // Cambia 0x27 por tu dirección I2C

#define BUTTON_A_PIN A0
#define BUTTON_B_PIN 4
#define LED_YELLOW_PIN 13
#define LED_RED_PIN 12

void setup() {
// Inicializar LCD I2C (emula Zumo OLED)
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Zumo32U4 EMU");
lcd.setCursor(0, 1);
lcd.print("Display OK!");
delay(2000);

// Botones y LEDs
pinMode(BUTTON_A_PIN, INPUT_PULLUP);
pinMode(BUTTON_B_PIN, INPUT_PULLUP);
pinMode(LED_YELLOW_PIN, OUTPUT);
pinMode(LED_RED_PIN, OUTPUT);
}

void loop() {
bool btnA = digitalRead(BUTTON_A_PIN) == LOW;
bool btnB = digitalRead(BUTTON_B_PIN) == LOW;

// LED ROJO: ON cuando botón A NO pulsado
digitalWrite(LED_RED_PIN, !btnA);

// LED AMARILLO: ON cuando botón B pulsado
digitalWrite(LED_YELLOW_PIN, btnB);

// EMULAR DISPLAY ZUMO32U4
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BtnA:"); lcd.print(btnA ? "ON " : "OFF");
lcd.print(" BtnB:"); lcd.print(btnB ? "ON " : "OFF");

lcd.setCursor(0, 1);
lcd.print("Red:"); lcd.print(digitalRead(LED_RED_PIN) ? "ON " : "OFF");
lcd.print("Yel:"); lcd.print(digitalRead(LED_YELLOW_PIN) ? "ON" : "OFF");

delay(200); // Refresh 5Hz
}

Este código simula parte de la interfaz del robot Zumo 32U4 usando un Arduino con una pantalla LCD I2C y algunos elementos básicos como LEDs y botones. En la función setup(), se inicializa la pantalla LCD para mostrar un mensaje de bienvenida (“Zumo32U4 EMU – Display OK!”) y se configuran los pines: dos entradas con resistencia pull-up para los botones (A y B) y dos salidas para los LEDs rojo y amarillo. De este modo, se prepara el entorno para imitar la interacción que tendría un Zumo real con su pantalla y entradas físicas.

En el bucle principal loop(), el programa lee el estado de los botones y ajusta los LEDs de forma inversa o directa según el botón pulsado. Luego actualiza continuamente el LCD para mostrar en tiempo real el estado de los botones y de los LEDs, lo que permite verificar visualmente la interacción. Con un retardo de 200 ms (frecuencia de unas 5 actualizaciones por segundo), esta implementación emula de manera sencilla cómo el Zumo muestra información y responde a los mandos del usuario, sirviendo como práctica educativa de entrada/salida digital y manejo de pantallas I2C.

PROYECTO FINAL

Y ahora ya finalmente al proyecto anterior le añadimos la gestión de los motores junto a todo lo demás:

BOTONES:
A0 ← Btn A → GND
D4 ← Btn B → GND
A3 ← Btn C → GND

LEDS:
D13 ← LED Amarillo → 220Ω → GND
D12 ← LED Rojo → 220Ω → GND

BUZZER:
D6 ← Buzzer → GND

L298N:
D3 ← ENA (Izq)
A2 ← IN1 (Izq Dir)
D11 ← ENB (Der)
A1 ← IN3 (Der Dir)
OUT1,2 → Motor Izq
OUT3,4 → Motor Der

A continuación mostramos un código funcional que ejemplariza le emulación de la gestión del display LCD, pulsadores, leds y botones:

<Wire.h>
<LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);

BUTTON_A_PIN A0 // AVANZAR
BUTTON_B_PIN 4 // RETROCEDER
BUTTON_C_PIN A3 // PARAR
LED_YELLOW_PIN 13
LED_RED_PIN 12
BUZZER_PIN 6

// ✅ PINS L298N COMPLETOS
M1_ENA_PIN 3 // Enable Motor Izq (PWM)
M1_DIR_PIN A2 // Dirección Motor Izq
M2_ENB_PIN 11 // Enable Motor Der (PWM)
M2_DIR_PIN A1 // Dirección Motor Der

bool lastBtnA = false, lastBtnB = false, lastBtnC = false;
String estado = «PARADO»;

void setup() {
Wire.begin();
lcd.init(); lcd.backlight(); lcd.clear();
lcd.setCursor(0,0); lcd.print(«Zumo32U4 v3.0»);
lcd.setCursor(0,1); lcd.print(«Motores OK»);
delay(2000);

// Botones con pull-up
pinMode(BUTTON_A_PIN, INPUT_PULLUP);
pinMode(BUTTON_B_PIN, INPUT_PULLUP);
pinMode(BUTTON_C_PIN, INPUT_PULLUP);

// LEDs
pinMode(LED_YELLOW_PIN, OUTPUT);
pinMode(LED_RED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);

// ✅ MOTORES – TODOS LOS PINES
pinMode(M1_ENA_PIN, OUTPUT);
pinMode(M1_DIR_PIN, OUTPUT);
pinMode(M2_ENB_PIN, OUTPUT);
pinMode(M2_DIR_PIN, OUTPUT);

// INICIALIZAR PINES EN LOW
digitalWrite(M1_ENA_PIN, LOW);
digitalWrite(M1_DIR_PIN, LOW);
digitalWrite(M2_ENB_PIN, LOW);
digitalWrite(M2_DIR_PIN, LOW);

parar(); // Estado inicial
}

void loop() {
bool btnA = digitalRead(BUTTON_A_PIN) == LOW;
bool btnB = digitalRead(BUTTON_B_PIN) == LOW;
bool btnC = digitalRead(BUTTON_C_PIN) == LOW;

// Detectar pulsación única (flanco ↓)
bool btnA_pressed = btnA && !lastBtnA;
bool btnB_pressed = btnB && !lastBtnB;
bool btnC_pressed = btnC && !lastBtnC;

// CONTROL MOTORES
if (btnA_pressed) {
avanzar();
tone(BUZZER_PIN, 1000, 200);
}
if (btnB_pressed) {
retroceder();
tone(BUZZER_PIN, 800, 200);
}
if (btnC_pressed) {
parar();
tone(BUZZER_PIN, 500, 300);
}

// LEDs indicadores
digitalWrite(LED_YELLOW_PIN, (estado == «AVANZAR»));
digitalWrite(LED_RED_PIN, (estado == «RETROCEDER»));

// DISPLAY
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(«Estado: «); lcd.print(estado);

lcd.setCursor(0, 1);
lcd.print(«A:»); lcd.print(btnA ? «ON » : «OFF»);
lcd.print(«B:»); lcd.print(btnB ? «ON » : «OFF»);
lcd.print(«C:»); lcd.print(btnC ? «ON» : «OFF»);

// Actualizar estados
lastBtnA = btnA;
lastBtnB = btnB;
lastBtnC = btnC;

delay(50);
}

// ✅ FUNCIONES MOTORES CORREGIDAS
void avanzar() {
digitalWrite(M1_DIR_PIN, HIGH); // Izq adelante
digitalWrite(M2_DIR_PIN, LOW); // Der adelante
analogWrite(M1_ENA_PIN, 180); // Velocidad suave
analogWrite(M2_ENB_PIN, 180);
estado = «AVANZAR»;
}

void retroceder() {
digitalWrite(M1_DIR_PIN, LOW); // Izq atrás
digitalWrite(M2_DIR_PIN, HIGH); // Der atrás
analogWrite(M1_ENA_PIN, 180); // Velocidad suave
analogWrite(M2_ENB_PIN, 180);
estado = «RETROCEDER»;
}

void parar() {
// ✅ APAGAR COMPLETAMENTE AMBOS MOTORES
analogWrite(M1_ENA_PIN, 0); // Motor 1 OFF
analogWrite(M2_ENB_PIN, 0); // Motor 2 OFF
digitalWrite(M1_DIR_PIN, LOW); // Direcciones LOW
digitalWrite(M2_DIR_PIN, LOW);
estado = «PARADO»;
}

Este código implementa una emulación de control de robot tipo Zumo usando un Arduino, una pantalla LCD I2C, tres botones, dos LEDs, un buzzer y un módulo de potencia L298N para dos motores DC. En setup() se inicializa la LCD en la dirección I2C 0x3F, se muestra un mensaje de arranque, se configuran los botones con INPUT_PULLUP, los LEDs, el buzzer y todos los pines del L298N como salidas, dejando los motores apagados inicialmente mediante parar(). Además, se usa una variable de estado (estado) que mantiene si el “robot” está AVANZAR, RETROCEDER o PARADO y que luego se mostrará en pantalla.​

BotónAcciónLEDDisplaySonido
AAvanzarAmarillo ON«AVANZAR»1000Hz
BRetrocederRojo ON«RETROCEDER»800Hz
CPARAROFF«PARADO»500Hz

En loop() se leen los tres botones (A=avanzar, B=retroceder, C=parar) con lógica de flanco descendente para que cada pulsación cuente solo una vez, y según el botón se llama a avanzar(), retroceder() o parar(), disparando también un tono distinto en el buzzer con tone() como feedback sonoro. Las funciones de motor fijan la dirección con los pines M1_DIR_PIN y M2_DIR_PIN y la velocidad mediante PWM en M1_ENA_PIN y M2_ENB_PIN, tal y como se hace habitualmente al controlar el L298N con Arduino. Los LEDs indican el modo (amarillo al avanzar, rojo al retroceder) y la LCD se refresca continuamente para mostrar el estado actual y si cada botón está ON/OFF, creando una interfaz sencilla pero completa de prueba y depuración del “robot” emulado.