7

If I remove the transmission code from slave this works properly but I need to transmit from slave.

Here is my master code

#include <Wire.h>
void setup() {
  Wire.begin(3); 
  Wire.onReceive(receiveEvent);
}
byte x = 0;

void loop() {
  Wire.beginTransmission(9); 
  Wire.write("s");        
  Wire.write(x);                
  Wire.endTransmission();    
  x++;
  delay(500);
}

void receiveEvent(int howMany) {
  if(Wire.available()){
    int x = Wire.read();
    Serial.println(x);
  }
}

Here is my slave code:

#include <Wire.h>
void setup() {
  Wire.begin(9);                // join i2c bus with address #9
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(100);
}

void receiveEvent(int howMany) {
  if(Wire.available()){
    char c = Wire.read(); 
    Serial.print(c);
    if(c == 's'){
      int x = Wire.read();
      Serial.println(x);
      //transmit to master 
      Wire.beginTransmission(3);
      Wire.write(1);
      Wire.endTransmission();
    } else {
      Wire.read();
    }
  }
}

Is it possible not to use Wire.onRequest(requestCallback); to send data to master? Kindly help.

5
  • 1
    When a sketch calls Wire.begin() and passes a number, it has nominated itself as a slave on the bus. So you appear to have two slaves. Normally one would have one master and one slave.
    – James Cameron
    Jun 23, 2014 at 8:44
  • What you seem to want is a combination of the Arduino Wire Tutorial arduino.cc/en/Tutorial/MasterReader and arduino.cc/en/Tutorial/MasterWriter do you agree?
    – James Cameron
    Jun 23, 2014 at 8:50
  • i had a look but not able to implement it properly any suggestion ? if i give 2 wire.write the master is not reading it properly
    – srinivas
    Jun 23, 2014 at 9:21
  • I don't know what you mean, sorry.
    – James Cameron
    Jun 23, 2014 at 9:37
  • the Wire.requestFrom has only one wire.write i need multiple wire.write which is not supported so is there any workarounds ?
    – srinivas
    Jun 23, 2014 at 14:30

3 Answers 3

6

To join the bus as a master you cannot supply a 7-Bit slave address so your code has two slaves.

Below you will find 2 sketches that successfully sends data to a slave. I would suggest you start looking at the I2C protocol and understand there are 4 Modes:

  • Master->Transmitter
  • Master->Receiver
  • Slave->Transmitter
  • Slave->Receiver

All communications regardless of how the data is transferred requires a master. It's the master that controls the clock pulses, thats why its always the master that initiates the communcation.

The MasterReader/MasterWriter tutorials on the arduino forum should now possibly start to make a little more sense when understanding those modes.

This code shows how a master sends data to a slave, and then how it requests data from the slave. If we look at this code from the master point-of-view, you can see it essentially says, send this byte to the client (m->t & s->r), then request data from the slave (m->r,s->t)

Master Code

#include <Wire.h>

#define SLAVE_ADDRESS 0x60

void setup()
{
  Wire.begin(); 
  randomSeed(analogRead(3));
  Serial.begin(9600);  
}

byte x = 0;

void loop()
{
  x = random(0,255);
  Serial.print("Sent: ");
  Serial.print(x, HEX);
  Serial.print("\n");
  Wire.beginTransmission(0x60);   
  Wire.write(x);                
  Wire.endTransmission();   
  delay(500);
  Serial.println("Requesting Data"); 
  Wire.requestFrom(SLAVE_ADDRESS, 1);

  int bytes = Wire.available();
  Serial.print("Slave sent ");
  Serial.print(bytes);
  Serial.print(" of information\n");
  for(int i = 0; i< bytes; i++)
  {
    x = Wire.read();
    Serial.print("Slave Sent: ");
    Serial.print(x, HEX);
    Serial.print("\n");
  }  
  delay(500);
}

Slave Code

#include <Wire.h>

#define SLAVE_ADDRESS 0x60
byte x = 0x00;
void setup()
{
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  Serial.begin(9600);
}

void loop()
{
  delay(100);
}

void requestEvent() 
{
  Serial.print("Request from Master. Sending: ");
  Serial.print(x, HEX);
  Serial.print("\n");

  Wire.write(x);
}

void receiveEvent(int bytes)
{
  if(Wire.available() != 0)
  {
    for(int i = 0; i< bytes; i++)
    {
      x = Wire.read();
      Serial.print("Received: ");
      Serial.print(x, HEX);
      Serial.print("\n");
    }
  }
}
3
  • On master you could scan the address range for connected device. This would be a proper approach.
    – wajatimur
    Feb 4, 2015 at 17:56
  • In both of your event handlers: Don't do serial prints inside an ISR. It may work until the serial buffer fills up, then it will hang.
    – Nick Gammon
    Jul 22, 2015 at 23:49
  • 1
    You don't need to test if(Wire.available() != 0) because the bytes variable has the number of bytes you received. If anything, test if bytes > 0 however I presume that a receive event would have at least one byte.
    – Nick Gammon
    Jul 22, 2015 at 23:50
2

I went through this problem recently. Your slave needs two functions: one for sending and the other for receiving data.

// function: what to do when asked for data
void requestEvent() {
Wire.write(t); 
}

// what to do when receiving data from master
void receiveEvent(int howMany)
{Val = Wire.read();}

Here is a code that works both ways of i2c communication in a single code

Sending and receiving different types of data via I2C in Arduino

0

You had:

 void receiveEvent(int howMany)
 {
   {         
         if(Wire.available()){
           char c = Wire.read(); 
           Serial.print(c);
           if(c == 's'){
             int x = Wire.read();
             Serial.println(x);

             //transmit to master 
             Wire.beginTransmission(3);
             Wire.write(1);
             Wire.endTransmission();

           }else{
             Wire.read();
           }
         }

       }

There are a number of problems with your slave code.

  1. Don't do Serial prints in an ISR (interrupt service routine)
  2. Don't do beginTransmission / endTransmission in a receive event.
  3. Don't do any writes
  4. To send data back use a requestEvent not a receiveEvent.

Better would be:

// add in setup()
Wire.onRequest (requestEvent);  // interrupt handler for when data is wanted

...


volatile byte what;

void receiveEvent(int howMany)
{
  if (howMany < 2)
    return;

  char c = Wire.read ();
  if (c != 's')
    return;

  what = Wire.read ();  // remember what we got
}  // end of receiveEvent

void requestEvent()
{
  Wire.write (1);  // return a response
}  // end of requestEvent

the Wire.requestFrom has only one Wire.write. I need multiple Wire.write which is not supported so are there any workarounds?

Batch up the response and do one write:

void requestEvent ()
  {
  byte buf [4] = { 1, 2, 3, 4 };
  Wire.write (buf, sizeof buf);   // send response
  }  // end of requestEvent

Reference

There are a lot of examples at I2C - Two-Wire Peripheral Interface - for Arduino

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.