Pages: [1]   Go Down
Author Topic: Problem Setting up I2C Handshake  (Read 1053 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 3
Posts: 716
a, b = b, a+b
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Hi everyone

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.

Here is my code. Its based on Nick Gammons tutorial (http://www.gammon.com.au/forum/?id=10896)

This is the Master (Arduino Duemillenove):
Code:
#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):

Code:
#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);
}


Any suggestions?
Logged


0
Offline Offline
God Member
*****
Karma: 0
Posts: 593
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: June 14, 2012, 10:46:23 am by frank26080115 » Logged

Freelance engineer, consultant, contractor. Graduated from UW in 2013.

Offline Offline
God Member
*****
Karma: 3
Posts: 716
a, b = b, a+b
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

cool. that should fix it.

thanks.
Logged


Offline Offline
God Member
*****
Karma: 3
Posts: 716
a, b = b, a+b
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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):

Code:
// 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):

Code:
#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;
}



Logged


Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5152
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
God Member
*****
Karma: 3
Posts: 716
a, b = b, a+b
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

yep. that fixed it.

thanks

edit: posting code, in case anyone is interested:

Master:

Code:
// 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){
    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;
    Serial.println("b");
    Serial.println(b);
  }

}  


void receiveEvent (int numBytes)
{
  while (Wire.available () > 0)
  {
    b = Wire.read (); //never tested this
  }  
  byteReceived = true;
}

Slave:

Code:

#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
byte c;
byte val = 3;
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
void receiveEvent (int numBytes)
{
   while (Wire.available () > 0)
  {
    c = Wire.read (); //never tested this
  }
  byteReceived = true;
}


« Last Edit: June 14, 2012, 07:37:42 pm by fkeel » Logged


Pages: [1]   Go Up
Jump to: