Help using I2C?

Hello guys! Newbie here, first time programming multiple Arduinos. Could you help me determine what’s wrong with my code? It’s crappy, I know. I just want to test I2C.

Master Code:

#include <Wire.h>

int alarm = 13;
int P = 1; //Process Number

void setup(){
  Wire.begin();
  Serial.begin(9600);
  
  pinMode(alarm, OUTPUT);
  digitalWrite(alarm, LOW);
  
  Wire.requestFrom(1,11);
   while(Wire.available()){
     char S1 = Wire.read();
     if(S1 == 'Slave1 Done'){
        Wire.beginTransmission(1);
        Wire.write('Slave1 Off');
        Wire.endTransmission(1);
        P = 2;
     }    
   }
   delay(50);
   
  Wire.requestFrom(2,11);
   while(Wire.available()){
     char S2 = Wire.read();
     if(S2 == 'Slave2 Done'){
        Wire.beginTransmission(2);
        Wire.write('Slave2 Off');
        Wire.endTransmission(2);
        P = 3;
     }    
   }
    delay(50); 
 
}

void loop(){
  Serial.print("BEGIN");
  
  while(Serial.available()){
  Serial.print("here");
  char M = Serial.read();
    Serial.print(M);
    if(M == 'GO'){
      digitalWrite(alarm, HIGH);    
      delay(1000);
      
      if(P = 1){
        Wire.beginTransmission(1);
        Wire.write('Slave1 On');
        Wire.endTransmission(1);
      }
      else if(P = 2){
        Wire.beginTransmission(2);
        Wire.write('Slave2 On');
        Wire.endTransmission(2);
      }
      else if(P = 3){
        M = 'STOP';
      }
    }
    else if(M == 'STOP'){             
      digitalWrite(alarm, LOW);    
      delay(1000);
    }
  } 
}

Slave1&2 Code:

#include <Wire.h>

int i = 0;

void setup()
{
  Wire.begin(1);
  Wire.onReceive(receiveEvent);
  
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char S1 = Wire.read();
    
    if(S1 == 'Slave1 On'){
      Serial.print(S1);
      for(i = 0; i < 5; i++){
        digitalWrite(13,HIGH);
        delay(1000);
        digitalWrite(13,LOW);
        delay(1000);
      }
      digitalWrite(13,HIGH);
      delay(1000);
      Wire.onRequest(requestEvent);
    }
    else if(S1 == 'Slave1 Off'){
      Serial.print(S1);
      digitalWrite(13,LOW);
      delay(1000);
    }
  }
}

void requestEvent()
{
  Wire.write('Slave1 Done');
  
}

If I type ‘GO’ to the Serial Monitor, the master will alert slave1 and slave1’s LED will blink 5 times then slave1 will alert master that he’s finish then master will alert slave2 and slave2 will blink 3 times then slave will tell master that he’s done and master will turn slave1 and slave2’s LED off.

I tried using Serial.print() to determine what’s running. It seems that it doesn’t enter the wire.requestFrom() in void setup() so I moved it into the void loop() but then it can’t enter the while(Serial.available()). I don’t know what to do now

   if(S1 == 'Slave1 On'){

'Slave On' is not a string and you can't test for equality of strings in any case. Look at the string functions such as strcmp - string compare.

Mark

Changed strings to letters, still doesn't work :(

void receiveEvent(int howMany)

This is an interrupt handler. There are things you shouldn't do in interrupt handlers, like Serial.print(), and things you can NOT do, like delay().

Start over. Collect the data in the function, and make loop() use the data.

Thank you PaulS! That convinced me I know nothing about this I2C programming. =( I$ just combined the master-write-slave-read code to the master-read-slave-write code from this [ur=http://www.youtube.com/watch?v=Jndb2vpAWwUl]tutorial[/url] hoping it would lead to 1master 2slave communication.

What site do you recommend that shows basic 1 master nslave communication?

What site do you recommend that shows basic 1 master nslave communication?

http://www.gammon.com.au/forum/?id=10896

on the sample code given,

Master

// Written by Nick Gammon
// February 2012

#include <Wire.h>

const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
const byte LED = 13;

void setup() 
  {
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);
  pinMode (LED, OUTPUT);     
  }  // end of setup

void loop() 
  {
  
  for (int x = 2; x <= 7; x++)
    {  
    Wire.beginTransmission (SLAVE_ADDRESS);
    Wire.write (x);
    Wire.endTransmission ();
    delay (200);
    }  // end of for

  }  // end of loop

void receiveEvent (int howMany)
 {
  for (int i = 0; i < howMany; i++)
    {
    byte b = Wire.read ();
    digitalWrite (LED, b); 
    }  // end of for loop
} // end of receiveEvent

Slave

// Written by Nick Gammon
// February 2012

#include <Wire.h>

const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;

void setup () 
  {
  Wire.begin (MY_ADDRESS);
  for (byte i = 2; i <= 7; i++)
    pinMode (i, OUTPUT);
  Wire.onReceive (receiveEvent);
  }  // end of setup

void loop() 
  {
  int v = analogRead (0);
  Wire.beginTransmission (OTHER_ADDRESS);
  Wire.write (v < 512);
  Wire.endTransmission ();
  delay (20);
  }  // end of loop

// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
 {
  for (int i = 0; i < howMany; i++)
    {
    byte c = Wire.read ();
    // toggle requested LED
    if (digitalRead (c) == LOW)
      digitalWrite (c, HIGH);
    else
      digitalWrite (c, LOW);
    }  // end of for loop
  }  // end of receiveEvent

What does it do? I don’t get it

For a start:

      if(P = 1){
...
      else if(P = 2){

http://www.gammon.com.au/forum/?id=12153#trap3


Next:

  Wire.requestFrom(1,11);
   while(Wire.available()){
     char S1 = Wire.read();
     if(S1 == 'Slave1 Done'){
        Wire.beginTransmission(1);
        Wire.write('Slave1 Off');
        Wire.endTransmission(1);
        P = 2;
     }    
   }

Apart from the problem with the quotes:

http://www.gammon.com.au/forum/?id=12153#trap22

You are asking for 11 bytes and reading one. It would be much easier to define a couple of numbers, eg. 1 = Slave1 done, 2 = Slave1 on, and so on. Then ask for a single byte rather than 11 bytes.

In fact you don't need "Slave1 done" because since you ask slave 1 a question, presumably slave 1 replies. So you just need: 1 = done, 2 = on, and so on.


I2C addresses 0 to 7 and 120 to 127 are reserved, so your first slave should really be address 8.

Also:

 if(S1 == 'Slave1 Done'){
        Wire.beginTransmission(1);
        Wire.write('Slave1 Off');
        Wire.endTransmission(1);
        P = 2;
     }

You can't transmit back to the slave while the slave is talking to you. It's like talking to someone while they are talking to you. Wait for them to finish, then reply.

Why do you even need to tell it to turn off? If Slave1 sends you "done" and you reply "off" why not make the slave do "off" when it is "done"?

Thank you, Nick! One question though, can master-write-slave-read and slave-write-master-read coexist in a code?

Yes, not at the exact same moment, but in principle.

http://www.gammon.com.au/i2c

Thank you for all the comments! Here’s the code I tweaked from jeremy blum (aka humanHardDrive in youtube.com) that shows both master-write-slave-read and master-read-slave-write for 1 master 2 slaves :slight_smile:

Master

#include <Wire.h>

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW); 
}

void loop()
{ 
  int P = 0;
  
  while(Serial.available())
  {
    char M = Serial.read();
    Serial.print(M);
    
    if(M == 'G') //G means GO
    {
      Serial.print("BEGIN");      
      digitalWrite(13, HIGH);    
      
      if(P == 0)
      {
        Wire.beginTransmission(8);
        Wire.write('H'); //H means HIGH
        Wire.endTransmission();
        
        Wire.requestFrom(8,1);
        delay(3000);   
        while(Wire.available())
        {
          char S1 = Wire.read();
     
          if(S1 == '1')
          { 
            P = 1; // S1 is HIGH
            Serial.print("SLAVE1 DONE!");
          }    
        }
        delay(50);
      }
      if(P == 1)
      {
        Wire.beginTransmission(9);
        Wire.write('H'); 
        Wire.endTransmission();
        
        Wire.requestFrom(9,1);   
        delay(3000);
        while(Wire.available())
        {
          char S2 = Wire.read();
     
          if(S2 == '1')
          {
            P = 2; // S2 is HIGH
            Serial.print("SLAVE2 DONE!");
          }    
        }
        delay(50); 
      }
      if(P == 2)
      {
        Serial.print("END");
        Wire.beginTransmission(8);
        Wire.write('L'); //L means LOW
        Wire.endTransmission();
        Wire.beginTransmission(9);
        Wire.write('L'); 
        Wire.endTransmission();
        P = 0;
      }      
    }
    else if(M == 'S') //S means STOP
    {             
      Serial.print("END");
      digitalWrite(13,LOW);
      P = 0;    
    }
  } 
}

Slave1

#include <Wire.h>

void setup()
{
  Wire.begin(8);
  Wire.onReceive(receiveEvent);
  
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);
}

void loop()
{
  delay(10);
}

void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char S1 = Wire.read();
    
    if(S1 == 'H')
    {
      digitalWrite(13,HIGH);
      Wire.onRequest(requestEvent);
    }
    else if(S1 == 'L')
    {
      digitalWrite(13,LOW);
    }
  }
}

void requestEvent()
{
  Wire.write('1'); 
}

Slave2

#include <Wire.h>

void setup()
{
  Wire.begin(9);
  Wire.onReceive(receiveEvent);
  
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);
}

void loop()
{
  delay(10);
}

void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char S2 = Wire.read();
    
    if(S2 == 'H')
    {
      digitalWrite(13,HIGH);
      Wire.onRequest(requestEvent);
    }
    else if(S2 == 'L')
    {
      digitalWrite(13,LOW);
    }
  }
}

void requestEvent()
{
  Wire.write('1'); 
}