📡
Arduino Mega 2560 Práctica 4 Mando a Distancia por Infrarrojos (IR) • Control por Casos
Control Inalámbrico por Sensor TSOP38238 / VS1838B (Pin 43)

Mando a Distancia Infrarrojo (IR)

Control de secuencias en la maqueta Arduino Mega 2560 mediante mando a distancia (librería IRremote.hpp). La máquina de estados está estructurada por casos (1: Encender todos, 2: Apagar todos, 3: Marquesina, 4: Relleno) sin bloqueos con millis().

Simulador en Vivo — Práctica 4 (Mando IR)
Estado Activo: CASO 2: APAGADOS
Emisor Infrarrojo
MANDO A DISTANCIA 38 kHz
¡Haz click en las teclas 1, 2, 3 o 4!
📡

Receptor Infrarrojo (TSOP38238 / VS1838B)

Detecta ráfagas de 38 kHz. Salida conectada al Pin Digital 43 del Arduino Mega.

OUT → Pin 43 VCC → 5V GND → Masa
LED Chivato
Pin 43
Acción según el caso: Apagar todos los LEDs
Variable: int caso = 2;
Último código IR: 0x000000
150 ms
💡

Barra de 9 LEDs en la Protoboard (Pines 13 al 5)

3 Rojos • 3 Amarillos • 3 Verdes
L1 P13
L2 P12
L3 P11
L4 P10
L5 P9
L6 P8
L7 P7
L8 P6
L9 P5

🔌 Conexiones y Circuito Eléctrico (Práctica 4)

Ubicación física del receptor IR en la protoboard y conexión al Pin 43 del Arduino Mega.

Esquema Real de Conexiones (Pin 43 destacado) Pin 43 → Justo debajo del 41
Esquema de montaje con receptor IR

* El cable morado conecta el pin OUT del sensor al Pin 43 del Arduino Mega (fila impar, bajo el cable azul del sensor DHT22).

Pines del Receptor IR (TSOP / VS1838) IRremote.hpp
Terminal Pin Mega Función
OUT (Señal) Pin 43 Señal demodulada 38 kHz
VCC (+) 5V Alimentación positiva
GND (-) GND Masa común
Casos de Control (switch caso)
Caso Tecla Mando Acción en LEDs
caso = 1 Tecla 1 Enciende todos los 9 LEDs
caso = 2 Tecla 2 Apaga todos los 9 LEDs
caso = 3 Tecla 3 Secuencia 3: Marquesina
caso = 4 Tecla 4 Secuencia 4: Relleno

💻 Monitor Serie Virtual (9600 Baudios)

Muestra los códigos en tiempo real al hacer click en el mando.

==================================================
PRÁCTICA 4: CONTROL POR CASOS (MANDO IR)
Receptor inicializado en Pin 43
==================================================
Listo. Pulsa teclas 1, 2, 3 o 4 en el mando virtual...

📜 Código Arduino Completo (Estructura por Casos)

Listo para copiar y subir directamente con Arduino IDE.

// =============================================================================
// MAQUETA ARDUINO MEGA 2560 — PRÁCTICA 4
// Control por Mando a Distancia (IR) mediante variable "caso"
// Librería necesaria: "IRremote" (incluir )
// =============================================================================

#include <IRremote.hpp>

// 1. PINES DE LOS 9 LEDs (Pines 13 al 5)
const uint8_t NUM_LEDS = 9;
const uint8_t PINES_LEDS[NUM_LEDS] = {13, 12, 11, 10, 9, 8, 7, 6, 5};

// 2. RECEPTOR IR (Conectado al Pin 43)
const int PIN_RECEPTOR = 43;

// 3. VARIABLE DE CONTROL DE CASO
// Caso 1: Enciende todos | Caso 2: Apaga todos | Caso 3: Marquesina | Caso 4: Relleno
int caso = 2; // Inicia en Caso 2 (Apagado)

// Variables de tiempo para las secuencias con millis()
unsigned long tiempoUltimoPasoLED = 0;
const unsigned long INTERVALO_ANIMACION = 150; // Velocidad de la secuencia (ms)
int pasoActual = 0;

// =============================================================================
// SETUP
// =============================================================================
void setup() {
  Serial.begin(9600);    // Monitor Serie USB para depuración
  Serial3.begin(9600);   // Bluetooth (Serial3: Pin 14 TX, Pin 15 RX)

  // Configurar los 9 LEDs como salida
  for (uint8_t i = 0; i < NUM_LEDS; i++) {
    pinMode(PINES_LEDS[i], OUTPUT);
    digitalWrite(PINES_LEDS[i], LOW);
  }

  // Inicializar receptor IR en Pin 43
  IrReceiver.begin(PIN_RECEPTOR, ENABLE_LED_FEEDBACK);

  Serial.println(F("=================================================="));
  Serial.println(F("  PRÁCTICA 4: CONTROL POR CASOS (MANDO IR)        "));
  Serial.println(F("=================================================="));
  Serial.println(F("  Caso 1: Enciende todos (Tecla 1 / BT '1')"));
  Serial.println(F("  Caso 2: Apaga todos    (Tecla 2 / BT '2')"));
  Serial.println(F("  Caso 3: Marquesina     (Tecla 3 / BT '3')"));
  Serial.println(F("  Caso 4: Relleno        (Tecla 4 / BT '4')"));
  Serial.println(F("=================================================="));

  apagarTodos();
}

// =============================================================================
// LOOP PRINCIPAL
// =============================================================================
void loop() {
  // 1. Escanear señales del Mando IR
  leerMandoIR();

  // 2. Escanear órdenes de Bluetooth
  leerBluetooth();

  // 3. Máquina de estados según el "caso"
  switch (caso) {
    case 1:
      // Caso 1: Todos los LEDs encendidos
      encenderTodos();
      break;

    case 2:
      // Caso 2: Todos los LEDs apagados
      apagarTodos();
      break;

    case 3:
      // Caso 3: Secuencia Marquesina cíclica
      secuencia3(INTERVALO_ANIMACION);
      break;

    case 4:
      // Caso 4: Secuencia Relleno acumulativo cíclico
      secuencia4(INTERVALO_ANIMACION);
      break;
  }
}

// =============================================================================
// LECTURA DEL MANDO IR
// =============================================================================
void leerMandoIR() {
  if (IrReceiver.decode()) {
    uint32_t cmd = IrReceiver.decodedIRData.command;
    uint32_t raw = IrReceiver.decodedIRData.decodedRawData;

    Serial.print(F("Comando IR recibido: 0x"));
    Serial.println(cmd, HEX);

    // Tecla 1 (Encender todos)
    if (cmd == 0x45 || cmd == 0x16 || cmd == 0xC || raw == 0xFF6897) {
      cambiarCaso(1);
    }
    // Tecla 2 (Apagar todos)
    else if (cmd == 0x46 || cmd == 0x19 || cmd == 0x18 || raw == 0xFF9867) {
      cambiarCaso(2);
    }
    // Tecla 3 (Secuencia Marquesina)
    else if (cmd == 0x47 || cmd == 0xD || cmd == 0x5E || raw == 0xFFB04F) {
      cambiarCaso(3);
    }
    // Tecla 4 (Secuencia Relleno)
    else if (cmd == 0x44 || cmd == 0xC || cmd == 0x8 || raw == 0xFF30CF) {
      cambiarCaso(4);
    }

    IrReceiver.resume(); // Listo para el siguiente pulso
  }
}

// =============================================================================
// LECTURA DEL BLUETOOTH (Serial3)
// =============================================================================
void leerBluetooth() {
  if (Serial3.available() > 0) {
    char dato = Serial3.read();
    Serial.print(F("Dato Bluetooth: '"));
    Serial.print(dato);
    Serial.println(F("'"));

    if (dato == '1') cambiarCaso(1);
    if (dato == '2') cambiarCaso(2);
    if (dato == '3') cambiarCaso(3);
    if (dato == '4') cambiarCaso(4);
  }
}

// =============================================================================
// FUNCIÓN PARA CAMBIAR DE CASO
// =============================================================================
void cambiarCaso(int nuevoCaso) {
  caso = nuevoCaso;
  pasoActual = 0;
  tiempoUltimoPasoLED = millis() - INTERVALO_ANIMACION;

  if (caso == 1) encenderTodos();
  if (caso == 2) apagarTodos();
  if (caso == 3 || caso == 4) apagarTodos();

  Serial.print(F("-> ACTIVADO CASO: "));
  Serial.println(caso);
}

// =============================================================================
// FUNCIONES DE CONTROL DE LEDs
// =============================================================================
void apagarTodos() {
  for (uint8_t i = 0; i < NUM_LEDS; i++) {
    digitalWrite(PINES_LEDS[i], LOW);
  }
}

void encenderTodos() {
  for (uint8_t i = 0; i < NUM_LEDS; i++) {
    digitalWrite(PINES_LEDS[i], HIGH);
  }
}

// Secuencia 3: Se enciende un LED y se apaga el anterior de forma cíclica
void secuencia3(unsigned long retardo) {
  unsigned long tiempoActual = millis();
  if (tiempoActual - tiempoUltimoPasoLED >= retardo) {
    tiempoUltimoPasoLED = tiempoActual;
    apagarTodos();
    digitalWrite(PINES_LEDS[pasoActual], HIGH);
    pasoActual++;
    if (pasoActual >= NUM_LEDS) pasoActual = 0;
  }
}

// Secuencia 4: Acumulativo de LEDs encendidos hasta completarse y reiniciar
void secuencia4(unsigned long retardo) {
  unsigned long tiempoActual = millis();
  if (tiempoActual - tiempoUltimoPasoLED >= retardo) {
    tiempoUltimoPasoLED = tiempoActual;
    if (pasoActual < NUM_LEDS) {
      digitalWrite(PINES_LEDS[pasoActual], HIGH);
      pasoActual++;
    } else {
      apagarTodos();
      pasoActual = 0;
    }
  }
}

🧠 Fundamentos Técnicos del Mando Infrarrojo

Cómo viaja la información desde el mando hasta el microcontrolador.

📶 Portadora de 38 kHz

La luz ambiente (sol, tubos fluorescentes) emite infrarrojos. Para evitar interferencias, el mando modula la luz a 38.000 Hz. El filtro interno del sensor TSOP solo amplifica esa frecuencia exacta.

📦 Protocolo NEC

Codifica bits mediante modulación por distancia de pulsos (Pulse Distance Modulation). Un bit '0' dura 1.12 ms y un bit '1' dura 2.25 ms. Cada paquete transmite 32 bits (dirección y comando invertido para comprobación).

⏱️ Multitarea con millis()

El receptor IR requiere medir micropulsos. Si el código tuviera un delay(500) durante la animación de los LEDs, el Arduino quedaría ciego y perdería las pulsaciones del mando.