Módulo 1

Primer programa: Blink en ESP32

Tu Primera Experiencia con Programación de Microcontroladores

Arduino IDE LED GPIO ESP32 UNAM

Introducción al Programa Blink

El programa Blink es el equivalente al famoso "¡Hola, Mundo!" en el mundo de los microcontroladores y la mecatrónica. Es tradicionalmente el primer programa que todo ingeniero escribe cuando aprende a programar un microcontrolador, ya que demuestra los conceptos fundamentales de programación embebida.

¿Por qué empezar con Blink?

Este programa simple pero fundamental te enseña:

  • Configuración de pines GPIO - Control de entradas y salidas digitales
  • Control de tiempo - Uso de delays y temporizadores
  • Estructura básica - Setup() y loop() en Arduino
  • Debugging visual - Feedback inmediato del sistema
En mecatrónica: El control de LEDs es la base para señalización en maquinaria industrial, indicadores de estado en robots, y sistemas de alerta en automatización.

Preparación del Hardware

Para realizar este proyecto necesitarás los siguientes componentes básicos. Vamos a utilizar el LED integrado del ESP32 para simplicidad, pero también aprenderemos a conectar LEDs externos.

Lista de Materiales

  • ESP32 DevKit v1 - Placa de desarrollo
  • Cable USB - Para programación y alimentación
  • LED (opcional) - Para conexión externa
  • Resistencia 220Ω (opcional) - Limitación de corriente
  • Protoboard (opcional) - Para montaje

Pines GPIO del ESP32

GPIO 2
LED integrado azul - Ideal para comenzar
GPIO 4, 16, 17
Pines de salida seguros para LEDs externos
GND
Tierra - Conexión negativa
3.3V
Alimentación positiva (3.3 voltios)
Diagrama de Conexión (LED Externo)
ESP32

GPIO 2

GND

Resistencia 220Ω

LED

Ánodo (+)

Cátodo (-)

Código Básico: Blink Simple

Comencemos con el código más básico para hacer parpadear el LED integrado del ESP32. Este programa demuestra la estructura fundamental de cualquier sketch de Arduino.

C++ - Arduino IDE
/*
  Programa Blink Básico para ESP32
  Hace parpadear el LED integrado cada segundo
  
  Hardware: ESP32 DevKit v1
  Pin usado: GPIO 2 (LED integrado azul)
  
  Autor: Curso Mecatrónica UNAM
*/

// Definir el pin del LED (LED integrado en GPIO 2)
#define LED_PIN 2

// Función setup() - Se ejecuta una sola vez al iniciar
void setup() {
  // Inicializar comunicación serie para debug
  Serial.begin(115200);
  
  // Configurar el pin del LED como SALIDA
  pinMode(LED_PIN, OUTPUT);
  
  // Mensaje de inicio
  Serial.println("=== Programa Blink ESP32 Iniciado ===");
  Serial.println("LED integrado parpadeando cada 1 segundo");
}

// Función loop() - Se ejecuta continuamente
void loop() {
  // ENCENDER el LED (nivel alto = HIGH)
  digitalWrite(LED_PIN, HIGH);
  Serial.println("LED ENCENDIDO");
  
  // Esperar 1000 milisegundos (1 segundo)
  delay(1000);
  
  // APAGAR el LED (nivel bajo = LOW)
  digitalWrite(LED_PIN, LOW);
  Serial.println("LED APAGADO");
  
  // Esperar 1000 milisegundos (1 segundo)
  delay(1000);
}

Código Avanzado: Blink Mejorado

Ahora vamos a crear una versión más avanzada que incluye control de múltiples LEDs, patrones de parpadeo, y conceptos más avanzados que son útiles en aplicaciones mecatrónicas reales.

C++ - Arduino IDE Avanzado
/*
  Programa Blink Avanzado para ESP32 - Aplicación Mecatrónica
  Sistema de señalización con múltiples LEDs y patrones
  
  Características:
  - Control de múltiples LEDs
  - Patrones de parpadeo personalizados
  - Indicadores de estado del sistema
  - Comunicación serie con comandos
  - Control de frecuencia de parpadeo
*/

#include 

// Definición de pines para diferentes LEDs
#define LED_BUILT_IN    2   // LED integrado azul
#define LED_STATUS      4   // LED de estado (verde)
#define LED_ERROR       16  // LED de error (rojo)
#define LED_ACTIVITY    17  // LED de actividad (amarillo)

// Variables de control de tiempo (sin usar delay)
unsigned long previousMillis = 0;
unsigned long statusMillis = 0;
unsigned long activityMillis = 0;

// Configuración de intervalos de parpadeo
const long blinkInterval = 500;      // Intervalo principal (ms)
const long statusInterval = 2000;    // Intervalo de estado (ms)
const long activityInterval = 100;   // Intervalo de actividad (ms)

// Estados de los LEDs
bool ledState = false;
bool statusLedState = false;
bool activityLedState = false;
bool systemError = false;

// Contador de parpadeos para estadísticas
int blinkCount = 0;
int systemUptime = 0;

// Patrón de parpadeo personalizado
int blinkPattern[] = {200, 200, 500, 200, 200, 1000}; // ON, OFF, ON, OFF, ON, OFF
int patternSize = sizeof(blinkPattern) / sizeof(blinkPattern[0]);
int patternIndex = 0;
bool useCustomPattern = false;

void setup() {
  // Inicializar comunicación serie
  Serial.begin(115200);
  delay(1000);
  
  // Configurar todos los pines como salida
  pinMode(LED_BUILT_IN, OUTPUT);
  pinMode(LED_STATUS, OUTPUT);
  pinMode(LED_ERROR, OUTPUT);
  pinMode(LED_ACTIVITY, OUTPUT);
  
  // Estado inicial de los LEDs
  digitalWrite(LED_BUILT_IN, LOW);
  digitalWrite(LED_STATUS, LOW);
  digitalWrite(LED_ERROR, LOW);
  digitalWrite(LED_ACTIVITY, LOW);
  
  // Mensaje de inicio del sistema
  Serial.println("\n=== Sistema Blink Avanzado ESP32 ===");
  Serial.printf("Chip: %s\n", ESP.getChipModel());
  Serial.printf("Núcleos: %d\n", ESP.getChipCores());
  Serial.printf("Frecuencia CPU: %d MHz\n", ESP.getCpuFreqMHz());
  Serial.println("\nComandos disponibles:");
  Serial.println("  'status'  - Ver estado del sistema");
  Serial.println("  'pattern' - Alternar patrón personalizado");
  Serial.println("  'error'   - Simular error del sistema");
  Serial.println("  'reset'   - Reiniciar contador");
  Serial.println("  'fast'    - Parpadeo rápido");
  Serial.println("  'slow'    - Parpadeo lento");
  Serial.println("\nSistema iniciado correctamente.");
  
  // Secuencia de inicio - Test de LEDs
  testLEDSequence();
}

void loop() {
  // Obtener tiempo actual
  unsigned long currentMillis = millis();
  
  // Control del LED principal sin usar delay()
  if (useCustomPattern) {
    handleCustomPattern(currentMillis);
  } else {
    handleBasicBlink(currentMillis);
  }
  
  // Control del LED de estado (parpadeo lento)
  handleStatusLED(currentMillis);
  
  // Control del LED de actividad (parpadeo rápido)
  handleActivityLED(currentMillis);
  
  // Control del LED de error
  handleErrorLED();
  
  // Procesar comandos desde Serial
  handleSerialCommands();
  
  // Actualizar estadísticas del sistema
  updateSystemStats(currentMillis);
  
  // Pequeña pausa para optimización
  delay(10);
}

void handleBasicBlink(unsigned long currentMillis) {
  if (currentMillis - previousMillis >= blinkInterval) {
    previousMillis = currentMillis;
    
    // Cambiar estado del LED
    ledState = !ledState;
    digitalWrite(LED_BUILT_IN, ledState);
    
    // Incrementar contador
    if (ledState) {
      blinkCount++;
    }
  }
}

void handleCustomPattern(unsigned long currentMillis) {
  if (currentMillis - previousMillis >= blinkPattern[patternIndex]) {
    previousMillis = currentMillis;
    
    // Alternar LED en índices pares (ON) e impares (OFF)
    bool shouldBeOn = (patternIndex % 2 == 0);
    digitalWrite(LED_BUILT_IN, shouldBeOn);
    
    if (shouldBeOn) {
      blinkCount++;
    }
    
    // Avanzar al siguiente paso del patrón
    patternIndex = (patternIndex + 1) % patternSize;
  }
}

void handleStatusLED(unsigned long currentMillis) {
  if (currentMillis - statusMillis >= statusInterval) {
    statusMillis = currentMillis;
    statusLedState = !statusLedState;
    digitalWrite(LED_STATUS, statusLedState);
  }
}

void handleActivityLED(unsigned long currentMillis) {
  if (currentMillis - activityMillis >= activityInterval) {
    activityMillis = currentMillis;
    activityLedState = !activityLedState;
    digitalWrite(LED_ACTIVITY, activityLedState);
  }
}

void handleErrorLED() {
  // LED de error: ON constante si hay error, OFF si no
  digitalWrite(LED_ERROR, systemError ? HIGH : LOW);
}

void handleSerialCommands() {
  if (Serial.available() > 0) {
    String command = Serial.readString();
    command.trim();
    command.toLowerCase();
    
    if (command == "status") {
      printSystemStatus();
    }
    else if (command == "pattern") {
      useCustomPattern = !useCustomPattern;
      patternIndex = 0;
      Serial.printf("Patrón personalizado: %s\n", 
                   useCustomPattern ? "ACTIVADO" : "DESACTIVADO");
    }
    else if (command == "error") {
      systemError = !systemError;
      Serial.printf("Estado de error: %s\n", 
                   systemError ? "ACTIVADO" : "DESACTIVADO");
    }
    else if (command == "reset") {
      blinkCount = 0;
      systemUptime = 0;
      Serial.println("Contador reiniciado.");
    }
    else if (command == "fast") {
      // No implementado en esta versión básica
      Serial.println("Modo rápido activado");
    }
    else if (command == "slow") {
      // No implementado en esta versión básica  
      Serial.println("Modo lento activado");
    }
    else {
      Serial.printf("Comando desconocido: %s\n", command.c_str());
    }
  }
}

void printSystemStatus() {
  Serial.println("\n=== ESTADO DEL SISTEMA ===");
  Serial.printf("Uptime: %d segundos\n", systemUptime);
  Serial.printf("Parpadeos totales: %d\n", blinkCount);
  Serial.printf("Memoria libre: %d bytes\n", ESP.getFreeHeap());
  Serial.printf("Patrón personalizado: %s\n", 
               useCustomPattern ? "ACTIVO" : "INACTIVO");
  Serial.printf("Estado de error: %s\n", 
               systemError ? "ERROR" : "OK");
  Serial.printf("Temperatura CPU: %.1f°C\n", temperatureRead());
  Serial.println("========================\n");
}

void updateSystemStats(unsigned long currentMillis) {
  static unsigned long lastSecond = 0;
  
  if (currentMillis - lastSecond >= 1000) {
    lastSecond = currentMillis;
    systemUptime++;
    
    // Mostrar estadísticas cada 30 segundos
    if (systemUptime % 30 == 0) {
      Serial.printf("Sistema funcionando: %d seg, %d parpadeos\n", 
                   systemUptime, blinkCount);
    }
  }
}

void testLEDSequence() {
  Serial.println("Iniciando test de LEDs...");
  
  // Encender LEDs secuencialmente
  digitalWrite(LED_BUILT_IN, HIGH);
  delay(200);
  digitalWrite(LED_STATUS, HIGH);
  delay(200);
  digitalWrite(LED_ERROR, HIGH);
  delay(200);
  digitalWrite(LED_ACTIVITY, HIGH);
  delay(500);
  
  // Apagar todos los LEDs
  digitalWrite(LED_BUILT_IN, LOW);
  digitalWrite(LED_STATUS, LOW);
  digitalWrite(LED_ERROR, LOW);
  digitalWrite(LED_ACTIVITY, LOW);
  
  Serial.println("Test de LEDs completado.");
  delay(500);
}

Ejercicios Prácticos

1

Blink Básico

Principiante 10 min

Objetivo: Programar el ESP32 para hacer parpadear el LED integrado cada segundo.

Pasos:

  1. Conectar ESP32 al PC
  2. Abrir Arduino IDE
  3. Copiar el código básico
  4. Subir el programa
  5. Verificar funcionamiento

Resultado: LED azul parpadeando cada segundo

2

LED Externo con Resistencia

Intermedio 20 min

Objetivo: Conectar un LED externo y controlarlo con diferentes velocidades.

Componentes: LED, resistencia 220Ω, cables, protoboard

Conceptos: Ley de Ohm, limitación de corriente, GPIO

Modificación: Cambiar tiempos de delay para diferentes efectos

3

Sistema Completo de Señalización

Avanzado 45 min

Objetivo: Implementar el sistema avanzado con múltiples LEDs y control serial.

Funcionalidades:

  • 4 LEDs con diferentes patrones
  • Control por comandos serie
  • Monitoreo de estadísticas
  • Simulación de estados de error

Guía Paso a Paso: Tu Primer Programa

Sigue estos pasos detallados para cargar y ejecutar tu primer programa Blink en el ESP32:

1
Preparar el Entorno de Desarrollo
  • Asegúrate de tener Arduino IDE instalado
  • Instala el soporte para ESP32 (Gestor de Tarjetas)
  • Selecciona la tarjeta "ESP32 Dev Module"
  • Verifica el puerto COM correcto
2
Conectar el Hardware
  • Conecta el ESP32 al PC usando cable USB
  • Verifica que el LED azul integrado esté visible
  • Opcionalmente conecta LED externo con resistencia
  • Confirma la alimentación (LED rojo encendido)
3
Escribir y Cargar el Código
  • Abre un nuevo sketch en Arduino IDE
  • Copia el código básico de Blink
  • Verifica la sintaxis (Ctrl+R)
  • Sube el programa al ESP32 (Ctrl+U)
4
Verificar y Probar
  • Abre el Monitor Serie (115200 baudios)
  • Observa los mensajes de debug
  • Confirma que el LED parpadea correctamente
  • Experimenta modificando los delays

Aplicaciones del Blink en Mecatrónica

Más Allá del Parpadeo Simple

Aunque el programa Blink parece simple, las técnicas que aprendes son fundamentales en aplicaciones mecatrónicas reales:

Indicadores de Estado:
  • Señalización de maquinaria
  • Indicadores de vida del sistema
  • Alertas y advertencias
Control Temporal:
  • Secuencias de operación
  • Sincronización de procesos
  • Temporizadores precisos
Ejemplos de Aplicación Real
Brazos Robóticos
LEDs indican posición y estado de movimiento
Bandas Transportadoras
Señalización de funcionamiento y direcciones
Vehículos Autónomos
Luces de navegación y estado del sistema

Referencias y Recursos Adicionales