Go Down

Topic: Maintain variable identity between MasterWriter SlaveReceiver? (Read 160 times) previous topic - next topic

Rohla

Hello!

I'm somewhat quite desperate with this project. The deadline is pretty much now so sorry if I'm hasty or unpolite. :,D

So, I want to send multiple strings, integers and floats from an Arduino Uno Master to a nodemcu slave.
The main idea of the project is that the Arduino is going to take input of multiple temperature sensors to control the temperature of an animal physiology experiment. The nodemcdu (ESP8266mod) is going to receive this temperature data from Arduino, log then into google drive and, if some parameters is wrong, send a e-mail to me.

I believe I got almost everything figured out. I know the wiring, how to log the data, how to send an email, how to send convert float to char and back to float, etc.

I have seen multiple tutorials and such (all of them coping from the same example...) and all of then deal with a simpler problem that deals with passing only one or two values with different byte sizes.(Tutorial example)
I need an example code that sends multiple variables. All of them will be less than 8byte in size.

The pseudocode of what I want to do is something as follows:

->>Arduino Master Writer
Code: [Select]

If one minute has passed {
Receive input from 8 sensors
Makes decisions based on said input

Then
Wire.beginTransmission(<adress>);
Wire.write(<date>);        // String (ex. Set22)
Wire.write(<hour>);        //String (ex. 14h33)
Wire.write(<Val sensor 1>);        // float (I have read that it is easier if I convert it to string. Most likelly will do so)
Wire.write(<Val sensor n>);        // float (ex. 23.444)
Wire.write(<Val sensor 8>);        // float (ex. 30.222)
Wire.write(<state of equipment 1>);        //bolean (wheter the equipment is on or off)
Wire.write(<state of equipment n>);        //bolean (wheter the equipment is on or off)
Wire.write(<state of equipment 4>);        //bolean (wheter the equipment is on or off)
Wire.write(<Val light sensor >);        //int  (ex. 50000)
Wire.endTransmission();    // stop transmitting
}


->>Nodemcu SlaveReceiver
Code: [Select]

void setup() {
  Wire.begin(<adress>);                //
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
 
}


void receiveEvent(int howMany) {

char a = Wire.read(<date>);
char b = Wire.read(<hour>);       
float c = Wire.read(<Val sensor 1>);
etc
int n = Wire.read(<Val light sensor >);

upload2Drive(a,b...,n){}
shitHappened(a,b...n){}  //sends email.
}


Can anybody please provide any example of something like that?
I've tried multiple search strings on google and could find nothing!

-Edit-
The main question here, I believe, is how to maintain the identity of each variable among the two boards. The tutorials counts bytes, (e.g., the last byte is another variable), but I needed something that would identify positions (e.g. the first value(<=8bytes) is the first variable, the second (<=8bytes) is the second etc...


Rola

PaulS

Quote
All of them will be less than 8byte in size.
Are you aware that the write() method (that takes one argument) writes ONE byte?

Your code that reads the data written to the I2C pins MUST know the order, and size, of each bit of data. There is nothing that makes that happen for you.
The art of getting good answers lies in asking good questions.

Rohla

Thank you very much for your time and reply!

Quote
Are you aware that the write() method (that takes one argument) writes ONE byte?
I was not aware of that. I think therefore that I must have misunderstood the documentation and tutorial badly!

In the the tutorial, the master apparently sends a string 5 bytes long:
Code: [Select]
void loop() {
  Wire.beginTransmission(8); // transmit to device #8
  Wire.write("x is ");        // sends five bytes
  Wire.write(x);              // sends one byte
  Wire.endTransmission();    // stop transmitting

  x++;
  delay(500);
}

So is this information then sent a character at a time (like "x", " ", "i", "s" and" ")?


Quote
Your code that reads the data written to the I2C pins MUST know the order, and size, of each bit of data. There is nothing that makes that happen for you.
I'm sorry, I do not think I understand.  So given and event of information transmitting,  the values for each variable would mend together and the therefor e I need to provide to receiver the order and sizes of variables so it can "deconstruct" the long melding into the original values?

Thank you very much.

GolamMostafa

@OP

Check and re-check if NodeMCU works as a slave in the I2C Bus with UNO?

If not, use Software UART Communication.

PaulS

The write() method handles strings properly, but the Wire class isn't really intended for sending strings.

Code: [Select]
float pi = 3.14159;
Wire.write(pi);

will NOT send the value of pi as you expect.

Code: [Select]
float pi = 3.14159;
Wire.write(pi, sizeof(float));

Will send all 4 bytes of the value.

Of course, you need to make sure that the receiver expects 4 bytes, and reads all 4 of them and uses all 4 of them in the correct order to reconstruct the float.
The art of getting good answers lies in asking good questions.

GolamMostafa

Quote
Code: [Select]
float pi = 3.14159;
Wire.write(pi, sizeof(float));

Will send all 4 bytes of the value.
Unfortunately, compilation error!

Quote
no matching function for call to 'TwoWire::write(float&, unsigned int)'

PaulS

Quote
Unfortunately, compilation error!
So, fix it.

Code: [Select]
Wire.write(&pi, sizeof(float));
The art of getting good answers lies in asking good questions.

GolamMostafa

Quote
So, fix it.
The fix is:
Code: [Select]
Wire.print(pi);
or
Code: [Select]
union
{
   float pi;
   byte myData[4];
}data;

data.pi = 3.14159;
Wire.write(data.myData, sizeof(data.myData));

PaulS

Quote
The fix is:
Code: [Select]

Wire.print(pi);
Bullshit.

The write() and print() methods do VERY different things.

There is no reason to create a union when the compiler is perfectly capable of treating a float as an array of 4 bytes.
The art of getting good answers lies in asking good questions.

GolamMostafa

Quote
Bullshit.
Contradicts with the practical result.
Screenshot of the Slave in response to Wire.print()


Master-Code
Code: [Select]
#include<Wire.h>
bool flag1 = false;
byte x;

float pi = 3.14159;

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

void loop()
{
  Wire.beginTransmission(0x68);
  Wire.print(pi, 5);
  Wire.endTransmission();
  delay(1000);    //test interval
}


Slave-Code
Code: [Select]
#include<Wire.h>
bool flag1 = false;
char myData[20] = "";

void setup()
{
  Serial.begin(9600);
  Wire.begin(0x68);  ////UNO-Slave Address
  Wire.onReceive(receiveEvent);
}

void loop()
{
  if (flag1 == true)
  {
    Serial.print("Received from MEGA is: ");
    Serial.println(myData);
    flag1 = false;
  }
}

void receiveEvent(int howMany)
{
  for (int i = 0; i < howMany; i++)
  {
    myData[i] = Wire.read(); //read the received byte
  }
  flag1  = true;
}

GolamMostafa

Code: [Select]
Wire.write(&pi, sizeof(float));
Also, compilation error?

Quote
no matching function for call to 'TwoWire::write(float*, unsigned int)'
"Galileo Galilei says that he does not guess; he experiments and then predicts."

PaulS

If you write the receiver to expect a string, then print() can be used to send the value. But, that is NOT the normal way that I2C is used. I2C is used to write values, not strings, to other devices.
The art of getting good answers lies in asking good questions.

GolamMostafa

If you write the receiver to expect a string, then print() can be used to send the value. But, that is NOT the normal way that I2C is used. I2C is used to write values, not strings, to other devices.
It is not forbidden; it is legal.

Go Up