#include #include #include #include #include #include #include #include // ---------------- CONFIGURACION ---------------- #define CANAL_WIFI 1 #define LED_VERDE 14 #define LED_AMARILLO 12 #define LED_ROJO 13 #define OLED_ANCHO 128 #define OLED_ALTO 64 #define OLED_RESET -1 #define OLED_DIR 0x3C #define TIEMPO_ESPERA 700 Adafruit_SH1106G display( OLED_ANCHO, OLED_ALTO, &Wire, OLED_RESET ); typedef struct { uint8_t comando; } Mensaje; // Comunicacion volatile uint8_t comandoActual = 0; volatile unsigned long ultimoMensaje = 0; volatile bool mensajeRecibido = false; portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; // OLED bool oledDisponible = false; uint8_t comandoAnteriorPantalla = 255; bool senalAnterior = false; // LED uint8_t comandoAnteriorLED = 255; unsigned long tiempoBlink = 0; bool estadoAmarillo = false; // ---------------- TEXTO CENTRADO ---------------- void textoCentrado(const char* texto, int y, int tamano) { display.setTextSize(tamano); int ancho = strlen(texto) * 6 * tamano; int x = (OLED_ANCHO - ancho) / 2; display.setCursor(x, y); display.print(texto); } // ---------------- CONFIGURACION OLED ---------------- void iniciarOLED() { Wire.begin(21, 22); Wire.setClock(100000); // I2C a velocidad estándar y estable oledDisponible = display.begin(OLED_DIR, true); if (!oledDisponible) { Serial.println("ERROR: NO SE DETECTA LA OLED"); return; } // Limpiar memoria física de la pantalla para evitar basura inicial display.clearDisplay(); display.display(); delay(50); display.setRotation(0); display.setTextColor(SH110X_WHITE, SH110X_BLACK); // Fondo negro en el texto display.setTextWrap(false); display.clearDisplay(); display.drawRect(0, 0, 128, 64, SH110X_WHITE); textoCentrado("INICIANDO", 19, 2); textoCentrado("ESP32 RECEPTOR", 43, 1); display.display(); delay(1200); } // ---------------- ACTUALIZAR PANTALLA ---------------- void actualizarPantalla(uint8_t comando, bool senal) { if (!oledDisponible) return; display.clearDisplay(); // Marco display.drawRect(0, 0, 128, 64, SH110X_WHITE); // Cabecera display.setTextSize(1); display.setCursor(7, 6); display.print(F("CONTROL ESP-NOW")); display.setCursor(105, 6); display.print(F("RX")); display.drawLine(5, 18, 122, 18, SH110X_WHITE); // Estado de comunicacion if (!senal) { textoCentrado("SIN CONEXION", 26, 1); textoCentrado("ESPERANDO", 39, 2); } else if (comando == 1) { textoCentrado("SENAL RECIBIDA", 26, 1); textoCentrado("IZQUIERDA", 39, 2); } else if (comando == 2) { textoCentrado("SENAL RECIBIDA", 26, 1); textoCentrado("DERECHA", 39, 2); } else { textoCentrado("SENAL RECIBIDA", 26, 1); textoCentrado("REPOSO", 39, 2); } // Pie display.drawLine(5, 55, 122, 55, SH110X_WHITE); display.setTextSize(1); display.setCursor(31, 57); display.print(F("RECEPTOR")); display.display(); } // ---------------- RECEPCION ESP-NOW ---------------- void OnDataRecv( const esp_now_recv_info_t *info, const uint8_t *datos, int longitud ) { if (longitud != sizeof(Mensaje)) return; Mensaje recibido; memcpy( &recibido, datos, sizeof(Mensaje) ); if (recibido.comando > 2) return; portENTER_CRITICAL(&mux); comandoActual = recibido.comando; ultimoMensaje = millis(); mensajeRecibido = true; portEXIT_CRITICAL(&mux); } // ---------------- SETUP ---------------- void setup() { Serial.begin(115200); // Configurar LED pinMode(LED_VERDE, OUTPUT); pinMode(LED_AMARILLO, OUTPUT); pinMode(LED_ROJO, OUTPUT); digitalWrite(LED_VERDE, LOW); digitalWrite(LED_AMARILLO, LOW); digitalWrite(LED_ROJO, LOW); // Iniciar OLED iniciarOLED(); // Iniciar WiFi WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); Serial.println(); Serial.println("=== RECEPTOR ESP-NOW ==="); Serial.print("MAC: "); Serial.println(WiFi.macAddress()); // Configurar canal if (esp_wifi_set_channel( CANAL_WIFI, WIFI_SECOND_CHAN_NONE ) != ESP_OK) { Serial.println("ERROR CONFIGURANDO CANAL"); while (true) delay(1000); } // Iniciar ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("ERROR INICIANDO ESP-NOW"); while (true) delay(1000); } // Registrar recepcion if (esp_now_register_recv_cb(OnDataRecv) != ESP_OK) { Serial.println("ERROR RECEPCION"); while (true) delay(1000); } Serial.println("RECEPTOR PREPARADO"); actualizarPantalla(0, false); } // ---------------- LOOP ---------------- void loop() { uint8_t comando; unsigned long ultimo; bool recibido; portENTER_CRITICAL(&mux); comando = comandoActual; ultimo = ultimoMensaje; recibido = mensajeRecibido; portEXIT_CRITICAL(&mux); // Comprobar conexion bool senal = recibido && (millis() - ultimo <= TIEMPO_ESPERA); if (!senal) { comando = 0; } // Detectar cambios if (comando != comandoAnteriorLED) { estadoAmarillo = false; tiempoBlink = millis(); comandoAnteriorLED = comando; } // ---------------- CONTROL DE LED ---------------- switch (comando) { case 1: // IZQUIERDA digitalWrite(LED_VERDE, HIGH); digitalWrite(LED_ROJO, LOW); if (millis() - tiempoBlink >= 180) { tiempoBlink = millis(); estadoAmarillo = !estadoAmarillo; digitalWrite( LED_AMARILLO, estadoAmarillo ? HIGH : LOW ); } break; case 2: // DERECHA digitalWrite(LED_VERDE, LOW); digitalWrite(LED_AMARILLO, LOW); digitalWrite(LED_ROJO, HIGH); estadoAmarillo = false; break; default: // REPOSO O SIN CONEXION digitalWrite(LED_VERDE, LOW); digitalWrite(LED_AMARILLO, LOW); digitalWrite(LED_ROJO, LOW); estadoAmarillo = false; break; } // Actualizar OLED si cambia el estado if ( comando != comandoAnteriorPantalla || senal != senalAnterior ) { actualizarPantalla(comando, senal); comandoAnteriorPantalla = comando; senalAnterior = senal; } delay(5); }