i2C issue (Master receiver/ Slave sender): send measurement values as byte array

Hello everyone,

it's my first time dealing with serial communication and I am currently stuck understanding/ dealing with sending/reading/converting integers and arrays that I'm hoping someone has a solution for. Sorry in advance for these rather bad coding approaches and my bloody beginner questions.

The idea is to let the slave read data from a sensor (3 digit numbers), store them into arrays and send it to the Master (Mega), as requested. I was thinking about sending the "incoming" values as binary data, but I have no clue how to implement that into the below written "framework" I built. I have read to heaps of posts and tried using the named approaches but nothing really worked.
Also, I do not use any pull up/ down resistors, if this could be an issue.

The below described solution does not yet use the approach of storing the values as array, but I thought someone could help me to understand whit this given in and output, what is actually happening.
Requesting 6 bits, the Master Arduino returns a loop of "0 255 255 255 255 255" on it's serial monitor. What does this say?

Master Code:

#include <Wire.h> 
char c[10]={};           //empty array where to put the numbers comming from the slave


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

void loop() {


  Wire.requestFrom(8, 6); 
    
     while (Wire.available()) {
     c = Wire.read();   
     Serial.println(c);  
  }

}

Slave Code:

#include <Wire.h> 

char c[10]; 


void setup() {
  Wire.begin(8); 
  Wire.onRequest(requestEvent);

  Serial.begin(9600);                  // to validate the output returned by the master
  pinMode(13, OUTPUT);         
}

void loop() {
  int light = analogRead(0); 
  Serial.println(light); 

  if (light < 150) {    // this remaining code within the loop triggers the LED within the circuit
    digitalWrite(13, HIGH);    
   }
  else {
    digitalWrite(13, LOW);     
  }
}

void requestEvent() {    
 Wire.write(light); 

}

I then used the following approach (it is full of bugs I guess and has nothing to do yet with storing the data in arrays)

...in the slave code with:

#include <Wire.h> 

...

void requestEvent() {  
 byte light[6];  
 Wire.write((byte*)&light,sizeof 6); // send response of 4 bits back to master
}

...and in the master code with:

#include <Wire.h>
int response;

... 

void loop() {
  Wire.requestFrom(8, 6);    
  while (Wire.available()) {
  int c = Wire.readBytes((byte*)response, 6); // store bytes as int    
  Serial.println(c));
  }
}

In this case, I only get "5⸮" as output on the serial master monitor once.

Any help is highly appreciated!!

I wrote this a week ago, can you have a look at it ?
How to make a reliable I2C bus · Koepel/How-to-use-the-Arduino-Wire-library Wiki · GitHub.

Have you seen this tutorial by Robin2: Use I2C for communication between Arduinos - Exhibition / Gallery - Arduino Forum.

Is the Master always the Master ? So the Master requests data now and then from the Slave ? The Slave only has to deal with the onRequest handler ?

The integer array needs to be global in the Slave (above the setup function).
It can be handy to have the same name in the Master and the Slave.
The number of bytes is sizeof(sensorData). With 6 elements, the size will be 12.
The name of an array is already a pointer.
It is better to turn off the interrupts when the array is filled in the loop(), but that is often omitted.

Slave

int sensorData[6];

void setup()
{
  ...
}

void loop()
{
  int rawADC = analogRead( A0);

  noInterrupts();
  sensorData[0] = rawADC;
  interrupts();
}

void requestEvent()
{  
 Wire.write( (byte*) sensorData, sizeof( sensorData));
}

Master

int sensorData[6];

void setup()
{
  ...
}

void loop()
{
  ...
  Wire.requestFrom( 8, sizeof( sensorData));
  if( Wire.available() == sizeof( sensorData))    // received the number of bytes that was requested ?
  {
    Wire.readBytes( (byte *) sensorData, sizeof( sensorData));
  }
  ...
}

Those 255 numbers is when the Slave is doing nothing. Suppose the Slave sends one byte, and the Master requests 6 bytes. Then the Slave sends that one byte and after that the Slave does not use the SDA signal anymore. The SDA will stay high and the Master thinks that it reads all 1's. That makes 255. When the Slave is not connected, then the Wire.read() returns -1, and that converted to a byte will be 255 as well.

You were going in the right direction. So I think it is about time that you show working sketches for the Master and the Slave :sunglasses:

I have to admit that I've not tried this, but glancing the documentation and from previous experience with other platforms, I guess you would implement an I2C slave something like this.

#include <Wire.h>

#define DEVICE_ADDRESS 0x50

static uint8_t memory[256];
static uint8_t memoryPointer = 0;

static void onRequestHandler() {
  
  // This function is called for every byte requested by the master.
  // The memory pointer is manipulated by the master using writes
  // so we'll just send the byte in the currently addressed memory.
  Wire.write(memory[memoryPointer++]);
}

static void onReceiveHandler(int numBytes) {

  // This function is called after the stop/restart condition has occured.
  // We treat the first received byte differently to allow the master to manipulate
  // the memorypointer.
  uint8_t memoryAddress = 1;
  
  while (Wire.available()) {
    if (memoryAddress) {
      memoryPointer = Wire.read();
      memoryAddress = 0;
      
      continue;
    }

    // Read in any data bytes to the currently addressed memory.
    memory[memoryPointer++] = Wire.read();
  }
}

void setup() {
  Wire.begin(DEVICE_ADDRESS);
  Wire.onReceive(onReceiveHandler);
  Wire.onRequest(onRequestHandler);
}

void loop() {
  
}

What I've written here is an attempt to implement an emulated EEPROM. I don't know if you are familiar with how an EEPROM interface works?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.