Serial Send and Receive Multiple Variable Data from Nano to Mega

Hi for All, I'm just done with the send data, and I'm trying to receive the data, but the received data can't stable, just stable in 5 time receive, but the sixth is messy. Please I need help

This is my Sender Code

#include <SoftwareSerial.h>
#include <PZEM004Tv30.h>

float v8,c8,pw8,e8,f8,pf8,v9,c9,pw9,e9,f9,pf9;

//float v8 = 220.42;
//float c8 = 100.00;
//float pw8 = 9999.40;
//float e8 = 9999.99;
//float f8 = 50.00;
//float pf8 = 1.00;

char volt8[6];
char curr8[6];
char powe8[7];
char ener8[7];
char freq8[5];
char pof8[4];

SoftwareSerial S1(A4,A5);
PZEM004Tv30 p8(A1,A0);
PZEM004Tv30 p9(A2,A3);

void setup(){
  Serial.begin(115200);
  S1.begin(115200);
}

void loop(){
  PZ8();
  PZ9();
  delay(5000);
  kirimV();
  delay(50);
  kirimC();
  delay(50);
  kirimP();
  delay(50);
  kirimE();
  delay(50);
  kirimF();
  delay(50);
  kirimPf();
  delay(5000);
}

void kirimV(){
  dtostrf(v8,7,7,volt8);
  S1.write(volt8,6);
}

void kirimC() {
  dtostrf(c8,7,7,curr8);
  S1.write(curr8,6);
}

void kirimP() {
  dtostrf(pw8,8,8,powe8);
  S1.write(powe8,7);
}

void kirimE() {
  dtostrf(e8,8,8,ener8);
  S1.write(ener8,7);
}

void kirimF() {
  dtostrf(f8,6,6,freq8);
  S1.write(freq8,5);
}

void kirimPf() {
  dtostrf(pf8,5,5,pof8);
  S1.write(pof8,4);
}

void PZ8(){
    v8=p8.voltage();c8=p8.current();pw8=p8.power();e8=p8.energy();f8=p8.frequency();pf8=p8.pf();
    if(!isnan(v8)){
        Serial.print(v8);
    }else{
      err();
    }
}

void PZ9(){
    v9=p9.voltage();c9=p9.current();pw9=p9.power();e9=p9.energy();f9=p9.frequency();pf9=p9.pf();
    if(!isnan(v9)){
        Serial.print(v9);
    }else{
      err();
    }
}

void err(){
  Serial.print("Err");
}

And this is my receiver code

char v8[7];
char c8[7];
char pw8[8];
char e8[8];
char f8[6];
char pf8[5];

void baca(){
  if (Serial1.available()>0) {
    Serial1.readBytesUntil('\n',v8,6);
    Serial.println(v8);
    delay(100);
    Serial1.readBytesUntil('\n',c8,6);
    Serial.println(c8);
    delay(100);
    Serial1.readBytesUntil('\n',pw8,7);
    Serial.println(pw8);
    delay(100);
    Serial1.readBytesUntil('\n',e8,7);
    Serial.println(e8);
    delay(100);
    Serial1.readBytesUntil('\n',f8,5);
    Serial.println(f8);
    delay(100);
    Serial1.readBytesUntil('\n',pf8,4);
    Serial.println(pf8);
    Serial.println();
  }
}

Result Example
ask

Thanks in advance

I suggest that you take a look at Serial input basics - updated

1 Like

there are several issues

in your received code you wait until something is available before calling readByteUntil(), but call readBytesUntil() multiple times even though something may not be available. readBytesUntil() will time out.

presumably you intend to send a sequence of strings containing values, but there's no way to determine when the sequence begins.

sending all the values as a single string, comma separated and with a single \n terminator would be easier and more reliable. strtok() can be used to separate the values using the comma as a delimiter. the received string should be sufficiently long (~100).

i'm sure about the behavior of readBytesUntil() because of it's timeout. it is probably more reliable if a complete string is sent and buffered so that readBytesUntil() sees a steady stream of bytes and doesn't have an opportunity to time-out.

the transmitter could easily construct a single string to output from an array of values, separating each with a comma. there can be multiple output functions called to construct a single string and terminated by the \n

1 Like

Yeah well done gcjr, Thanks, I convert the data to string with separated comma to parsing then, but some data is missing in the receiver. Any solution?

I'm using Serial1.readStringUntil("\n") to receive the data btw

Like this

void reads8() {
  if (Serial1.available()) {
    s8 = Serial1.readStringUntil("\n");
    Serial.println(s8);
  }
}

The data from sender
234.50,0.00,0.00,0.00,50.00,0.00,234.30,0.00,0.00,0.00,50.00,0.00

The received data
234.20,0.00,0.00,0.00,50.00,0.00,234.00,0.00,0.00,0.00,50.00,0.

looks like a RX buffer overflow at ~64 bytes
try reducing the baudrate from 115200 to 9600 and see if that works.
Or send as two strings each less the 64 bytes
My SerialComs class synchronizes send/receive so you don't over run the RX buffer
see the tutorial How to send text between Arduino boards via Serial

1 Like

Reduce the baudrate is still not working, maybe because of over at 64 bytes. But I still confuse with the serial handshake communication if send as two strings. Maybe any code that can inspire me about that?

If you send as 2 strings then add an identifier string as the first data item so that you can parse it and determine which set of data is being received

1 Like

I have just updated Arduino to Arduino via Serial to include example CSV transfer sketches as well as example sketches using SerialComs and details on fault finding.
Try 300 baud and also add a loopTimer to see how slow your receive loop is running.
There is also the possibility of increasing the RX buffer in the Mega, but that requires changing the package code for that board.
But suggest you clarify why your receive loop is not processing the serial input quickly enough first.

1 Like

Have you revised the sender program?
Please post the latest.

1 Like

The latest sender code, the problem is while send the second data (sends9) function, some data is missing

SoftwareSerial S1(A4,A5);
PZEM004Tv30 p8(A1,A0);
PZEM004Tv30 p9(A2,A3);

void setup(){
  Serial.begin(115200);
  S1.begin(115200);
}

void loop(){
  PZ8();
  PZ9();
  sends8();
  sends9();
  delay(10000);
}

void sends8(){
  s8 = s8 + v8 + ',' + c8 + ',' + pw8 + ',' + e8 + ',' + f8 + ',' + pf8 + '\n';
  Serial.println(s8);
  S1.println(s8);
  s8 = "";
}

void sends9(){
  s9 = s9 + v9 + ',' + c9 + ',' + pw9 + ',' + e9 + ',' + f9 + ',' + pf9 + '\n';
  Serial.println(s9);
  S1.println(s9);
  s9 = "";
}

And sometimes the data is collision between sends8() and sends9(), maybe because the loop time

[ UPDATE ]

Yeay I have done with the first send data include receive and parsing the sends8(). but the second data sends9(), when I try to send after sends8() in the receiver happen a collision even though the delimiter is different between them. Any solution?

Sender code

SoftwareSerial S1(A4,A5);
PZEM004Tv30 p8(A1,A0);
PZEM004Tv30 p9(A2,A3);

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

void loop(){
  PZ8();
  PZ9();
  sends8();
//  sends9();
  delay(10000);
}

void sends8(){
  s8 = s8 + '*' + v8 + ' ' + c8 + ' ' + pw8 + ' ' + e8 + ' ' + f8 + ' ' + pf8 + '\n';
  Serial.println(s8);
  S1.println(s8);
  s8 = "";
}

void sends9(){
  s9 = s9 + '#' + v9 + ' ' + c9 + ' ' + pw9 + ' ' + e9 + ' ' + f9 + ' ' + pf9 + '\n';
  Serial.println(s9);
  S1.println(s9);
  s9 = "";
}

Receiver Code

void loop() {
  statusFotoCell = digitalRead(fotocell);
  if (statusFotoCell == 0) {
    Serial.println(statusFotoCell);
    reads8();
//    reads9();
    PZ7();
    PZ1();
    PZ2();
    PZ3();
    PZ4();
    PZ5();
    PZ6();
    Serial.println();
//    Data();
    delay(59999);
  } else {
    Serial.println(statusFotoCell);
    reads8();
    PZ7();
    PZ1();
    PZ2();
    PZ3();
    PZ4();
    PZ5();
    PZ6();
//    reads9();
    Serial.println();
//    Data();
    delay(10000);
  }  
}

void reads8() {
  if (Serial1.available()) {
    char c = Serial1.read();
    s8 = Serial1.readStringUntil("\n");

    if (c == '*') {
      Serial.print("Captured String : ");
      Serial.println(s8);

      ind1 = s8.indexOf(' ');
      v8 = s8.substring(0, ind1);
      ind2 = s8.indexOf(' ', ind1+1);
      c8 = s8.substring(ind1+1, ind2+1);
      ind3 = s8.indexOf(' ', ind2+1);
      pw8 = s8.substring(ind2+1, ind3+1);
      ind4 = s8.indexOf(' ', ind3+1);
      e8 = s8.substring(ind3+1, ind4+1);
      ind5 = s8.indexOf(' ', ind4+1);
      f8 = s8.substring(ind4+1, ind5+1);
      ind6 = s8.indexOf(' ', ind5+1);
      pf8 = s8.substring(ind5+1);

      Serial.println(v8);
      Serial.println(c8);
      Serial.println(pw8);
      Serial.println(e8);
      Serial.println(f8);
      Serial.println(pf8);

      s8 = "";
      v8 = "";
      c8 = "";
      pw8 = "";
      e8 = "";
      f8 = "";
      pf8 = "";
    } else {
      s8 += c;
    }
  }
}

void reads9() {
  if (Serial1.available()) {
    char a = Serial1.read();
    s9 = Serial1.readStringUntil("\n");

    if (a == '#') {
      Serial.print("Captured String : ");
      Serial.println(s9);

      ins1 = s9.indexOf(' ');
      v9 = s9.substring(0, ins1);
      ins2 = s9.indexOf(' ', ins1+1);
      c9 = s9.substring(ins1+1, ins2+1);
      ins3 = s9.indexOf(' ', ins2+1);
      pw9 = s9.substring(ins2+1, ins3+1);
      ins4 = s9.indexOf(' ', ins3+1);
      e9 = s9.substring(ins3+1, ins4+1);
      ins5 = s9.indexOf(' ', ins4+1);
      f9 = s9.substring(ins4+1, ins5+1);
      ins6 = s9.indexOf(' ', ins5+1);
      pf9 = s9.substring(ins5+1);

      Serial.println(v9);
      Serial.println(c9);
      Serial.println(pw9);
      Serial.println(e9);
      Serial.println(f9);
      Serial.println(pf9);

      s9 = "";
      v9 = "";
      c9 = "";
      pw9 = "";
      e9 = "";
      f9 = "";
      pf9 = "";
    } else {
      s9 += a;
    }
  }
}

The " \n" is not a single char terminator. Using it as a terminator will cause the readStringUntil() to end by timeout and will slow things down.

Try these two sketches (the sender is using RX pin 8 and TX pin 9)
PowerSenderUno.ino (1.4 KB)
PowerReceiverMega2560.ino (3.6 KB)

The receiver loop code is just

void loop() {
  //  statusFotoCell = digitalRead(fotocell);
  //  if (statusFotoCell == 0) {
  //    Serial.println(statusFotoCell);
  //  }

  if (sfInput.readUntil(Serial1, '\n')) {
    // returns true if found \n OR reached sfInput limit
    // if \n found it is returned.
    Serial.print("sfInput: "); Serial.print(sfInput);
    if (decodeCSV(sfInput)) {
      // got new valid inputs update
    } else {
      // error in CSV
    }
    sfInput.clear(); // for next line
  }
}

It uses the SafeString non-blocking replacement for String readUntil

Output (note the output is stored in floats converted from the text received)

Receiver started
sfInput: *,250.00,15.50,3800.50,3500.70,50.50,0.78
250.00
15.50
3800.50
3500.70
50.50
0.78
sfInput: #,255.00,10.50,2800.50,300.70,51.50,0.88
255.00
10.50
2800.50
300.70
51.50
0.88

If you want to have long delays in the receiver then you need to use my SerialComs code which will force the sender to wait until the receiver is ready.

1 Like

Yeayy well done my brothers, all of you safe my final year project. Can I still ask maybe it's last question in this forum hehe.

    PZ7();
    PZ1();
    PZ2();
    PZ3();
    PZ4();
    PZ5();
    PZ6();
    Serial.println();
    Data();

Where can I put this code so it doesn't send the data to the database twice?.
Because if I put here

void loop() {
  if (sfInput.readUntil(Serial1, '\n')) {
    // returns true if found \n OR reached sfInput limit
    // if \n found it is returned.
    Serial.print("sfInput: "); Serial.print(sfInput);
    if (decodeCSV(sfInput)) {
      // got new valid inputs update
    } else {
      // error in CSV 
    }
    sfInput.clear(); // for next line
    statusFotoCell = digitalRead(fotocell);
    Serial.println(statusFotoCell);
    PZ7();
    PZ1();
    PZ2();
    PZ3();
    PZ4();
    PZ5();
    PZ6();
    Serial.println();
    Data();
  }  
}

It will send the data to the database twice at a moment.

Under what circumstances do you want those functions to be called ?

After all of the sensors are sensed and the variables are filled

Where in the code are you "filling the variables" ?

After I called PZ6(). In the end of loop