Sending Array to master arduino (i2c wire connection)

Hi to everyone
i would like your help, if what i want to do can be done.

General description :
i have 2 Arduinos (pro mini) that i have configured them as a pair via i2c connection, One to be the master and the other the slave

what i would like to do is to use the slave to read 3 sensors and store the values in arrays and send them to master

char *myStrings[] = {"Full", "Half", "RES", "EMPTY" };
int j = 0;

char *myStrings4[] = {"100", "90", "80", "70", "60", "50", "40", "30", "20",
                                  "10", "5", "0" };
int k = 0;

char *myStrings2[] = {"LOW", "0", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5"};
int m = 0;


// example for *myStrings[] 


  Watervalue = analogRead(potentiometer);
  Watervalue = map(Watervalue, 0, 1023, 0, 255);
  
if (Watervalue <= 1) {
    j = 1;
  }
  else if (Watervalue >= 10 && Watervalue < 100 ) {
    j = 2;
  }
  else if (Watervalue >= 100 && Watervalue < 200 ) {
  j = 3;
   
//etc....

  }


// sending data *myStrings  via wire i2c 

Wire.write(myStrings[j]);

i am able to send and read in master one array of them but i am not sure if it is possible to send three of them with that method.

or is any other more appropriate method to achieve what i want to do and i missing it ? (i am a self-taught in coding so i am sure that most probably there are other ways and don’t know them for the moment)

thanks in advance

It is often handy to let the Slave send raw values and do the calculation in the Master. This is not always possible, but if it is only the three sensors, then you can store it in a integer array.
We don't send strings via I2C, we use binary data. That means you can send a integer array, a total of 6 bytes.

Please show the full Master and Slave sketch.

Did you connect the GNDs as well ? What are your pullup resistors ?

Do you really need two Arduino boards ? Can you do it with just one Arduino board ?
One Arduino board means no I2C Slave, which has many things that can go wrong, and one sketch to maintain. That would be so much easier.

Look at the master/slave example that is part of the Wire library. Your slave never sends data to the master. The master has to request it and then the slave responds to that request.

It would also be a much better idea to send a fixed response rather than some variable length string. The slave should just respond with the analog value (or the mapped value, 0-255) and let the master do the interpretation.

Koepel:
It is often handy to let the Slave send raw values and do the calculation in the Master. This is not always possible, but if it is only the three sensors, then you can store it in a integer array.
We don't send strings via I2C, we use binary data. That means you can send a integer array, a total of 6 bytes.

ok i will check more about that...

Koepel:
Please show the full Master and Slave sketch.

it is not the code i am going to use for my project... just experimenting with the code to see if what i want to do can be done before invest and write all the code for my project

Koepel:
Did you connect the GNDs as well ? What are your pullup resistors ?

Yes they have common Gnd... i dont have problem with the connection.. i can read and send data between them...

Koepel:
Do you really need two Arduino boards ? Can you do it with just one Arduino board ?
One Arduino board means no I2C Slave, which has many things that can go wrong, and one sketch to maintain. That would be so much easier.

my original plan/code was to use just one arduino pro mini but as i am getting warnings

Global variables use 1645 bytes (80%) of dynamic memory, leaving 403 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

and still had more code to add i decide to brake my project to two arduinos to share the load of the variables of the sensors (i cant use arduino mega for this project)

blh64:
Look at the master/slave example that is part of the Wire library. Your slave never sends data to the master. The master has to request it and then the slave responds to that request.

master can send and receive from a slave... and the same can be done with the slave after master reguest.
i have done that all ready in my experiment code in order to see how to send my data

the master send an order to the slave to start reading the sensor values... and then request to send back the sensor readings (data).
so the slave receives data in order to start reading sensors and store values and after that send the store values to the master

blh64:
It would also be a much better idea to send a fixed response rather than some variable length string. The slave should just respond with the analog value (or the mapped value, 0-255) and let the master do the interpretation.

my problem is how to send 3 individual sensors readings after the calculation to the master

And here is my test code that i am using for the moment to experiment

Code for the master Arduino (sending and receiving data)

// Wire Master Reader sender
// based in the arduino ide examble with some additions by me
//  caslor 03/05/2020

#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 8

// Define Slave answer size
#define ANSWERSIZE 6
const byte button = 4; // pin to read button
char t[10] = {};

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  pinMode(button, INPUT_PULLUP);
}

void loop() {

  if (digitalRead(button) == LOW  ) {
    Command2Slave() ;
  }
  else if (digitalRead(button) == HIGH ) {
    Serial.println("Stand By mode");
  }


  delay(500);
}
void Command2Slave()  {

  Wire.beginTransmission(SLAVE_ADDR);

  Wire.write('U');

  Wire.endTransmission();

  delay(500);

  ReceiveSlave() ;

}


void ReceiveSlave()  {
  Wire.requestFrom(SLAVE_ADDR, ANSWERSIZE);
  int i = 0; //counter for each bite as it arrives
  while (Wire.available()) {
    t[i] = Wire.read(); // every character that arrives it put in order in the empty array "t"
    i = i + 1;
  }
  Serial.println(t);   //shows the data in the array t
  delay(500);
}


/*
  void ReceiveSlave()  {
  Wire.requestFrom(SLAVE_ADDR, ANSWERSIZE);
  while (Wire.available()) { // slave may send less than requested
   char c = Wire.read(); // receive a byte as character
   Serial.print(c);         // print the character
  }
   delay(500);
  }
*/

Code for the Slave Arduino (sending and receiving data)

// Wire Slave Reader sender
// based in the arduino ide examble with some additions by me
//  caslor 03/05/2020

#include <Wire.h>
#define SLAVE_ADDR 8
#define ANSWERSIZE 6

const byte potentiometer1 = A0;
const byte potentiometer2 = A2;
const byte potentiometer3 = A3;
const byte testbutton = 4;

int Watervalue1;
int Watervalue2;
int Watervalue3;

char *myStrings1[] = {"Full", "Half", "RES", "EMPTY" };
int j = 0;

char *myStrings2[] = {"100", "90", "80", "70", "60", "50", "40", "30", "20",
                      "10", "5", "0"
                     };
int k = 0;

char *myStrings3[] = {"LOW", "0", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5"};
int m = 0;

char *myStrings4[2];


void setup() {
  pinMode(testbutton, INPUT_PULLUP);

  
  Wire.begin(SLAVE_ADDR);
  // Function to run when data requested from master
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);
}

void loop() {

  //  Serial.println(Windvalue);

  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {

  // as expected by master
  Wire.write(myStrings1[j]);
  // Wire.write(myStrings2[k]);
  // Wire.write(myStrings3[m]);
  // Wire.write(myStrings4[0]);

}

void receiveEvent(int howMany)
{
  if (Wire.available())
  {
    char c = Wire.read();

    if (c == 'U')
    {
      SensorsRead1() ;
      SensorsRead2() ;
      SensorsRead3() ;
      ButtonState() ;

    }
  }

}
void SensorsRead1() {
  Watervalue1 = analogRead(potentiometer1);
  Watervalue1 = map(Watervalue1, 0, 1023, 0, 255);
 
  if (Watervalue1 <= 1) {
    j = 1;

  }
  else if (Watervalue1 >= 10 && Watervalue1 < 100 ) {
    j = 2;
  }
  else if (Watervalue1 >= 100 && Watervalue1 < 200 ) {
    j = 3;

  }


}

void SensorsRead2() {
  Watervalue2 = analogRead(potentiometer2);
  Watervalue2 = map(Watervalue2, 0, 1023, 0, 255);
 
  if (Watervalue2 <= 1) {
    k = 1;

  }
  else if (Watervalue2 >= 10 && Watervalue2 < 100 ) {
    k = 2;
  }
  else if (Watervalue2 >= 100 && Watervalue2 < 200 ) {
    k = 3;
  }


}
void SensorsRead3() {
  Watervalue3 = analogRead(potentiometer3);
  Watervalue3 = map(Watervalue3, 0, 1023, 0, 255);
  
  if (Watervalue3 <= 1) {
    m = 1;

  }
  else if (Watervalue3 >= 10 && Watervalue3 < 100 ) {
    m = 2;
  }
  else if (Watervalue3 >= 100 && Watervalue3 < 200 ) {
    m = 3;
  }


}
void ButtonState() {
  if (digitalRead(testbutton) == LOW) {
    myStrings4[0] = " Low " ;

  }
  else if (digitalRead(testbutton) == HIGH) {
    myStrings4[0] = " High" ;

  }
}
void loop() {

  //  Serial.println(Windvalue);

  delay(100);
}

Are you being billed for each iteration of loop()?

Why doesn't the master convert the values in j, k, and m to strings? It would a LOT simpler to send 3 bytes than to send three strings.

Actually, you are sending three values that are in the range 1 to 3. If you changed the range to 0 to 2, each value is 2 bits, and you could put all 6 bits in one byte, which is trivial to return.

This is what decoding it on the master would look like
slave code

// Wire Slave Reader sender
// based in the arduino ide examble with some additions by me
//  caslor 03/05/2020

#include <Wire.h>
const int SLAVE_ADDR = 8;

const byte potentiometer1 = A0;
const byte potentiometer2 = A2;
const byte potentiometer3 = A3;
const byte testbutton = 4;

struct {
  uint8_t w1;
  uint8_t w2;
  uint8_t w3;
  uint8_t b1;
} response;

void setup() {
  pinMode(testbutton, INPUT_PULLUP);
  Wire.begin(SLAVE_ADDR);
  // Function to run when data requested from master
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);
  SensorsRead();
}

void loop() {
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {

  // as expected by master
  Wire.write(response.w1);
  Wire.write(response.w2);
  Wire.write(response.w3);
  Wire.write(response.b1);
}

void receiveEvent(int howMany) {
  if (Wire.available()) {
    char c = Wire.read();
    if (c == 'U') {
      SensorsRead();
    }
  }
}

void SensorsRead() {
  int value;

  value = analogRead(potentiometer1);
  response.w1 = map(value, 0, 1023, 0, 255);
  value = analogRead(potentiometer2);
  response.w2 = map(value, 0, 1023, 0, 255);
  value = analogRead(potentiometer3);
  response.w3 = map(value, 0, 1023, 0, 255);
  response.b1 = digitalRead(testbutton);
}

Master

// master

#include <Wire.h>

// Define Slave I2C Address
const int SLAVE_ADDR = 8;

const byte button = 4; // pin to read button

int lastButtonState;

struct {
  uint8_t w1;
  uint8_t w2;
  uint8_t w3;
  uint8_t b1;
} response;

// Define Slave answer size
const int ANSWERSIZE = sizeof(response);

void setup2() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  pinMode(button, INPUT_PULLUP);
  lastButtonState = digitalRead(button);
}

void loop2() {

  int buttonState = digitalRead(button);

  if ( buttonState != lastButtonState ) {
    // we have a transistion
    if (buttonState == LOW  ) {
      Command2Slave();
      delay(500);
      ReceiveSlave();
      Decode();
    }
    else {
      Serial.println("Stand By mode");
    }
    delay(50);
  }
  lastButtonState = buttonState;
}

void Command2Slave()  {
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write('U');
  Wire.endTransmission();
}


void ReceiveSlave()  {
  Wire.requestFrom(SLAVE_ADDR, ANSWERSIZE);
  response.w1 = Wire.read();
  response.w2 = Wire.read();
  response.w3 = Wire.read();
  response.b1 = Wire.read();
}

void Decode() {
  decodeSensor( "W1", response.w1);
  decodeSensor( "W2", response.w2);
  decodeSensor( "W3", response.w3);
  Serial.print( "Button is " );
  if ( response.b1 == HIGH ) {
    Serial.println( " HIGH " );
  }
  else {
    Serial.println( " LOW " );
  }
}

void decodeSensor( const char *msg, uint8_t val ) {
  Serial.print( msg );
  Serial.print( " is " );
  if (val <= 1) {
    Serial.println( "Full" );
  }
  else if (val >= 10 && val < 100 ) {
    Serial.println( "Half" );
  }
  else if (val >= 100 && val < 200 ) {
    Serial.println( "RES" );
  }
  else {
    Serial.println( "EMPTY" );
  }
}

PaulS:
.

Thank you

[/quote]

blh64:
This is what decoding it on the master would look like

Wow !!! that was much more that was expecting for a help !!

that changed my project planning .. i will use the suggested code to move all my sensors to the second slave Arduino

Thanks !!