accelerometer analog values from one arduino to another arduino using wire.h

Hey guys n00b here,please help!
I’m using i2c to send the data of Accelerometer incoming analog values from master arduino to slave arduino.
I can send only 1 value not all 3 at the same time.
Please help.
Thanks

Master Code

#include <Wire.h>

const int xPin = 0;
const int yPin = 1;
const int zPin = 2;


void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;
byte y = 0;
byte z = 0;


void loop()
{
  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  Wire.beginTransmission(4); // transmit to device #4

  Wire.write("x is ");        
  Wire.write(xRead);             

  Wire.write("y is ");        
  Wire.write(yRead);             

  Wire.write("z is ");      
  Wire.write(zRead);              


  Wire.endTransmission();    

  x++;
  y++;
  z++;

  delay(500);
}

slave code

// Wire Slave Receiver
#include <Wire.h>

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

void loop()
{
  delay(100);
}


void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer

  int y = Wire.read();    // receive byte as an integer
  Serial.println(y);         // print the integer

  int z = Wire.read();    // receive byte as an integer
  Serial.println(z);         // print the integer
}

Don't use a Serial function in the onReceive handler. The onReceive is an interrupt handler and should be as short and as fast as possible.

In the examples, readable text is transmitted via I2C, but I2C is always used with binary data.
In the Slave, the parameter 'howMany' is the number of received bytes. Therefor, the Wire.available() is not needed anymore.

You want to transmit 3 integers ?
Create an array of three integers : int data [ 3 ] ;
Fill them with the data, and write them with single write : Wire.write ( (byte *) data , 6 ) ;
In the Slave, you can check if 'howMany' is 6, and use Wire.readBytes() to read the data in a array of three integers.

Thank you for the reply sir.

I’ve edited my master code as you’ve said here it is

master

#include <Wire.h>

const int xPin = 0;
const int yPin = 1;
const int zPin = 2;


void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
}




void loop()
{
  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  Wire.beginTransmission(4); // transmit to device #4

  int data [3] = {xRead, yRead, zRead};


  Wire.write ( (byte *) data , 6 ) ;

  Wire.endTransmission();



  delay(100);
}

I cannot understand what to do at the slave side.

It would be appreciated if you do it for me
Thanks

For the Master you fill in the array when declaring it. That is okay. I would do it different, like this:

int data[3];
data[0] = analogRead(xPin);
data[1] = analogRead(yPin);
data[2] = analogRead(zPin);

When an array of three elements is created, the elements are at index [ 0 ], [ 1 ], [ 2 ]. They are filled with the x, y, and z value.
Did you change the delay from 500 to 100 ? Perhaps it is safer to keep using 500 for now.

For the Slave, it is the same, but the other way around. I did not test the next code.

// Wire Slave Receiver
#include <Wire.h>

// Variables that are changed in an interrupt routine, should be 'volatile'.
// With 'volatile' the compiler allows that they can suddenly be changed in an interrupt.

volatile int data[3];     // received data for x, y, z.
volatile boolean validData = false; // flag to indicate that something is received.

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

void loop()
{
  // The loop does not contain a delay(), since the 'validData' is checked as many times as possible

  if(validData)
  {
    // It is best to make a copy of the data while interrupts are disabled, but for now they are used directly.
    Serial.print("x=");
    Serial.print(data[0]);
    Serial.print(", y=");
    Serial.print(data[1]);
    Serial.print(", z=");
    Serial.print(data[2]);
    Serial.println();

    // Now that the data is used, reset the flag for new data.
    validData = false;
  }
}


void receiveEvent(int howMany)
{
  // 6 bytes are expected.
  // If not 6 bytes received, then ignore everything.

  if( howMany == 6)
  {
    // extra safety check. If the flag is clear, fill a new value.
    if( !validData)
    {
      Wire.readBytes( (byte *) data, 6);
      validData = true;
    }
  }
}

Do you see how the interrupt handler works together with the code in the loop ? The data is a global array that is filled in the interrupt, and used in the loop. The flag ‘validData’ makes that smoother.

I totally understood this one,and this one is working like a charm now.
Thank you very much sir..

Nice!
When you want to add more variables, like a byte a float or something else, then you can transmit a 'struct'. That is what I always do. A 'struct' can contain any combination of variables. The Master and Slave should have exactly the same struct of course. The maximum size for the Wire library to transmit is 32 bytes.

struct
{
  int x;
  int y;
  int z;
  float voltage;
  float temperature;
  boolean alarm;
  char identifier[6];
} myData;

Wire.write( (byte *) &myData, sizeof( myData));

An array is already a pointer, but a 'struct' is not. So I had to use the address of the struct "&myData" and cast that to a byte pointer.

In your sketch you could also use "sizeof(data)" instead of "6". The "sizeof()" is a command for the compiler to fill in the size of it.

thanks for the reply sir, I included one more sensor (Ultrasonic sensor) and I’m sending the Accelerometer and ultrasonic sensor wirelessly using 433Mhz Rx and Tx modules from Arduino UNO #1( 433Mhz Transmitter) ,On the other hand side I’m receiving the data on Arduino UNO #2 (Receiver & Master i2c ) and i can successfully read the incoming data and can work on it, Now I want to send this Data which is received my Arduino UNO #2 by using i2c using wire.h to Arduino UNO #3 (Slave i2c) ,I’ve done the same thing as you said but included the values of ultrasonic sensor too, and i cannot read the values of both the sensors on salve Arduino.

I made three sketches for all three Arduinos

Here are the three codes…

Arduino UNO #1( 433Mhz Transmitter)

#include <VirtualWire.h>

const int transmit_pin = 12;

#define echoPin 7
#define trigPin 8 

const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

int maximumRange = 200;
int minimumRange = 0;

long duration;

int minVal = 265;
int maxVal = 402;


int x;
int y;
int z;
int distance;


void setup() {

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  vw_set_tx_pin(transmit_pin);

  Serial.begin(9600);
  vw_setup(2000);
}

void loop() {


  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);

  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);

  int xAng = map(xRead, minVal, maxVal, -90, 90);
  int yAng = map(yRead, minVal, maxVal, -90, 90);
  int zAng = map(zRead, minVal, maxVal, -90, 90);


  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
  y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
  z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);

  distance = duration / 58.2;

  Serial.print("X: ");
  Serial.print(x);

  Serial.print("  Y: ");
  Serial.print(y);

  Serial.print("  Z:");
  Serial.print(z);

  Serial.print("   Distance");
  Serial.println(distance);

  int sensorArray[] = {x, y, z, distance};

  digitalWrite(13, true);
  vw_send((uint8_t *)sensorArray, sizeof(sensorArray));
  vw_wait_tx();
  delay(50);

}

Arduino #2 (Receiver & Master i2c)

#include <VirtualWire.h>
#include <Wire.h>


int ledPin = 13;



int x, y, z, distance;
int sensorArray[4] = {};


const int receive_pin = 3;

void setup() {

  pinMode(ledPin, OUTPUT);

  vw_set_rx_pin(receive_pin);
  vw_set_ptt_inverted(true);

  vw_setup(2000);
  Serial.begin(9600);

  vw_rx_start();

}

void loop() {
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;


  if (vw_get_message(buf, &buflen))
  {
    memcpy(sensorArray, buf, buflen);

    x = sensorArray[0];
    y = sensorArray[1];
    z = sensorArray[2];
    distance = sensorArray[3];



    Serial.print("X: ");
    Serial.print(x);

    Serial.print("  Y: ");
    Serial.print(y);

    Serial.print("  z: ");
    Serial.print(z);

    Serial.print("  Distance: ");
    Serial.print(distance);

    Serial.println();

    int data[4];

    data[0] = x;
    data[1] = y;
    data[2] = z;
    data[3] = distance;


    Wire.beginTransmission(4); // transmit to device #4

    Wire.write ( (byte *) data , 6 ) ;

    Wire.endTransmission();


    delay(100);

  }
}

Arduino UNO #3 (Slave)

#include <Wire.h>


volatile int data[4];     // received data for x, y, z.
volatile boolean validData = false; // flag to indicate that something is received.

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output

}

void loop()
{
  // The loop does not contain a delay(), since the 'validData' is checked as many times as possible

  if (validData)
  {
    // It is best to make a copy of the data while interrupts are disabled, but for now they are used directly.
    Serial.print("x=");
    Serial.print(data[0]);
    Serial.print(", y=");
    Serial.print(data[1]);
    Serial.print(", z=");
    Serial.print(data[2]);
    Serial.print(", Distance=");
    Serial.print(data[3]);
    Serial.println();


    // Now that the data is used, reset the flag for new data.
    validData = false;


  }
}



void receiveEvent(int howMany)
{
  // 6 bytes are expected.
  // If not 6 bytes received, then ignore everything.

  if ( howMany == 6)
  {
    // extra safety check. If the flag is clear, fill a new value.
    if ( !validData)
    {
      Wire.readBytes( (byte *) data, 6);
      validData = true;
    }
  }
}

Please help me…

Four integers are 8 bytes. You have to transmit and receive 8 bytes. Or you can use "sizeof(data)", which is now 8.
Wire.write() with 8, and 'howMany' will be 8.

The function "vw_set_ptt_inverted(true)" is not needed, that is only for a few very specific transmitters. You can remove that.

The library VirtualWire sets all three pins (tx, rx, ptt). Even if you don't use them. I suggest to set the unused pins to free pins, which are not connected to something.

Uno #1

const int transmit_pin = 12;
const int vw_receive_pin = 4;  // unused pin, not needed for transmitter
const int vw_ptt_pin = 5; // unused pin, not needed for transmitter
...
vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(vw_receive_pin);
vw_set_ptt_pin(vw_ptt_pin);

Uno #2

const int receive_pin = 3;
const int vw_transmit_pin = 4;  // unused pin, not needed for receiver
const int vw_ptt_pin = 5; // unused pin, not needed for receiver
...
vw_set_rx_pin(receive_pin);
vw_set_tx_pin(vw_transmit_pin);
vw_set_ptt_pin(vw_ptt_pin);

Most of us prefer to use "A0", "A1" and so on for the analog inputs, instead of "0", "1". It doesn't change a thing, but when reading the sketch, it is clear to everyone that it is an analog pin.

Uno #1

const int xPin = A0;
const int yPin = A1;
const int zPin = A2;

There might be small problem with timing and interrupts. I don't know how everything will influence on each other. In Uno #1, the VirtualWire interrupts might influence the ultrasonic distance measurement. In Uno #2 the interrupts from the Wire library will have very little influence on the receiving VirtualWire. In Uno #3 is no timing/delay/interrupt problem.

I done as you said replaced the 6bytes with 8bytes, But still the slave UNO #3 cannot receive the data from UNO #2, I can receive the data with the same sketch but removing the 433Mhz Tx and Rx modules and directly connecting Accelerometer and ultrasonic sensor to any of the UNO and sending it directly using i2c to the another UNO

for better understanding Arduino UNO #1( 433Mhz Transmitter) TO Arduino #2 (Receiver & Master i2c) TOArduino #2 (Receiver & Master i2c) <---- This Method is not working.

Arduino UNO (Accelerometer & Ultrasonicsensor(MASTER)) TO Arduino UNO (SLAVE) <---- This Method is working fine, Like i we did before..

Here is the sketch of master

#include <VirtualWire.h>
#include <Wire.h>


int ledPin = 13;



int x, y, z, distance;
int sensorArray[4] = {};


const int receive_pin = 3;

void setup() {

  pinMode(ledPin, OUTPUT);

  vw_set_rx_pin(receive_pin);

  vw_setup(2000);
  Serial.begin(9600);

  vw_rx_start();

}

void loop() {
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;


  if (vw_get_message(buf, &buflen))
  {
    memcpy(sensorArray, buf, buflen);

    x = sensorArray[0];
    y = sensorArray[1];
    z = sensorArray[2];
    distance = sensorArray[3];



    Serial.print("X: ");
    Serial.print(x);

    Serial.print("  Y: ");
    Serial.print(y);

    Serial.print("  z: ");
    Serial.print(z);

    Serial.print("  Distance: ");
    Serial.print(distance);

    Serial.println();

    int data[4];

    data[0] = x;
    data[1] = y;
    data[2] = z;
    data[3] = distance;


    Wire.beginTransmission(4); // transmit to device #4

    Wire.write ( (byte *) data , 8 ) ;

    Wire.endTransmission();


    delay(100);

  }
}

Here is the Slave

#include <Wire.h>


volatile int data[4];     // received data for x, y, z,Distance.
volatile boolean validData = false; // flag to indicate that something is received.

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output

}

void loop()
{
  // The loop does not contain a delay(), since the 'validData' is checked as many times as possible

  if (validData)
  {
    // It is best to make a copy of the data while interrupts are disabled, but for now they are used directly.
    Serial.print("x=");
    Serial.print(data[0]);
    Serial.print(", y=");
    Serial.print(data[1]);
    Serial.print(", z=");
    Serial.print(data[2]);
    Serial.print(", Distance=");
    Serial.print(data[3]);
    Serial.println();


    // Now that the data is used, reset the flag for new data.
    validData = false;


  }
}



void receiveEvent(int howMany)
{
  // 8 bytes are expected.
  // If not 8 bytes received, then ignore everything.

  if ( howMany == 8)
  {
    // extra safety check. If the flag is clear, fill a new value.
    if ( !validData)
    {
      Wire.readBytes( (byte *) data, 8);
      validData = true;
    }
  }
}

I'm getting confused with three Arduino boards, but I think those sketches should work.

Do you know that you can develop all three Arduino boards at the same time ?
Start the Arduino IDE, select the board and the serial port of Uno #1.
Start the Arduino IDE again, select the board, and the serial port of Uno #2.
Start the Arduino IDE once again for Uno #3.
Then you have three Arduino IDE on your screen, with three open serial monitors if you want. Then you can upload and test something while they are all running at the same time.

Is Uno #2 showing the x, y, z values ? and is Uno #3 also showing those values ?

Perhaps you can add a start message for every Uno, to avoid any confusion. Here is an example for Uno #3.

void setup()
{
  Serial.begin(9600);           // start serial for output
  Serial.println("Uno #3 started");       // added

  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
}

Here is all the Serial monitors at the same time.

COM 3 : UNO #3 the slave i2c receiver from UNO #2

Sorry i typed wrong in the picture

UNO #1,UNO#2 is showing the values but UNO#3 is not.

I don't see the problem, you have do many tests to get more information.
Is the I2C communication still working ? Perhaps a wire is loose ?

As I wrote, let Uno #3 print a start message. Then you know the serial communication is working.

Uno #2 can detect if the Slave is on the I2C bus.

    Wire.beginTransmission(4); // transmit to device #4

    Wire.write ( (byte *) data , 8 ) ;

    int error = Wire.endTransmission();
    Serial.print("endTransmission return value=");
    Serial.println(error);

Or transmit dummy data for Uno #2.

    int dummy[4] = { 100, 110, 120, 130 };
    Wire.write ( (byte *) dummy , 8 ) ;

It is possible to alter a output pin, for example the led from the onReceive handler. That can be done with digitalWrite, but there is also a very short instruction for that : Interrupt / Atomic blocking question - #9 by nickgammon - Programming Questions - Arduino Forum

I2C is working fine,Same connection is working with the first two sketches.

Master

Successfully can transmit the values by below code 'with same I2C physical connections'.

#include <Wire.h>

const int xPin = A0;
const int yPin = A1;
const int zPin = A2;


void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
}




void loop()
{
  int data[3];
  data[0] = analogRead(xPin);
  data[1] = analogRead(yPin);
  data[2] = analogRead(zPin);
  
  Wire.beginTransmission(4); // transmit to device #4


  Wire.write ( (byte *) data , 6 ) ;

  Wire.endTransmission();



  delay(100);
}

Slave

Successfully can receive the values by below code 'with same I2C physical connections'.

// Wire Slave Receiver
#include <Wire.h>

// Variables that are changed in an interrupt routine, should be 'volatile'.
// With 'volatile' the compiler allows that they can suddenly be changed in an interrupt.

volatile int data[3];     // received data for x, y, z.
volatile boolean validData = false; // flag to indicate that something is received.

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

void loop()
{
  // The loop does not contain a delay(), since the 'validData' is checked as many times as possible

  if(validData)
  {
    // It is best to make a copy of the data while interrupts are disabled, but for now they are used directly.
    Serial.print("x=");
    Serial.print(data[0]);
    Serial.print(", y=");
    Serial.print(data[1]);
    Serial.print(", z=");
    Serial.print(data[2]);
    Serial.println();

    // Now that the data is used, reset the flag for new data.
    validData = false;
  }
}


void receiveEvent(int howMany)
{
  // 6 bytes are expected.
  // If not 6 bytes received, then ignore everything.

  if( howMany == 6)
  {
    // extra safety check. If the flag is clear, fill a new value.
    if( !validData)
    {
      Wire.readBytes( (byte *) data, 6);
      validData = true;
    }
  }
}
[\code]

But Here

433Mhz Transmitter code

Successfully can transmit the values wirelessly to the receiver by below code 'with same I2C physical connections'.

#include <VirtualWire.h>

const int transmit_pin = 12;

#define echoPin 7
#define trigPin 8 

const int xPin = A0;
const int yPin = A1;
const int zPin = A2;

int maximumRange = 200;
int minimumRange = 0;

int duration;

int minVal = 265;
int maxVal = 402;


int x;
int y;
int z;
int distance;


void setup() {

 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);

 vw_set_tx_pin(transmit_pin);

 Serial.begin(9600);
 vw_setup(2000);
}

void loop() {


 int xRead = analogRead(xPin);
 int yRead = analogRead(yPin);
 int zRead = analogRead(zPin);

 digitalWrite(trigPin, LOW);
 delayMicroseconds(2);

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10);

 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);

 int xAng = map(xRead, minVal, maxVal, -90, 90);
 int yAng = map(yRead, minVal, maxVal, -90, 90);
 int zAng = map(zRead, minVal, maxVal, -90, 90);


 x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
 y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
 z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);

 distance = duration / 58.2;

 Serial.print("X: ");
 Serial.print(x);

 Serial.print("  Y: ");
 Serial.print(y);

 Serial.print("  Z:");
 Serial.print(z);

 Serial.print("   Distance");
 Serial.println(distance);

 int sensorArray[] = {x, y, z, distance};

 digitalWrite(13, true);
 vw_send((uint8_t *)sensorArray, sizeof(sensorArray));
 vw_wait_tx();
 delay(50);

}

Master

It can receive the values coming wirelessly,I can see that in Serial Monitor by below code 'with same I2C physical connections'.

#include <VirtualWire.h>
#include <Wire.h>


int ledPin = 13;



int x, y, z, distance;
int sensorArray[4] = {};


const int receive_pin = 3;

void setup() {

  pinMode(ledPin, OUTPUT);

  vw_set_rx_pin(receive_pin);

  vw_setup(2000);
  Serial.begin(9600);

  vw_rx_start();

}

void loop() {
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;


  if (vw_get_message(buf, &buflen))
  {
    memcpy(sensorArray, buf, buflen);

    x = sensorArray[0];
    y = sensorArray[1];
    z = sensorArray[2];
    distance = sensorArray[3];



    Serial.print("X: ");
    Serial.print(x);

    Serial.print("  Y: ");
    Serial.print(y);

    Serial.print("  z: ");
    Serial.print(z);

    Serial.print("  Distance: ");
    Serial.print(distance);

    Serial.println();
    int data[4];

    data[0] = x;
    data[1] = y;
    data[2] = z;
    data[3] = distance;



    Wire.beginTransmission(4); // transmit to device #4

    Wire.write ( (byte *) data , 8 ) ;

    Wire.endTransmission();




    delay(100);

  }

}

Slave

It's not receiving the values here by below code 'with same I2C physical connections'.

#include <Wire.h>


volatile int data[4];     // received data for x, y, z,Distance.
volatile boolean 
validData = false; // flag to indicate that something is received.

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output

}

void loop()
{
  // The loop does not contain a delay(), since the 'validData' is checked as many times as possible

  if (validData)
  {

    // It is best to make a copy of the data while interrupts are disabled, but for now they are used directly.
    Serial.print("x=");
    Serial.print(data[0]);
    Serial.print(", y=");
    Serial.print(data[1]);
    Serial.print(", z=");
    Serial.print(data[2]);
    Serial.print(", Distance=");
    Serial.print(data[3]);
    Serial.println();


    // Now that the data is used, reset the flag for new data.
    validData = false;


  }
}



void receiveEvent(int howMany)
{
  // 8 bytes are expected.
  // If not 8 bytes received, then ignore everything.

  if ( howMany == 8)
  {
    // extra safety check. If the flag is clear, fill a new value.
    if ( !validData)
    {
      Wire.readBytes( (byte *) data, 8);
      validData = true;
    }
  }
}

No loose connections,All the connections are fit and fine.
Please have a closer look at these sketches sir, I cannot receive the values at this end.
Thanks

I'm sorry, but I don't see what the problem is. You have to add more Serial.println() and do some tests (for example sending dummy data).

Thanks for the rapid replies sir.
Please can you see my another post on this same issue.? There i clearly written everything in detail.

Thanks.

http://forum.arduino.cc/index.php?topic=326831.new#new