Serial - parseData, showParsedData - Problem

Hello, friends,

I have a serial connection between Raspberry Pi 4 and the Arduino Mega 2560 R3 via USB. They exchange data and this works reasonably well.
It is so that when several commands are sent from the RPI4 to the Arduino in a row, the Arduino is blocked or seems to get stuck.
I only read out texts like “GaesteZ_ON” or “GaesteZ_OFF” to switch lights or shutters.

Do you have an idea if this has to do with the function for reading the string or maybe with the evaluation afterwards?

My Strings from RPI4 to Arduino look like this:
<Rollladen_GZ_UP,>

The Arduino turns it into this:
Rollladen_GZ_UP

But if you give him more than one command at a time, he hangs himself

Many thanks in advance for your help!!!

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
boolean newData = false;

// variables to hold the parsed data
char messageFromPC[numChars] = {0};

void setup() {
    Serial.begin(9600);
    Wire.begin(); // wake up I2C bus
 }

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            // because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;  
    }
 }

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();
        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }
        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
}

void showParsedData() {
    
  /**********************Rollershutter**********************/
          
         if (strcmp(messageFromPC, "Rollladen_GZ_UP") == 0) {
        mcp1.digitalWrite(9, HIGH);
                delay(100);
        mcp1.digitalWrite(8, LOW);
         }

        if (strcmp(messageFromPC, "Rollladen_GZ_DOWN") == 0) {
        mcp1.digitalWrite(8, HIGH);
        delay(100);
        mcp1.digitalWrite(9, LOW);
  }

          if (strcmp(messageFromPC, "Rollladen_GZ_STOP") == 0) {
        mcp1.digitalWrite(8, HIGH);
      //  delay(100);
        mcp1.digitalWrite(9, HIGH);
  }

           if (strcmp(messageFromPC, "Rollladen_SZ_UP") == 0) {
        mcp1.digitalWrite(11, HIGH);
                delay(100);
        mcp1.digitalWrite(10, LOW);
         }

        if (strcmp(messageFromPC, "Rollladen_SZ_DOWN") == 0) {
    mcp1.digitalWrite(10, HIGH);
            delay(100);
    mcp1.digitalWrite(11, LOW);
  }

          if (strcmp(messageFromPC, "Rollladen_SZ_STOP") == 0) {
        mcp1.digitalWrite(10, HIGH);
      //  delay(100);
        mcp1.digitalWrite(11, HIGH);
  }

  /**********************Lights**********************/
        
        if (strcmp(messageFromPC, "Licht_GaesteZ_ON") == 0 && mcp2.digitalRead(1) == LOW ){
    mcp3.digitalWrite(8, LOW);
        delay(100);
    mcp3.digitalWrite(8, HIGH);
          }
          
        if (strcmp(messageFromPC, "Licht_GaesteZ_OFF") == 0 && mcp2.digitalRead(1) == HIGH ){
    mcp3.digitalWrite(8, LOW);
        delay(100);
    mcp3.digitalWrite(8, HIGH);
          }
          
        if (strcmp(messageFromPC, "Licht_SchlafZ_Allgemein_ON") == 0 && mcp3.digitalRead(7) == LOW) {
    mcp3.digitalWrite(10, LOW);
        delay(100);
    mcp3.digitalWrite(10, HIGH);
}

        if (strcmp(messageFromPC, "Licht_SchlafZ_Allgemein_OFF") == 0 && mcp3.digitalRead(7) == HIGH) {
    mcp3.digitalWrite(10, LOW);
        delay(100);
    mcp3.digitalWrite(10, HIGH);
  } 
}

"But if you give him more than one command at a time, he hangs himself"

Have you tried putting a short delay between sending the commands? Controlling how data is sent is often key for receiving the code. An uncontrolled data spew can be difficult to receive. Also you code has a lot of internal delays that might slow or degrade receiving the sent code.

const byte numChars = 32;

This line says that the maximum length of your message is 31, excluding the markers.

How long is your message?

zoomkat:
"But if you give him more than one command at a time, he hangs himself"

Have you tried putting a short delay between sending the commands? Controlling how data is sent is often key for receiving the code. An uncontrolled data spew can be difficult to receive. Also you code has a lot of internal delays that might slow or degrade receiving the sent code.

Hello zoomkat,

i send the code from Openhab 2 to the Arduino via serial string, but this is done instantaneously with every click i think. For this reason I'll see if I can add a serial connection check like the Arduino" while (Serial.available() > 0 && newData == false)".

The mentioned delays are unfortunately necessary because I use current surge relays and therefore I have to imitate a push button. I'll try it without, although I wanted to replace them with the internal timers, but I didn't have enough time to get it to work.

Thanks for your super fast feedback zoomkat!!!!
I'm uploading the code without any delays and I'm curious if at least the commands get through, even if the relays don't switch through properly.

Greeting
Tobi

arduino_new:

const byte numChars = 32;

This line says that the maximum length of your message is 31, excluding the markers.

How long is your message?

Hello arduino_new,

I had this problem in the beginning and therefore shortened the messages so that the longest message has 28 characters including the markers:
<Light_Sleep_ON_General_ON>

But this is really a classic mistake and it had been with me at the beginning, so thank you very much for your good idea!

Greeting
Tobi

If you need to send data frequently a much higher baud rate may help. A Mega will work quite happily at 500,000 baud.

And, as already mentioned, make sure that you have space for the longest possible message.

Why has your showParsedData() function acquired delay()s? There are none in my tutorial - and that is deliberate. If you need to control timing do it in the sending program.

...R

Hello, friends,

I have detected another possible problem, which is in the loop. In each loop the Arduino checks via I2C at the MCP23017 port expander if a level at its ports has changed (feedback from a normally open contact of the respective surge relay from the light).

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            // because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;  
    }
   
Status_Licht_Gaestezimmer = mcp2.digitalRead(1);
Status_Licht_Schlafzimmer_Allgemein = mcp3.digitalRead(7);
Status_Licht_Schlafzimmer_Kleiderschrank = mcp3.digitalRead(6);
Status_Licht_Arbeitszimmer = mcp3.digitalRead(4);
Status_Licht_Wohnzimmer_Allgemein = mcp3.digitalRead(3);
Status_Licht_Wohnzimmer_LED = mcp3.digitalRead(2);

Status_Licht_Kueche = mcp3.digitalRead(0);
Status_Licht_Balkon = mcp4.digitalRead(7);
Status_Licht_Gang = mcp4.digitalRead(6);
Status_Licht_Seitengang = mcp4.digitalRead(5);
Status_Licht_Abstellraum = mcp4.digitalRead(4);
Status_Licht_Bad = mcp4.digitalRead(3);
Status_Licht_GaesteWC = mcp4.digitalRead(2);


  if (Status_Licht_Gaestezimmer != Letzter_Status_Licht_Gaestezimmer){
           if (Status_Licht_Gaestezimmer == HIGH) {
    Serial.println("Licht_GaesteZ,ON;");
       }   
    if (Status_Licht_Gaestezimmer == LOW) {
    Serial.println("Licht_GaesteZ,OFF;");
    }
  }
  
 if (Status_Licht_Schlafzimmer_Allgemein != Letzter_Status_Licht_Schlafzimmer_Allgemein){
    if (Status_Licht_Schlafzimmer_Allgemein == HIGH) {
  Serial.println("Licht_SchlafZ_Allgemein,ON;");
    }
    
    if (Status_Licht_Schlafzimmer_Allgemein == LOW) {
  Serial.println("Licht_SchlafZ_Allgemein,OFF;");
    }
 }
 
if (Status_Licht_Schlafzimmer_Kleiderschrank != Letzter_Status_Licht_Schlafzimmer_Kleiderschrank){
    if (Status_Licht_Schlafzimmer_Kleiderschrank == HIGH) {
          Serial.println("Licht_SchlafZ_Schrank,ON;");
    }
   
    if (Status_Licht_Schlafzimmer_Kleiderschrank == LOW) {
          Serial.println("Licht_SchlafZ_Schrank,OFF;");
    }
 }

    if (Status_Licht_Arbeitszimmer != Letzter_Status_Licht_Arbeitszimmer){
    if (Status_Licht_Arbeitszimmer == HIGH) {
          Serial.println("Licht_ArbeitsZ,ON;");
    }

    if (Status_Licht_Arbeitszimmer == LOW) {
          Serial.println("Licht_ArbeitsZ,OFF;");
    }
 }

 if (Status_Licht_Wohnzimmer_Allgemein != Letzter_Status_Licht_Wohnzimmer_Allgemein){
    if (Status_Licht_Wohnzimmer_Allgemein == HIGH) {
          Serial.println("Licht_WohnZ_Allgemein,ON;");
    }
    
    if (Status_Licht_Wohnzimmer_Allgemein == LOW) {
          Serial.println("Licht_WohnZ_Allgemein,OFF;");
    }
 }

if (Status_Licht_Wohnzimmer_LED != Letzter_Status_Licht_Wohnzimmer_LED){
    if (Status_Licht_Wohnzimmer_LED == HIGH) {
          Serial.println("Licht_WohnZ_LED,ON;");
    }
    
    if (Status_Licht_Wohnzimmer_LED == LOW) {
          Serial.println("Licht_WohnZ_LED,OFF;");
    }   
 }

if (Status_Licht_Kueche != Letzter_Status_Licht_Kueche){
    if (Status_Licht_Kueche == HIGH) {
          Serial.println("Licht_Kueche,ON;");
    }

    if (Status_Licht_Kueche == LOW) {
          Serial.println("Licht_Kueche,OFF;");
    }  
 }

if (Status_Licht_Balkon != Letzter_Status_Licht_Balkon){
    if (Status_Licht_Balkon == HIGH) {
          Serial.println("Licht_Balkon,ON;");
    }

    if (Status_Licht_Balkon == LOW) {
          Serial.println("Licht_Balkon,OFF;");
    }  
 }

if (Status_Licht_Gang != Letzter_Status_Licht_Gang){
    if (Status_Licht_Gang == HIGH) {
          Serial.println("Licht_Gang,ON;");
    }

    if (Status_Licht_Gang == LOW) {
          Serial.println("Licht_Gang,OFF;");
    }  
 }

if (Status_Licht_Seitengang != Letzter_Status_Licht_Seitengang){
    if (Status_Licht_Seitengang == HIGH) {
          Serial.println("Licht_Seitengang,ON;");
    }

    if (Status_Licht_Seitengang == LOW) {
          Serial.println("Licht_Seitengang,OFF;");
    } 
 }

if (Status_Licht_Abstellraum != Letzter_Status_Licht_Abstellraum){
     if (Status_Licht_Abstellraum == HIGH) {
          Serial.println("Licht_Abstellraum,ON;");
    }

    if (Status_Licht_Abstellraum == LOW) {
          Serial.println("Licht_Abstellraum,OFF;");
    }    
 }

if (Status_Licht_Bad != Letzter_Status_Licht_Bad){
     if (Status_Licht_Bad == HIGH) {
          Serial.println("Licht_Bad,ON;");
    }

    if (Status_Licht_Bad == LOW) {
          Serial.println("Licht_Bad,OFF;");
    } 
 }

if (Status_Licht_GaesteWC != Letzter_Status_Licht_GaesteWC){
      if (Status_Licht_GaesteWC == HIGH) {
          Serial.println("Licht_GaesteWC,ON;");
    }

if (Status_Licht_GaesteWC == LOW) {
          Serial.println("Licht_GaesteWC,OFF;");
    }   
 } 

 Letzter_Status_Licht_Gaestezimmer = Status_Licht_Gaestezimmer;
 Letzter_Status_Licht_Schlafzimmer_Allgemein = Status_Licht_Schlafzimmer_Allgemein;
 Letzter_Status_Licht_Schlafzimmer_Kleiderschrank = Status_Licht_Schlafzimmer_Kleiderschrank;
 Letzter_Status_Licht_Arbeitszimmer = Status_Licht_Arbeitszimmer;
 Letzter_Status_Licht_Wohnzimmer_Allgemein = Status_Licht_Wohnzimmer_Allgemein;
 Letzter_Status_Licht_Wohnzimmer_LED = Status_Licht_Wohnzimmer_LED;

 Letzter_Status_Licht_Kueche = Status_Licht_Kueche;
 Letzter_Status_Licht_Balkon = Status_Licht_Balkon;
 Letzter_Status_Licht_Gang = Status_Licht_Gang;
 Letzter_Status_Licht_Seitengang = Status_Licht_Seitengang;
 Letzter_Status_Licht_Abstellraum = Status_Licht_Abstellraum;
 Letzter_Status_Licht_Bad = Status_Licht_Bad;
 Letzter_Status_Licht_GaesteWC = Status_Licht_GaesteWC;
}

Without this check, the light control commands will work fine.

With the roller shutters everything is running as well, except the moment a "STOP" command is sent to a roller shutter motor...
I have not yet found out this problem.

I will test the light feedback check of an interrupt routine and or an external function and hope that it is done.

Many thanks again to all of you!
I will give feedback as soon as something has happened!

Greeting
Tobi

Robin2:
If you need to send data frequently a much higher baud rate may help. A Mega will work quite happily at 500,000 baud.

And, as already mentioned, make sure that you have space for the longest possible message.

Why has your showParsedData() function acquired delay()s? There are none in my tutorial - and that is deliberate. If you need to control timing do it in the sending program.

...R

Hello, Robin,

there must be no delays in "void showParsedData()"?
With the small delays of 30ms it works with the light at least, but you are right, if I just read the commands I save computing power or the Raspberry Pi can implement a time delay in Openhab and just send the ON/OFF command. This will be better for the percentage control of the shutters anyway I think.

Thank you for your hint and with it a new impulse to perhaps easier implementation.
Maybe I got too involved in the problem that I did not see the simplest solution!

Now I'm going to set the baudrate high and then I'll implement the other ideas and I'm curious how it works!

Thanks again and see you later/morning/the days! :slight_smile:

Greeting
Tobi

Hello, friends,

I have now tried everything (baudrate, no delays, new MCP23017, different circuit designs,…) and I have come to the conclusion that there must be possible voltage peaks from switching the relays on the Sainsmart 16 channel relay board (5V-Version not the 12V-Version).

Even in the galvanically isolated setup, the MCP23017 hangs up after one or a few switching operations of the shutter motors. When switching the relays for the toggle relays, everything works permanently, but there must be large voltage spikes in the shutter motors.

Do you have a different theory?
Should I open a new topic on this?
I might try to use additional transistors at the output of the MCP23017.

Thanks in advance for your support!

If you need delays, you might try incorporating the millis() functions in your code like in the below example instead of using delay().

//zoomkat 6-29-14 Simple serial echo test
//type or paste text in serial monitor and send

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("Simple serial echo test"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the String readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    delay(200);   
    Serial.print("nano also received ");
    Serial.println(readString);  //so you can see the captured String
    readString="";
  }
}

TobiasR1991:
I have come to the conclusion that there must be possible voltage peaks from switching the relays on the Sainsmart 16 channel relay board (5V-Version not the 12V-Version).

That should be easy to check - {A} run the program with nothing connected to the relay outlets and see if communication works properly and if that does not make any difference {B} disconnect the relay board completely and see if communication works.

…R

Robin2:
That should be easy to check - {A} run the program with nothing connected to the relay outlets and see if communication works properly and if that does not make any difference {B} disconnect the relay board completely and see if communication works.

...R

Hello, Robin,

that's exactly what I was doing earlier and that's why I had this bad feeling....
I just put a ULN2803 in between and it works....
So I can now plan an ULN2803 board for larger loads and may extend my finished cabinet as optically nice as possible.
At least now I know the mistake and thank you very much for your super fast and constructive support!

Hello again,

the ULN2803 unfortunately did not eliminate the faulty circuits and "hangers" of the MCP's
I suspect that the relays from the Sainsmart relay board for the roller shutters have voltage peaks due to the higher power.
The suspicion arises from the fact that the circuits of the impulse relays 0 cause faulty switching and only the circuits of the roller shutter relays when they switch loadless. Under load the roller shutter relays must apparently intersperse voltage peaks when switching off.

I have read some articles and tried the interference suppression by ceramic capacitors, but without success.
I would like to
Connect TVS diode, 1N 5908, unidirectional, 5 V, 1500 W, CB421 in front of the power supply of the relay board and if necessary to further power supplies e.g. to the MCP23017 chips.

If that does not bring the final solution, then I will use ssr relay boards if necessary and hope that these do not intersperse voltage peaks.

Do you have an idea what else would be possible?
I will make a drawing tomorrow so that a better "picture" is created.

Greeting
Tobi

Good morning,

i looked at my 16 channel relay board again while looking for SSR-Relayboard and there someone left a comment that the voltage peaks from the relay to the inputs of the control modules can overflow due to the missing separation of the supply voltage of the optocouplers and the relays.
I suspected this but still hoped that I could solve it by diodes, capacitors and a further separation by ULN2803.

I have now bought an ssr relay board and an 8 channel relay board and will test them. The 8 channel relay board has at least jumpers to separate the power supply of the relays and the optocouplers.
If that still doesn't work, then I'll take the SSR relay board.

I will give feedback!