How to Read string on serial event

Hello, I have been learning about serial comm lately because I need to send some data from guardian arduino to controll arduino, they are both uno R3, and pls dont ask why

Guardian watches the system all the time and can send a turnoff over digital pin(not yet there)

Controller can ask for diagnostic, then guardian switches modes, and communicates some variables and compares responses to verify untill control asks to end diagnostic........

So I wrote a piece of code and am using serial monitor to test out the guardian response:

String Rx;                        //data reciever
String Tx;                        //data transmiter
float V320=285.734;               //320V measurement
float V12=11.875;                  //12V measurement
float V5=4.987;                     //5V measurement
int increment=0;                       //program advancement
float Rxf=0;                           //float for comunications verification
char RxCS[18];                         //Char for translation to float
int i;                                 //counter for timeout
int errorcode;                         //error code variable
bool mode=0;                            //guard or diagnostic

void setup(){
  Serial.begin(9600);
}
void serialEvent() {
//TRIED TO READ HERE,DOSENT WORK
   
  }
  
void loop() {
   while (mode==0) {                               //guard mode-will have much more code for comparing stuff
    Serial.println(F("Guarding,Input command"));            //just to see the loop speed is ok

V320 = ceil(V320 * 100.0) / 100.0;                          //rounding float measures to 2 decimals-for easier comm and verification
V12 = ceil(V12 * 100.0) / 100.0; 
V5 = ceil(V5 * 100.0) / 100.0; 
  
 Rx = Serial.readStringUntil('\n');            //MY TIME CONSUMING PROBLEM
    Rx.trim();                       

    if (Rx == "Start diagnostic") {
    Serial.println(F("Diagnostic started"));
    Rx = "";
    mode = 1;
    }
 
}

  while (mode==1){                                                                                  //diagnostic mode

  while (Serial.available() == 0) {}     //wait for data available
  Rx = Serial.readStringUntil('\n');     //read until timeout
  Rx.trim();                             // remove any \r \n whitespace at the end of the String
   Rx.toCharArray(RxCS, 18);             //converting string to char
   float Rxf=atof(RxCS);                 //converting char to float

if (increment>0){                                                                      //timing out wrong verification...
   i++;
   }
    if (i>10){                                                                         //10 guesses
    Serial.println(F("Timeout,diagnostic ended"));
    i=0;
    mode=0;
    }


    if (Rx==F("Send errorcode")) {                                                                 //event for sending error code
    Tx=String(errorcode);
    if (errorcode>0){
    increment=1;
    Serial.println(F("Confirmed,sending errorcode"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
     }
    else Serial.println(F("No error"));                                                            //or skipping errorcode verification
   Rx=""; 
   increment=0;
   }
  
  if (Rx == F("Send 320V")) {                                                                     
    increment=2;
    Tx=String(V320);
    Serial.println(F("Confirmed,sending 320V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
  Rx="";
 }
   if (Rx == F("Send 12V")) {
    increment=3;
    Tx=String(V12);
    Serial.println(F("Confirmed,sending 12V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
  Rx="";
 }
   if (Rx == F("Send 5V")) {
    increment=4;
    Tx=String(V5);
    Serial.println(F("Confirmed,sending 5V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
    Rx="";
 }
   if (Rx == F("End diagnostic")) {
    mode=0;
    Serial.println("Diagnostic ended");
    Rx="";
   }
   
                                                                                                                   //Confirmed verification
if (errorcode==Rxf and increment==1) {
  increment=0;
  i=0;
Serial.println(F("confirmed,errorcode ok"));
Rx="";
}

if (V320==Rxf and increment==2) {
increment=0;
i=0;
Serial.println(F("confirmed,320V ok"));
Rx="";
}
if (V12 == Rxf and increment==3) {
  increment=0;
  i=0;
Serial.println(F("confirmed,12V ok"));
Rx="";
}
if (V5 == Rxf and increment==4) {
  increment=0;
  i=0;
Serial.println(F("confirmed,5V ok"));
increment=0;
i=0;
Rx="";
}
   }

}                                                        

Everything is working dandy, except guardian guard loop is now 1 sec delayed because of readstring command..... lets just say it can't guard very well anymore....

Is there not a smarter way to start reading only on serial event/interrupt, and how exactly do I do it, i tried using the void serialEvent() to read string, but dosen't work...

All options are open, even controll arduino setting a guardian arduino digital pin before communication, but I realy want to avoid this...
Mind you, I can replace these funny text commands with numbers, but I need the comm strings for floats, it does not need to be fast while doing diagnostic (mode==1), only while guarding(mode==0)...

This is after 1 day spent learning serial, sorry if I made noob mistakes in coding
I know that this was probably answered somewhere, I tried finding info for a very long time to no avail before posting this...

while loop()ing read into an array character by character - when \n is received you have the message
have a look at serial-input-basics
seialEvent() is not a true event handler called when an event occures - it is in the same polling loop as loop()

Allright, but will it not try to read every time it passes still, tried a while loop, but that just hangs the main loop untill \n, and does things once after recieving message...

only call read() when Serial.available() indicates a character is ready to be read

while (Serial.available() == 0) {     //wait for data available
  Rx = Serial.readStringUntil('\n');     //read until newline
  Rx.trim();                             // remove any \r \n whitespace at the end of the String
}

Lile this? or is ==0 wrong? ... this stops my loop untill communication
should I ==1 maybe then?

have a look at

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

}

void loop() {
  static char data[200]={0};
  static int index=0;
  if(Serial.available()) {
    char ch=Serial.read();
    if(ch != '\n')
       { data[index++]=ch; data[index]=0; }
    else {
      Serial.print("data read = ");
      Serial.println(data);
      data[0]=index=0;
    }
  }
  // do other things
}

when you receive the \n you then test your mode setting etc

however, not sure why readString() should delay be one second
could be String class - on small memory micros like the UNO complex classes such as String should be avoided as they can fragment memory

1 Like

Allright I'll try just try

if(Serial.available())

with a string, if not working I'll switch to char
array on Rx, and try again XD
thx

delays for 1 sec exactly even if i terminate it with read until \n
it has a timeout for reading and wont budge...
string seamed very easy to correctly interpret anything on Rx, thats why I tried it first and it worked like a charm... only the initial mode switch is the problem

The one second timeout is what happens when you call readStringUntil() and the '\n' is not found, which will happen whenever there are no characters in the buffer.

See the link in reply##2, that will handle receiving the text properly, and will not be waiting if there are no characters in the buffer.

1 Like

well what do you know

 if(Serial.available()){
 Rx = Serial.readStringUntil('\n'); 
    Rx.trim();                       
  }

only change, and now I got loop printing like crazy untill i type Start diagnostic...
looks like its solved!
thought Serial available needed an argument XD
thanks

String Rx;                        //data reciever
String Tx;                        //data transmiter
float V320=285.734;               //320V measurement
float V12=11.875;                  //12V measurement
float V5=4.987;                     //5V measurement
int increment=0;                       //program advancement
float Rxf=0;                           //float for comunications verification
char RxCS[18];                         //Char for translation to float
int i;                                 //counter for timeout
int errorcode;                         //error code variable
bool mode=0;                            //guard or diagnostic

void setup(){
  Serial.begin(9600);
}
  
void loop() {
   while (mode==0) {                                           //Guard mode
    Serial.println(F("Guarding,Input command"));            //just to see the loop speed is ok

V320 = ceil(V320 * 100.0) / 100.0;                          //rounding float measures to 2 decimals-for easier comm and verification
V12 = ceil(V12 * 100.0) / 100.0; 
V5 = ceil(V5 * 100.0) / 100.0; 
  if(Serial.available()){                                                 //Read command only when serial available
 Rx = Serial.readStringUntil('\n'); 
    Rx.trim();                       
  }
    if (Rx == "Start diagnostic") {
    Serial.println(F("Diagnostic started"));
    Rx = "";
    mode = 1;
    }
 
}

  while (mode==1){                                                                                  //diagnostic mode

  while (Serial.available() == 0) {}     //wait for data available
  Rx = Serial.readStringUntil('\n');     //read until timeout
  Rx.trim();                             // remove any \r \n whitespace at the end of the String
   Rx.toCharArray(RxCS, 18);             //converting string to char
   float Rxf=atof(RxCS);                 //converting char to float

if (increment>0){                                                                      //timing out wrong verification...
   i++;
   }
    if (i>10){                                                                         //10 guesses
    Serial.println(F("Timeout,diagnostic ended"));
    i=0;
    mode=0;
    }


    if (Rx==F("Send errorcode")) {                                                                 //event for sending error code
    Tx=String(errorcode);
    if (errorcode>0){
    increment=1;
    Serial.println(F("Confirmed,sending errorcode"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
     }
    else Serial.println(F("No error"));                                                            //or skipping errorcode verification
   Rx=""; 
   increment=0;
   }
  
  if (Rx == F("Send 320V")) {                                                                     
    increment=2;
    Tx=String(V320);
    Serial.println(F("Confirmed,sending 320V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
  Rx="";
 }
   if (Rx == F("Send 12V")) {
    increment=3;
    Tx=String(V12);
    Serial.println(F("Confirmed,sending 12V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
  Rx="";
 }
   if (Rx == F("Send 5V")) {
    increment=4;
    Tx=String(V5);
    Serial.println(F("Confirmed,sending 5V"));
    delay(100);
    Serial.println(Tx); 
    Serial.println(F("Expecting return"));
    Rx="";
 }
   if (Rx == F("End diagnostic")) {                                                             //this ends diag mode
    mode=0;                                                                                                 //returns to guarding
    Serial.println("Diagnostic ended");
    Rx="";                                                                                                   //clears the comm strings
    Tx="";
   }
   
                                                                                                                   //Confirmed verification
if (errorcode==Rxf and increment==1) {
  increment=0;
  i=0;
Serial.println(F("confirmed,errorcode ok"));
Rx="";
}

if (V320==Rxf and increment==2) {
increment=0;
i=0;
Serial.println(F("confirmed,320V ok"));
Rx="";
}
if (V12 == Rxf and increment==3) {
  increment=0;
  i=0;
Serial.println(F("confirmed,12V ok"));
Rx="";
}
if (V5 == Rxf and increment==4) {
  increment=0;
  i=0;
Serial.println(F("confirmed,5V ok"));
increment=0;
i=0;
Rx="";
}
   }

}                                                        

Here is the fully working version if anyone wants to toss around some floats and text commands over serial, with strings XD

@Semtex9 If you encounter longer-term problems(for example, crashes after several hours or even days of operation) with the Uno that's using String functions instead of classic strings, you were told in this thread why - String functions cause problems with memory management on the less capable Arduinos, such as the Uno, Nano, and Mega products. Better to take the advice you've been given and process the input as chars you add to a null-terminated string. Good luck!

I'll keep it in mind, its for a welder college project, shouldn't work more then couple of hours at a time, as a working version, or couple of minutes ever to pass I guess...
Strings are used only on demand when I select to run diag or at the start of controllers program...
so it shouldn't be so crash prone, and I set them to clear after each communication
Idk if they would corrupt just for existing or if they get too long after many writes, clearing after each should solve the memory issue no?
it is easily changeable tho...
thanks for the heads up

1 Like

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