I am trying to get bidirectional communication via I2C set up between two Arduinos:
I want ArduinoA to send a byte to ArduinoB. ArduinoB then turns on the led at pin13 and sens a byte back to ArduinoA. ArduinoA then turns on the led at pin13 as well.
I can send a byte from ArduinoA to ArduinoB. ArduinoB the turns on the LED. However, after that, ArduinoB just sort of stalls. It never sends anything over I2C, it stops sending the serial commands.
I have connected A5 to A5 and A4 to A4 with 3.9k Pull Up resistors added.
#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
int counter = 0;
byte b;
void setup()
{
Wire.begin (MY_ADDRESS);
Wire.onReceive (receiveEvent);
Serial.begin(9600);
pinMode(13,OUTPUT);
} // end of setup
void loop()
{
if (counter == 0){
//I want this block to be executed once.
//It could also be in setup, but I will need it within my loop later down the line.
Serial.print("begin transmission1 ");
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (1);
Wire.endTransmission ();
counter = 1;
}
} // end of loop
void receiveEvent (int numBytes)
{
digitalWrite(13,HIGH); //the led does not turn on
Serial.print("Receiving Data "); //this is never printed to serial
while (Wire.available () > 0)
{
b = Wire.read ();
Serial.println(b);
} // end of while available
Serial.print("begin transmission2 "); //this is not printed to serial either
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (1);
Wire.endTransmission ();
} // end of receiveEvent
This is the Slave (Arduino Uno):
#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 2;
void setup ()
{
Wire.begin (MY_ADDRESS);
Wire.onReceive (receiveEvent);
pinMode(13,OUTPUT);
Serial.begin(9600);
} // end of setup
void loop()
{
Serial.println("Serial working"); //this acts as expected, but stops once the LED is turned on
}
// called by interrupt service routine when incoming data arrives
void receiveEvent (int numBytes)
{
digitalWrite(13,HIGH); //This works ok.
Serial.println("LED turned on"); //this never gets sent
Wire.beginTransmission (OTHER_ADDRESS);
Serial.println("transmission started");
Wire.write (val);
Wire.endTransmission ();
Serial.print("transmission ended");
delay (20);
}
The receive event must return before the I2C bus is free, so initiating another transmission inside the receive event is impossible, it might have frozen waiting for the bus to be free
Ok, slightly improved, but this is still not working the way I want to.
Basically, I can do all I described in the original post. ArduinoA sends a byte to ArduinoB. ArduinoB turns on LED, sends a byte back to ArduinoA. ArduinoA turns on LED.
I want to keep them talking, sending bytes back and forth. However, ArduinoA seems to be unable to send a second byte, or ArduinoB cannot receive it.
Heres my code
ArduinoA (master, duemillenove):
// Based on a tutorial by Nick Gammon
#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
byte b;
boolean byteReceived = false;
void setup()
{
Wire.begin (MY_ADDRESS);
Wire.onReceive (receiveEvent);
Serial.begin(9600);
pinMode(13,OUTPUT);
//This seems to work:
Serial.print("begin transmission0 ");
delay(200);
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (1);
Wire.endTransmission ();
}
void loop()
{
if (byteReceived){
//this part only executes once, presumably becouse the receiveEvent only executes once
digitalWrite(13,HIGH); // the led gets turned on
Serial.println("byte received ");
Serial.println("begin transmission1 ");
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (1);
Wire.endTransmission ();
Serial.println("end transimssion1 ");
byteReceived = false;
}
}
//this part also only seems to execute once:
void receiveEvent (int numBytes)
{
while (Wire.available () > 0)
{
b = Wire.read (); //never tested this
}
byteReceived = true;
}
Arduino B (Slave, Uno):
#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 2;
boolean byteReceived = false;
void setup ()
{
Wire.begin (MY_ADDRESS);
Wire.onReceive (receiveEvent);
pinMode(13,OUTPUT);
Serial.begin(9600);
}
void loop()
{
if(byteReceived){
//this part only executes once.
Serial.println("byte1 received");
digitalWrite(13,HIGH);
delay(50);
Wire.beginTransmission (OTHER_ADDRESS);
Serial.println("transmission started");
Wire.write (val);
Wire.endTransmission ();
Serial.print("transmission ended");
byteReceived = false;
}
}
// called by interrupt service routine when incoming data arrives
//it only executes once. If I send in more data (by resetting my master arduino) it does not execute again.
void receiveEvent (int numBytes)
{
byteReceived = true;
}
Arduino B doesn't receive the byte. You have to call Wire.read() in your actually get the bytes read and (that's important) to have the acknowledge sent.