NodeMCU <-> i2c <-> NodeMCU

Hola a todos, hoy necesito alguna orientación sobre I2C.

Necesito comunicar 2 NodeMCU por I2C, en teoría sencillo, pero no lo consigo. Y no encuentro ningún proyecto que se haya implementado, ni comentarios al respecto sobre NodeMCU <-> NodeMCU. Debería ser aún más sencillo (en cuanto a la electrónica) que de NodeMCU a UNO al tener el mismo voltaje.

El que tengo como Master parece que envía la información, pero el Slave nunca activa la función de recepción. He probado con y sin resistencias de Pull-UP y de 1K y 4,7K.

¿Alguna idea o experiencia reveladora?

El código con el que estoy probando es de la página de Luis Llamas, con un añadido para que parpadee el led y ver que están en ejecución ambas placas.

Master:

#include "Wire.h"

const byte I2C_SLAVE_ADDR = 0x20;

long data = 100;
long response = 0;
long parpadeo;
long envio;
boolean On;

void setup()
{
   Serial.begin(115200);
   Wire.begin();
   pinMode(D4, OUTPUT);
}

void loop()
{
   if (millis() > parpadeo + 300) {
       parpadeo=millis();
       if (On) {
        digitalWrite(D4, HIGH);
        On=!On;
       }
       else {
          digitalWrite(D4, LOW);
          On=!On;
       }
   }

   if (millis() > envio + 2000) {
    envio=millis();
    sendToSlave();
    requestToSlave();
   }
}

void sendToSlave()
{
   Wire.beginTransmission(I2C_SLAVE_ADDR);
   Wire.write((byte*)&data, sizeof(data));
   Wire.endTransmission();
   Serial.println("Enviamos Datos");
}

void requestToSlave()
{
   response = 0;
   Wire.requestFrom(I2C_SLAVE_ADDR, sizeof(response));
   
   uint8_t index = 0;
   byte* pointer = (byte*)&response;
   while (Wire.available())
   {
      *(pointer + index) = (byte)Wire.read();
      index++;
   }
   
   Serial.print("Respuesta: ");
   Serial.println(response);
   
}

Slave:

//led D4 GPIO2

#include "Wire.h"

const byte I2C_SLAVE_ADDR = 0x20;

void setup()
{
   Serial.begin(115200);

   Wire.begin(I2C_SLAVE_ADDR);
   Wire.onReceive(receiveEvent);
   Wire.onRequest(requestEvent);
   pinMode(D4, OUTPUT);
}

long data = 0;
long response = 200;
long parpadeo;
boolean On;

void receiveEvent(int bytes)
{
   data = 0;
   uint8_t index = 0;
   while (Wire.available())
   {
      byte* pointer = (byte*)&data;
      *(pointer + index) = (byte)Wire.read();
      index++;
   }
   Serial.print("Recibimos datos: ");
   Serial.println(data);
   digitalWrite(D4, HIGH);   
   delay(1000);
   digitalWrite(D4, LOW);    
}

void requestEvent()
{
   Wire.write((byte*)&response, sizeof(response));
   Serial.print("Respondemos. Datos: ");
   Serial.println(response);
   digitalWrite(D4, HIGH);  
   delay(1000);
   digitalWrite(D4, LOW);   
}


void loop() {

   if (millis() > parpadeo + 300) {
       Serial.println("Estamos esperando");
       parpadeo=millis();
       if (On) {
        digitalWrite(D4, HIGH);
        On=!On;
       }
       else {
          digitalWrite(D4, LOW);
          On=!On;
       }
   }
       
   if (data != 0)
   {
      Serial.println(data);
      data = 0;
   }
}

La protoboard, por si aporta algo:

Gracias de antemano por su atención.

Así, en un primer vistazo te puedo decir que ambos arduinos tienen igual dirección (0x20).
En el Master no hace falta definir una dirección con un simple Wire.begin() es suficiente.

Bueno en un segundo vistazo, me doy cuenta que no tienes muy en claro la diferencia en una comunicación, maestro-esclavo. Los códigos en ambos arduinos son iguales. El esclavo no inicia la comunicación con el maestro. En el IDE de Arduino hay ejemplos que tendrían que dejarte un poco mas en claro como funciona.

No se si para NodeMCU la constante D4 ya está definida, si no es el caso, no definiste cuál es el pin D4 (al menos en los códigos que nos muestras).

Lo simplifiqué para enviar/recibir un solo byte para que pruebes si funciona la comunicación

Master

#include "Wire.h"

const byte I2C_SLAVE_ADDR = 0x20;

byte data = 100;
byte response = 0;
long parpadeo;
long envio;
boolean On = true;
const byte D4 = 4; // ajusta al pin adecuado

void setup() {
  Serial.begin(115200);
  Wire.begin();
  pinMode(D4, OUTPUT);
}

void loop() {
  if (millis() - parpadeo >= 300) {
    parpadeo=millis();
    On = !On;
    digitalWrite(D4, On);
  }

  if (millis() - envio >= 2000) {
    envio=millis();
    sendToSlave();
    requestToSlave();
  }
}

void sendToSlave()
{
  Wire.beginTransmission(I2C_SLAVE_ADDR);
  Wire.write(data);
  if(Wire.endTransmission() == 0) {
    Serial.println("Enviamos Datos");
  }
}

void requestToSlave() {
  response = 0;
  Wire.requestFrom(I2C_SLAVE_ADDR, byte(1));
  while (Wire.available()){
    response = Wire.read();
  }
   
  Serial.print("Respuesta: ");
  Serial.println(response);
   
}

Esclavo

#include "Wire.h"

const byte I2C_SLAVE_ADDR = 0x20;

byte data = 0;
byte response = 200;
long parpadeo;
boolean On;
const byte D4 = 4; // ajustar a pin adecuado

void receiveEvent(int bytes) {
  data = 0;
   
  while (Wire.available()) {
    data = (byte)Wire.read();
  }
  
  Serial.print("Recibimos datos: ");
  Serial.println(data);
  digitalWrite(D4, HIGH);   
  delay(1000);
  digitalWrite(D4, LOW);    
}

void requestEvent() {
  Wire.write(response);
  
  Serial.print("Respondemos. Datos: ");
  Serial.println(response);
  digitalWrite(D4, HIGH);  
  delay(1000);
  digitalWrite(D4, LOW);   
}

void setup() {
  Serial.begin(115200);

  Wire.begin(I2C_SLAVE_ADDR);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  pinMode(D4, OUTPUT);
}

void loop() {

  if (millis() - parpadeo >= 300) {
    Serial.println("Estamos esperando");
    parpadeo=millis();
    On=!On;
    digitalWrite(D4, On);
  }
       
  if (data != 0) {
    Serial.println(data);
    data = 0;
  }
}

Fijate si ahora hay respuesta.

Yo solo lo puedo probar en Nano, y con Nano funciona bien (de hecho estoy usando un código similar ahora mismo en un proyecto con 7 Nano esclavos).

Gracias por dedicarme vuestro tiempo.

@PeterKantTropus En el Master está como comentas Wire.begin (). La dirección sólo la indico en la placa Slave. Es la primera vez que utilizo la comunicación maestro-esclavo, y estoy afianzando conceptos. Yo creo que no viste bien el código. Los códigos son distintos y el esclavo no inicia, pero responde cuando lo solicita el maestro. En principio vi y entendí el ejemplo (bastante simple) de Luis Llamas y tienes razón no se me ocurrió mirar los ejemplos. Gracias por el consejo, me pongo a ello.

@anon90500195 la constante D4 efectivamente ya está definida y es el pin GPIO2 del ESP-12E. Tiene dos leds integrados y uno está asociado a este pin. Probé tu código tal cual y el esclavo no se despierta.

Alguna peculiaridad tiene que haber, ya que no he encontrado dos conectados por ningún lado.

Voy a ver los que comenta @PeterKantTropus y mirar los ejemplos. Si no consigo nada, cambio uno por el UNO o nano que eso si he visto muchos ejemplos funcionando.

Gracias a los dos.

Volví a darme una vuelta, consultando de forma distinta y encontré esto:

El ESP actualmente solo admite el modo maestro I2C, no puede ejecutarlo en modo esclavo.

No exactamente, el problema es la librería y la compatibilidad con la IDE de arduino.

Si seguís leyendo los post, más adelante explica que hay un problema con la implementación de las interrupciones en el core del ESP y como en modo esclavo I2C trabaja por interrupciones... Chau modo esclavo.

O sea, el problema es de soft.

Saludos

Moderador:
Todo lo que no es Arduino va en microcontroladores. Acá he movido tu hilo.
Por favor mas atención en los próximos posteos.
Siempre lee las normas del foro donde te encuentres.

cuéntanos para que necesitas la comunicación i2c ¿Necesitas muy alta velocidad de transferencia de datos? Hay otras alterativas Maestro-esclavos que no dependen del microprocesador , como modbus (que tiene muchas mas ventajas).

Comparto el criterio de @PeterKantTropus incluso dos nodemcu comunicados por I2C es muy raro, lo haría y lo hago con Arduinos que no tiene mas que comunicaciones cableadas pero con nodemcu que pueden comunicarse por WIFI, porque no hacerlo asi?
Diras porque estan cercanos, bueno, pero por que dos nodemcu?
Puedes dar mas datos del contexto del problema que te llevo a decidir usar I2C y no otra forma de comunicación?

Bueno, lo primero gracias por vuestro interés. Realmente no hay ninguna razón de peso mas que la de aprender cosas nuevas.

Mis proyectos no tienen sentido si no están conectados a internet, aunque sea solo para recuperar el día y la hora. Por eso me gusta NodeMCU (y por el precio también), peeero me quedo sin pines enseguida.

Ahora estoy preparando un proyecto que gestione mi acuario de agua dulce: Luces led, comedero automático, aireador, calentador, pantalla tft 28’’…. Subiendo datos a thingspeak y control con Blynk.

La Pantalla TFT de 240x320 de 3v perfecta con NodeMCU, pero ya no me quedan pines ni para poner un multiplexor 74HC4067.

Buscando soluciones al “problema”, se me ocurre poner un Arduino Uno que trabaje y le pase la info a NodeMCU para que la muestre en pantalla y haga el trabajo de IoT, bueno mejor el nano por su tamaño. Ahhhh que van a 5v, ponemos un level shifter y listo, pero eso supone mas cables ¿y si pongo otro NodeMCU? ¿Que (en teoría) con dos cables y cuatro líneas de código está resuelto…? Y tengo todo a 3v.

Esta lógica, entiendo que un poco absurda, es por la que estoy probando la comunicación i2C entre dos NodeMCU. ¡No tengo más razones¡

Ya está descartada y espero probar comunicación i2c entre nano y nodeMcu, con el level shifter entre ambos, esta misma tarde. Que realmente es mejor opción, lo sé, por la cantidad de pines del Arduino, entre otras razones.

I2c

@ PeterKantTropus, sobre lo que comentas de modbus. Sinceramente, no tengo ni idea de lo que es, pero en cuanto termine de escribir me pongo a estudiarlo.

Quedo a la espera de cualquier comentario y/o sugerencia, encantado de aprender con ustedes.

Un saludo.

Ahora que contextualizas el proyecto uno se da cuenta cuantas tonterías hemos escrito, simplemente porque no se sabe que se quiere hacer.
Se ahorra mucho tiempo de los que aquí queremos ayudar haciendo esto que has hecho, explicando.
Si necesitas pines requires de un MEGA y no pierdas el tiempo con 1,2 3, n nodemcu.
Un MEGA tiene 54 I/Os simple.
Quieres poner dos NANOs okay, quieres poner dos nodemcu por aprender okay, tmb.

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