Arduinomega +esp8266

Hola a todos, soy nuevo en el foro y también en el uso de arduino. Estoy tratando de realizar un proyecto que involucra al siguiente hardware: elecrow 7´´ con esp32s3 integrado; arduino mega wifi r3 con esp8266 integrado, dos controladores de reles optoacopladores de 16 canales cada uno de ellos. Se trata de enviar órdenes desde una interface gráfica en elecrow 7´´ a arduino mega wifi (mediante una red wifi creada ad hoc) y que una vez recibidos los datos arduino mega wifi encienda o apague los reles. He diseñado la interface grafica para elecrow 7´´ y escrito el código para esp32s3. esta parte funciona correctamente y, al tocar los swichts envía la orden de encender o apagar el rele "x" a esp8266 que recibe la orden. sin embargo, cuando esp8266 le envía la orden a arduino mega, se muestra en el monitor serie de arduino ide el mensaje "comando desconocido". Alguien puede ayudarme con este problema. He leido otros post sobre el tema pero no soy capaz de ajustar el código. Adjunto código para arduino mega, código para esp8266 y captura de pantalla de monitor serie. Gracias.

Hello everyone, I’m new to the forum and also to using Arduino. I’m working on a project involving the following hardware: Elecrow 7’’ with an integrated ESP32-S3, Arduino Mega WiFi R3 with an integrated ESP8266, and two 16-channel optocoupler relay controllers. The goal is to send commands from a graphical interface on the Elecrow 7’’ to the Arduino Mega WiFi (via an ad hoc WiFi network), and once the data is received, the Arduino Mega WiFi should turn the relays on or off.

I have designed the graphical interface for the Elecrow 7’’ and written the code for the ESP32-S3. This part works correctly, and when I touch the switches, it sends the command to turn relay "x" on or off to the ESP8266, which successfully receives the command. However, when the ESP8266 sends the command to the Arduino Mega, the Arduino IDE serial monitor displays the message "unknown command."

Can anyone help me with this issue? I’ve read other posts on the topic but haven’t been able to adjust the code properly. I’m attaching the code for the Arduino Mega, the code for the ESP8266, and a screenshot of the serial monitor. Thank you!
Arduino Mega Sketch:

// Definición de los pines de los 33 relés
const int relayPins[33] = {
    22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 
    42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
    52, 53, 2 // Pin 2 para el relé 33
};

void setup() {
  Serial.begin(115200);    // Comunicación con el monitor serie
  Serial3.begin(115200);   // Comunicación con el ESP8266 (RX3/TX3)
  pinMode(13, OUTPUT);     // Indicador LED para depuración
  digitalWrite(13, LOW);   // Apagar el LED inicialmente

  // Inicializar los pines de los relés como salida y apagarlos (lógica inversa)
  for (int i = 0; i < 33; i++) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH); // Relés apagados inicialmente (lógica inversa)
  }

  // Configuración inicial del ESP8266 con comandos AT
  delay(500);
  Serial.println("Configurando el ESP8266...");
  Serial3.println("AT+CIPMUX=1");        // Permitir múltiples conexiones
  delay(2000);
  Serial3.println("AT+CIPSERVER=1,5000"); // Configurar servidor TCP en el puerto 5000
  delay(2000);
  Serial3.println("AT+CIPSTO=3600");     // Establecer tiempo de espera de la conexión
  delay(2000);
  Serial.println("ESP8266 configurado y listo.");
}

void loop() {
  // Escuchar comunicación del ESP8266 y procesar comandos
  if (Serial3.available()) {
    String command = Serial3.readStringUntil('\n'); // Leer el comando completo
    Serial.println("Comando recibido desde ESP8266: " + command); // Depuración
    processCommand(command);
  }

  // Escuchar entrada del usuario desde el monitor serie y enviarla al ESP8266
  if (Serial.available()) {
    String userInput = Serial.readStringUntil('\n');
    Serial3.println(userInput); // Enviar al ESP8266
  }
}

// Función para procesar los comandos recibidos
void processCommand(String command) {
  // Ejemplo de formato de comando esperado: "REL:1:ON"
  if (command.startsWith("REL:")) {
    int firstColon = command.indexOf(':');
    int secondColon = command.indexOf(':', firstColon + 1);

    if (firstColon > 0 && secondColon > firstColon) {
      // Extraer el número de relé y el estado
      int relayNumber = command.substring(firstColon + 1, secondColon).toInt();
      String state = command.substring(secondColon + 1);

      // Validar el número de relé
      if (relayNumber >= 1 && relayNumber <= 33) {
        bool relayState = (state == "ON"); // Determinar el estado (ON/OFF)
        
        // Ajustar para lógica inversa
        digitalWrite(relayPins[relayNumber - 1], relayState ? LOW : HIGH); // LOW = Encender, HIGH = Apagar
        Serial.print("Relé ");
        Serial.print(relayNumber);
        Serial.print(" ");
        Serial.println(relayState ? "Encendido" : "Apagado");
      } else {
        Serial.println("Número de relé fuera de rango.");
      }
    } else {
      Serial.println("Comando malformado.");
    }
  } else {
    Serial.println("Comando desconocido.");
  }
}

ESP8266 Sketch:

#include <ESP8266WiFi.h>
#include <espnow.h>

// Estructura de datos para las órdenes
typedef struct {
    int relayNumber; // Número del relé (1-33)
    bool state;      // Estado del relé (true = ON, false = OFF)
} RelayCommand;

// Callback para recibir datos desde el ESP32-S3
void onDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
    // Validar que los datos tengan el tamaño esperado
    if (len != sizeof(RelayCommand)) {
        Serial.println("Error: Tamaño de datos incorrecto.");
        return;
    }

    RelayCommand command;
    memcpy(&command, incomingData, sizeof(command));

    // Verificar rango válido del número de relé
    if (command.relayNumber >= 1 && command.relayNumber <= 33) {
        // Preparar el comando para enviar al Arduino Mega
        String commandToMega = "REL:" + String(command.relayNumber) + ":" + (command.state ? "ON" : "OFF") + "\n";

        // Depuración en el monitor serie
        Serial.println("Comando recibido desde ESP32-S3:");
        Serial.println(" - Relé: " + String(command.relayNumber));
        Serial.println(" - Estado: " + String(command.state ? "ON" : "OFF"));
        Serial.println("Enviando comando al Mega: " + commandToMega);

        // Enviar el comando al Arduino Mega a través de Serial1
        Serial1.print(commandToMega);
    } else {
        Serial.println("Error: Número de relé fuera de rango.");
    }
}

void setup() {
    // Configuración de la comunicación serial
    Serial.begin(115200);    // Depuración con el monitor serie
    Serial1.begin(115200);   // Comunicación con Arduino Mega vía Serial1 (RX/TX)

    // Configuración de ESP-NOW
    WiFi.mode(WIFI_STA); // Configurar WiFi en modo estación
    if (esp_now_init() == 0) { // `esp_now_init` devuelve 0 si tiene éxito
        Serial.println("ESP-NOW inicializado correctamente.");
        esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
        esp_now_register_recv_cb(onDataRecv); // Configurar callback para recepción
    } else {
        Serial.println("Error al inicializar ESP-NOW.");
    }
}

void loop() {
    // El ESP8266 no realiza ninguna acción activa en el bucle principal
}

Hola @trasnomar, revisando tu código y verificando la depuración de mensajes del puerto serial, claramente no estás obteniendo el comando correctamente. No se está almacenando adecuadamente en la línea de código siguiente:

Y por tanto el procesamiento posterior salta a la primera verificación que haces:

Por lo cual se imprime el mensaje que tienes configurado para ello, en este caso:
Comando desconocido.

Personalmente no me gusta utilizar la librería String del entorno de desarrollo, me deja muchas lagunas y no siempre funciona adecuadamente. Trata de utilizar otros métodos para conformar ése comando de la parte del ESP8266, como el siguiente:

char commandToMega[50];
char buffer[10];

// Convierte relayNumber a cadena y almacena en buffer 
itoa(command.relayNumber, buffer, 10); // 10 es la base decimal

// Construye el comando con sprintf 
sprintf(commandToMega, "REL:%s:%s\n", buffer, command.state ? "ON" : "OFF");

Por la parte del Arduino Mega trata de erradicar también el uso de la librería String, la manipulación de cadenas en C++ de forma directa es un poco compleja, pero aquí tienes una función equivalente para leer el comando desde el puerto de serie y almacenarlo en una variable tipo char[] :

// Función para leer una cadena hasta un carácter de nueva línea
 void readStringUntilNewline(Stream &stream, char *buffer, size_t bufferSize)  { 
    size_t index = 0; 
    while (stream.available()) { 
        char c = stream.read(); 
        if (c == '\n' || index >= bufferSize - 1) { 
            break; 
        } 
        buffer[index++] = c; 
    } 
    buffer[index] = '\0'; // Terminar la cadena 
}

Luego, la obtención de los datos quedaría:

char command[100]; 
readStringUntilNewline(Serial3, command, sizeof(command)); // Leer el comando completo 
Serial.print("Comando recibido desde ESP8266: "); 
Serial.println(command); // Depuración

Si con éste método logras imprimir en la consola el comando puedo ayudarte a modificar la función para procesar los comandos utilizando éste método. Coméntame si te ha sido útil.

En primer lugar, gracias por tu ayuda @cdavisongmz. Llevo varios días tratando de solucionar el problema de la falta de comunicación en la placa ATmega2560 r3 wifi. He de decirte que no tengo apenas conocimientos de programación, pero me las he apañado para crear la interface grafica y el codigo de la pantalla (Todo un logro para mi!!!!). Pensé que la parte de arduino mega sería más fácil pero me estoy dando cabezazos contra una piedra.
He usado el siguiente código para la parte de esp8266:

#include <ESP8266WiFi.h>
#include <espnow.h>

// Estructura de datos para las órdenes
typedef struct {
    int relayNumber; // Número del relé (1-33)
    bool state;      // Estado del relé (true = ON, false = OFF)
} RelayCommand;

// Callback para recibir datos desde el ESP32-S3
void onDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
    // Validar que los datos tengan el tamaño esperado
    if (len != sizeof(RelayCommand)) {
        Serial.println("Error: Tamaño de datos incorrecto.");
        return;
    }

    RelayCommand command;
    memcpy(&command, incomingData, sizeof(command));

    // Verificar rango válido del número de relé
    if (command.relayNumber >= 1 && command.relayNumber <= 33) {
        // Preparar el comando para enviar al Arduino Mega
        char commandToMega[50];  // Buffer para el comando completo
        sprintf(commandToMega, "REL:%d:%s\n", command.relayNumber, command.state ? "ON" : "OFF");

        // Depuración en el monitor serie
        Serial.println("Comando recibido desde ESP32-S3:");
        Serial.print(" - Relé: ");
        Serial.println(command.relayNumber);
        Serial.print(" - Estado: ");
        Serial.println(command.state ? "ON" : "OFF");
        Serial.print("Enviando comando al Mega: ");
        Serial.println(commandToMega);

        // Enviar el comando al Arduino Mega a través de Serial1
        Serial1.print(commandToMega);
    } else {
        Serial.println("Error: Número de relé fuera de rango.");
    }
}

void setup() {
    // Configuración de la comunicación serial
    Serial.begin(115200);    // Depuración con el monitor serie
    Serial1.begin(115200);   // Comunicación con Arduino Mega vía Serial1 (RX/TX)

    // Configuración de ESP-NOW
    WiFi.mode(WIFI_STA); // Configurar WiFi en modo estación
    if (esp_now_init() == 0) { // `esp_now_init` devuelve 0 si tiene éxito
        Serial.println("ESP-NOW inicializado correctamente.");
        esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
        esp_now_register_recv_cb(onDataRecv); // Configurar callback para recepción
    } else {
        Serial.println("Error al inicializar ESP-NOW.");
    }
}

void loop() {
    // El ESP8266 no realiza ninguna acción activa en el bucle principal
}

El resultado ha sido:


Hasta aquí todo correcto.
Para la parte del mega he usado el siguiente código:

// Definición de los pines de los 33 relés
const int relayPins[33] = {
    22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 
    42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
    52, 53, 2 // Pin 2 para el relé 33
};

// Variables para manejar la recepción de datos
char command[100];  // Buffer para almacenar el comando completo
size_t commandIndex = 0;

void setup() {
    Serial.begin(115200);    // Comunicación con el monitor serie
    Serial3.begin(115200);   // Comunicación con el ESP8266 (RX3/TX3)
    pinMode(13, OUTPUT);     // Indicador LED para depuración
    digitalWrite(13, LOW);   // Apagar el LED inicialmente

    // Inicializar los pines de los relés como salida y apagarlos (lógica inversa)
    for (int i = 0; i < 33; i++) {
        pinMode(relayPins[i], OUTPUT);
        digitalWrite(relayPins[i], HIGH); // Relés apagados inicialmente (lógica inversa)
    }
}

void loop() {
    // Leer datos desde Serial3 (ESP8266)
    while (Serial3.available()) {
        char c = Serial3.read();

        if (c == '\n') {  // Fin del comando
            command[commandIndex] = '\0'; // Terminar la cadena
            Serial.print("Comando recibido desde ESP8266: ");
            Serial.println(command);
            processCommand(command);      // Procesar el comando
            commandIndex = 0;             // Reiniciar el índice del buffer
        } else if (commandIndex < sizeof(command) - 1) {
            command[commandIndex++] = c;  // Almacenar el carácter en el buffer
        }
    }
}

// Función para procesar los comandos recibidos
void processCommand(const char *command) {
    // Verificar si el comando comienza con "REL:"
    if (strncmp(command, "REL:", 4) == 0) {
        char *token = strtok((char *)command + 4, ":"); // Extraer el número de relé
        if (token == nullptr) return;

        int relayNumber = atoi(token); // Convertir a número
        token = strtok(nullptr, ":"); // Extraer el estado
        if (token == nullptr) return;

        bool relayState = (strcmp(token, "ON") == 0); // Determinar el estado (ON/OFF)

        // Validar el número de relé
        if (relayNumber >= 1 && relayNumber <= 33) {
            digitalWrite(relayPins[relayNumber - 1], relayState ? LOW : HIGH); // LOW = Encender, HIGH = Apagar
            Serial.print("Relé ");
            Serial.print(relayNumber);
            Serial.print(" ");
            Serial.println(relayState ? "Encendido" : "Apagado");
        } else {
            Serial.println("Número de relé fuera de rango.");
        }
    } else {
        Serial.println("Comando desconocido.");
    }
}

y el resultado:


He leído algunos post sobre el tema de arduino mega wifi y parece ser que no es nada sencillo implementar la comunicación serie entre arduino mega y esp8266. en alguno de ellos hablan de "flashear" el esp8266, pero no se si mis conocimientos se acercan siquiera a hacer eso. Ten en cuenta que me estoy ayudando de chatgpt para escribir los códigos.
agradezco cualquier consejo.....

El Serial1 del ESP8266 solo sirve para transmitir (solo se usa Tx) porque el pin Rx tiene otro uso y no se puede cambiar.

El 2560, de acuerdo a tu captura, está recibiendo lo que envía el 8266 por Serial, tal vez el puerto Serial1 no está conectado.

Te sugiero que los datos del 8266 los envíes por Serial (no envíes mensajes de depuración que de todos modos no puedes ver porque el puerto USB está conectado al 2560).

En resumen, en el código del 8266, elimina (o comenta) las líneas que actualmente usan Serial y cambia las que usan Serial1 a Serial y listo.

1 Like

Muchas gracias @cdavisongmz y @MaximoEsfuerzo por vuestra ayuda. Eliminando la libreria String y las referencias a serial1 por fin he conseguido comunicación entre esp8266 y ATmega. Ahora me queda por "depurar" si se puede llamar así el código ya que si bien los relés encienden correctamente, a veces alguno se queda "atascado" y no apaga. Entiendo que puede ser ruido en la transmisión/código. Voy a tener que hablar seriamente con Chatgpt!!!! jajjaja. Ahora fuera bromas, os reitero el agradecimiento por vuestra inestimable aportación (¡¡Que bueno es el saber!!) que además me motiva para aprender más y no solo para finalizar este proyecto. Lo dicho: dos cracks.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.