1

Code for Master

#include <Wire.h>

void setup() 
{
  Wire.begin();

  Serial.begin(9600); 
}

void loop()    
{      
    Wire.beginTransmission(9);
     
    Wire.write('c');   
    Serial.println('c');             
    Wire.write('a');   
    Serial.println('a');             
    Wire.endTransmission();
}

In my case Wire.write('c') is performing the task which is assigned to 'c' in slave board. Then its printing 'c' in serial monitor as intended. But, Wire.write('a') line is being neglected and nothing happens on slave board. But again, it's printing 'a' in serial monitor as per code. Why is that Wire.write('a'); is neglected? Both boards are Arduino Nano.

Code for Slave

#include <Wire.h>
#define RED 8
#define GREEN 10
int x = 0;

void setup() {
  pinMode (RED, OUTPUT);
  pinMode (GREEN, OUTPUT);
  Wire.begin(9);
  Wire.onReceive(receiveEvent);
}

void receiveEvent(int bytes) {
  x = Wire.read();    // read one character from the I2C
}

void loop() {
    if (x == 'a') {
        digitalWrite(RED, HIGH);
        digitalWrite(GREEN, LOW);
    }
    if (x == 'b') {
        digitalWrite(RED, LOW);
        digitalWrite(GREEN, HIGH);
    }
    if (x == 'c') {
        digitalWrite(RED, HIGH);
        digitalWrite(GREEN, HIGH);
    }
    if (x == 'd') {
        digitalWrite(RED, LOW);
        digitalWrite(GREEN, LOW);
    }
}
4
  • What is your slave board? Is it another Arduino? If yes, you need to show us the code for that too. Maybe you are misunderstanding how the Wire library works. Wire.write() does not send anything over the I2C lines. It only puts the data into the libraries internal buffer. Transmission is then done by Wire.endTransmission(), which sends out the content of the internal buffer as one I2C transmission. My guess is, that your slave is only reading the first byte of every transmission, thus ignoring the second byte ('a')
    – chrisl
    Apr 24 at 15:08
  • Thnak you for you reply i have added slave code also... please do see it.. thanks again
    – Akshay
    Apr 24 at 15:10
  • "transmission is then done by Wire.endTransmission()" this line gave me a hit, I modified my master code and now it working perfectlu.. thanks man
    – Akshay
    Apr 24 at 15:26
  • 1
    Make sure you mark the answer accepted and vote it up since it contains what you found useful.
    – timemage
    Apr 24 at 15:28
7

Important information: Wire.write() does NOT send anything over the I2C lines. It just puts the data into the libraries internal buffer. The actual transmission is then done by Wire.endTransmission().

I2C is packaged transmission protocol. That means, that the transmission is done in confined data packages. In your master code you are calling Wire.write() two times before Wire.endTransmission(). That means you are sending 1 package with 2 data bytes in it.

Now for your slave code: You are using a callback function for the onReceive event. This callback function is called once per transmission. In there you can read all the data of that transmission. After that the data is thrown away (I think actually it gets deleted, when a new transmission is received). You are only reading once with Wire.read(). So you only ever read the first byte of every transmission, which is always the letter 'c'.

What to do know? This depends on how you want the code to behave. Since you are setting 2 LEDs based on the received byte it would be better to only send 1 byte transmissions. For that, you can change your master code. For example like this:

#include <Wire.h>

void setup() 
{
  Wire.begin();

  Serial.begin(9600); 
}

void loop()    
{
    // Send the command c
    Wire.beginTransmission(9);
    Wire.write('c');
    Wire.endTransmission();
    
    // Wait 1s, so that we can see the LEDs state accordingly
    delay(1000);
 
    // Send command a
    Wire.beginTransmission(9);        
    Wire.write('a');       
    Wire.endTransmission();

    // Wait 1s, so that we can see the LEDs state accordingly
    delay(1000);
}

This code will change between 'c' and 'a' every second. You need a delay there to actually see the LEDs light up. Otherwise they would change too fast for you to see it.

Note: Actually you need to declare the variable x as volatile, because the onReceive callback is called from an ISR. With that keyword you are telling the compiler, that x can change at any time (by the ISR of the corresponding I2C interrupt). It might be, that your current code works, because the compiler was smart enough to see that, but in general you should always use volatile with every variable, that can change in an ISR. Declaration then looks like this:

volatile int x = 0;

And to handle the ISR data really correct, you would need to make the usage atomic, because the ISR can happen in the middle of the comparison for the if statements. An int is two bytes, so the first byte might be updated and the second byte not. That would corrupt your data. There are two ways to handle that in your case:

  • Make the reading of x atomic: Normally one would turn of the interrupts, read the volatile variables into local variables (as a copy) and then turn the interrupts on again. That way the interrupt cannot corrupt the data in the variable during reading. The further calculation/comparison would then be done with the local variable.

  • Use a single byte as volatile data: The described problem does not apply to variables, which only use 1 byte (since on the 8bit Arduinos like the Nano the reading of a single byte cannot be interrupted). So just make x of type char (or uint8_t or byte).

You should use the second option.

2
  • The OP does use two LEDs to show the state, so he should be able to see which was the last received letter.
    – PMF
    Apr 24 at 15:53
  • 3
    @PMF Yes, he/she uses 2 LEDs. But there are 4 states, each with a different pattern for those 2 LEDs. For each of the valid commands both LED states are written. So he/she can only see the last received command. If he/she sends two command without any delay between them, the first command is shown only a very short time (most likely too short to actually see it). Thus the delay
    – chrisl
    Apr 24 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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