Send INT over I2C

Hey! I need to send values ​​collected from a sensor between 0 and 100000 by I2C between two arduinos. Can anybody help me? Tnks =)

Master Code:


#include <I2S.h>
#include <Wire.h>

void setup() {
  // Open serial communications and wait for port to open:
  // A baud rate of 115200 is used instead of 9600 for a faster data rate
  // on non-native USB ports
  SerialUSB.begin(115200);
  Wire.begin(); // join i2c bus (address optional for master)
  while (!SerialUSB) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start I2S at 16 kHz with 32-bits per sample
  if (!I2S.begin(I2S_PHILIPS_MODE, 16000, 32)) {
    //SerialUSB.println("Failed to initialize I2S!");
    while (1); // do nothing
  }

}

#define SAMPLES 128 // make it a power of two for best DMA performance

//byte x = 0;
int valorFinal;


void loop() {
  // read a bunch of samples:
  int samples[SAMPLES];

  for (int i=0; i<SAMPLES; i++) {
    int sample = 0; 
    while ((sample == 0) || (sample == -1) ) {
      sample = I2S.read();
    }
    // convert to 18 bit signed
    sample >>= 14; 
    samples[i] = sample;
  }

  // ok we hvae the samples, get the mean (avg)
  float meanval = 0;
  for (int i=0; i<SAMPLES; i++) {
    meanval += samples[i];
  }
  meanval /= SAMPLES;
  //Serial.print("# average: " ); Serial.println(meanval);

  // subtract it from all sapmles to get a 'normalized' output
  for (int i=0; i<SAMPLES; i++) {
    samples[i] -= meanval;
    //Serial.println(samples[i]);
  }

  // find the 'peak to peak' max
  float maxsample, minsample;
  minsample = 100000;
  maxsample = -100000;
  for (int i=0; i<SAMPLES; i++) {
    minsample = min(minsample, samples[i]);
    maxsample = max(maxsample, samples[i]);
  }
  //SerialUSB.println(maxsample - minsample);
  valorFinal = maxsample - minsample;
  x = (int)valorFinal;
  SerialUSB.println(valorFinal);
  Wire.beginTransmission(8); // transmit to device #4
  Wire.write(valorFinal);              // sends one byte  
  Wire.endTransmission();    // stop transmitting
  
  //delay(500);
}

Slave Code:

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

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

void loop() {
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
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
} 

may this article might help you ;)!

1 Like

Hi, please explain.

Why do you need to send data to a other Arduino board ? Can you do your project with a single Arduino board ? The I2C bus is a bad idea to communicate between Arduino boards.
How much data do you want to transfer ? The I2C bus is for maybe a few hundred bytes per second.

Which Arduino boards do you have ?
The I2C bus uses a number of bytes. The "Wire.write(valorFinal)" send a byte with a value of 0...255.
The explanation in the link given by sherzaad explains how to send more, but it is often easier to transfer a struct or an array and use pointers to them.

Do you know if your board supports the Slave mode ? Are there examples of working projects with that board in Slave mode ?
I know the Slave code is from the official example, but it is bad code. For example the "loop through all but the last" is confusing. What is wrong with the last byte ? If something is wrong with the last byte, then why would it be send over I2C ?

1 Like

That's more than an int's worth on an AVR.

I need to send this data to another board because I send this data to a mobile application, via bluetooth. This sensor uses the unique RX/TX ports. I need to transfer data between 0-60,000. I'm working with a samd21 mini and a mega2560. I need to send this data in real time to the mega2560.

I tried using these codes, but the results take a while to arrive on the other card, even without the delays.

Sparkfun SAMD21 Mini: https://www.sparkfun.com/products/13664
The SAMD21G is also used on a Arduino MKR Zero board. That is a 3.3V chip with a 3.3V I2C bus.
The Arduino Mega board is a 5V board with a 5V I2C bus. It is also the only board with 10k pullup resistors to 5V on the board.

You should not connect those I2C buses.

1 Like

As I2C is a byte oriented protocol, I would suggest to break the long number (for example: 100000) into bytes using union structure. For example:

union myTag
  {
    long y;
    byte myBytes[4];    //(edit)
  };

  myTag myData;
  myData.y = 100000;  //0x0186A0
  Wire.beginTransmission(8);
  Wire.write(myData.myBytes, sizeof myData.myBytes);
  Wire.endTransmission();

Besides the undefined behavior caused by using a union this way (it's been discussed here many times), this also demonstrates another reason for not doing this. A 'long' is 4 bytes.
Just use:

Wire.write(reinterpret_cast<uint8_t *>(&var), sizeof(var));

Even with setting ALL for "Compiler warnings:", there is no warning?

Though I am aware about type punning matter, yet I have to post union method as it works well for some people.

Why not do it properly, and it will work well for all people?

This one @gfvalvo?
1.

long var = 100000;
Wire.beginTransmission(8);
Wire.write(reinterpret_cast<uint8_t *>(&var), sizeof(var));
Wire.endTransmission();

or

This one?
2.

  long y2 = 100000;
  byte *ptr;
  ptr = (byte*)&y2;
  Wire.beginTransmission(8);
  for(int i = 0; i<sizeof y2; i++)
  {
    Wire.write(*ptr);
    ptr++;
  }
  Wire.endTransmission():
}

3. What is "reinterpret_cast"?
4. Does the pointer inside write() method of Step-1 undergo auto incrementing?

https://en.cppreference.com/w/cpp/language/reinterpret_cast

Happy to help.

(I also agree that using "union" to sneakily cast a long into a byte[3] is just nasty, results in code that is intransparent, and the idea of using a byte[3] in the first place is already a great way to make your code just a little bit more chaotic for pretty much no gain, unless your I2C line is at its capacity limit. Just don't do it.)

Where is the help -- put something in your own language so that we can enjoy a new presentation?

Here's a less pedantic reference: https://www.geeksforgeeks.org/reinterpret_cast-in-c-type-casting-operators/

1 Like

Hey, you asked and I answered.

If you asked that question as an attempt to sneakily imply that gfvalvo doesn't know how reinterpret_cast works, then I apologize for misreading your post and would recommend that you try using regular sentences instead of questions in the future.

They're equivalent. See the function source code in Wire.cpp. Using #1 makes your code less cluttered.

See answer above.

1 Like

You did not answer; rather, you had referred to a bureaucratic page?

bureaucratic
(adjective)
relating to a system of government in which most of the important decisions are taken by state officials rather than by elected representatives.