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.

dda
  • 1,595
  • 1
  • 12
  • 17
srinivas
  • 83
  • 1
  • 1
  • 4

3 Answers3

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");
    }
  }
}
Wayne
  • 161
  • 3
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

Camilo
  • 359
  • 2
  • 5
  • 12
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

Nick Gammon
  • 38,901
  • 13
  • 69
  • 125