Multiplex stops when reading/writing to serial

Hello, for the last few days I've been struggling to set up a working serial communication between two Arduino UNO's. Right now the communication problem itself has been solved, but it brought another with it: It interrupts a different proces, the multiplexing of two 7 segment displays.

To give a sketch of the whole situation: We are making a robot that is supposed to follow a line and has to load or unload at designated points. While it is driving it shows if its loaded or not and how many pieces of cargo it has had. This has to be done with multiplexing.

The multiplexing should be a proces that should always be on while the on switch has been pressed, but in the moment that the Arduino's communicate with eachother the multiplexing stops.
Video: https://puu.sh/D4ADD/e150972ec7.mp4

Is there a way to make it communicate and multiplex at the same time?

Parts in use with testing this code:

  • 2x arduino UNO
  • 2x L298P Shield (v1.2 and v1.3)
  • 1x LEGO motor
  • 2x 7 Segment display (SC52-115RWA)
  • 1x standard(?) switch

I translated the code for (maybe) easier reading, but I might have missed some things.
There are also pieces of code for the motors, you can ignore those.

Code Arduino 1:

#define M1 4  //Motor left direction
#define E1 5  //Motor left speed
#define E2 6  //Motor right speed
#define M2 7  //Motor right direction
#define LS1 A0 //Sensor far left
#define LS3 A1 //Sensor left
#define LS2 A2 //Sensor right
#define LS4 A3 //Sensor far right

void setup() {
  pinMode(E1, OUTPUT);
  pinMode(M1, OUTPUT);
  pinMode(E2, OUTPUT);
  pinMode(M2, OUTPUT);
  pinMode(LS1, INPUT);
  pinMode(LS2, INPUT);
  pinMode(LS3, INPUT);
  pinMode(LS4, INPUT);
  Serial.begin(9600);
}


int val1;
int val2;
int val3;
int val4;
int turn = 4000; //Test: time needed to turn 90  degrees.
const int black = 500;
bool loaded = false;
bool sent = false;
bool on = false;

void loop() {
  if (on) {
    //Infinite loop to test communication
    if (!sent) {
      if (loaded) {
        serialOutput("unload");
      } else {
        serialOutput("load");
      }
    }
  } else {
    //Make proper reset
    stopMotors();
    sent = false;
  }

  while (Serial.available() > 0) {
    serialInput();
  }

  delay(10);
}

//------------- Motor controls -------------

void motor1(int PWM, boolean forward) {
  analogWrite(E1, PWM);
  if (forward) {
    digitalWrite(M1, HIGH);
  } else {
    digitalWrite(M1, LOW);
  }
}

void motor2(int PWM, boolean forward) {
  analogWrite(E2, PWM);
  if (forward) {
    digitalWrite(M2, LOW);
  } else {
    digitalWrite(M2, HIGH);
  }
}

void forward() {
  motor1(255, true);
  motor2(255, true);
}

void backwards() {
  motor1(255, false);
  motor2(255, false);
}

void left() {
  motor1(255, false);
  motor2(255, true);
}

void right() {
  motor1(255, true);
  motor2(255, false);
}

void adjustLeft() {
  motor1(180, true);
  motor2(240, true);
}

void adjustRight() {
  motor1(240, true);
  motor2(180, true);
}

void turnAround() {
  motor1(255, false);
  motor2(255, true);
}

void stopMotors() {
  motor1(0, false);
  motor2(0, false);
}

//------------- Serial communication -------------

void serialInput() {
  String input = Serial.readString();
  if (input.substring(0, 9) == "on_device") {
    on = true;
  }
  if (input.substring(0, 9) == "of_device") {
    on = false;
  }

  if (on) {
    if (input.substring(0, 6) == "loaded") {
      loaded = true;
      sent = false;
    }
    if (input.substring(0, 8) == "unloaded") {
      loaded = false;
      sent = false;
    }

  }
}

void serialOutput(String output) {
  Serial.println(output);
  sent = true;
}

Code Arduino 2:

#define M3 4
#define E3 5
#define LDRpin A0
#define KNOP 2 //ON/OFF

int LDRvalue = 0;
int cargo = 0; //Number of the cargo being moved
bool loaded = false;
bool on = false;
bool on_display = false;
bool pressed = false;

void setup() {
  pinMode(LDRpin, INPUT);
  pinMode(KNOP, INPUT_PULLUP);
  pinMode(3, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(M3, OUTPUT);
  pinMode(E3, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
}


void loop() {
  if (!pressed) {
    if (digitalRead(KNOP) == LOW) {
      if (on) {
        //Make proper reset
        on = false;
        cargo = 0;
        loaded = false;
        Serial.println("of_device");
      } else {
        on = true;
        Serial.println("on_device");
      }
      pressed = true;
    }
  } else {
    if (digitalRead(KNOP) == HIGH) {
      pressed = false;
    }
  }

  
  if (on) {
    on_display = true;
  } else {
    on_display = false;
  }


  multiplex(1);

  while (Serial.available() > 0) {
    serialInput();
  }





}

//------------- Motor controls -------------

void motor(int PWM, boolean up) {
  analogWrite(E3, PWM);
  if (up) {
    digitalWrite(M3, HIGH);
  } else {
    digitalWrite(M3, LOW);
  }
}

void load() {
  motor(255, true);
  multiplex(1000);
  motor(0, false);
  cargo++;
  loaded = true;
  Serial.println("loaded");
}

void unload() {
  motor(255, false);
  multiplex(850);
  motor(0, true);
  loaded = false;
  Serial.println("unloaded");
}

//------------- 7 segment display 1 -------------

void e() {
  digitalWrite(3, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, LOW);
  digitalWrite(12, HIGH);
  digitalWrite(13, LOW);
}

void l() {
  digitalWrite(3, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, LOW);
  digitalWrite(12, HIGH);
  digitalWrite(13, LOW);
}

void counter(int tel) {
  if (tel == 0) {
    zero();
  } else if (tel == 1) {
    one();
  } else if (tel == 2) {
    two();
  } else {
    zero();
  }
}

//------------- 7 segment display 2 -------------

void zero() {
  digitalWrite(3, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);
  digitalWrite(12, LOW);
  digitalWrite(13, HIGH);
}

void one() {
  digitalWrite(3, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, HIGH);
  digitalWrite(12, LOW);
  digitalWrite(13, HIGH);
}

void two() {
  digitalWrite(3, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  digitalWrite(13, HIGH);
}

void ledOff() {
  digitalWrite(3, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
}

//------------- 7 segment displays combined -------------

void multiplex(int steps) { 
  if (on_display) {
    for (int i = 0; i < steps; i++) {
      if (loaded) {
        l();
        delay(2);
        counter(cargo);
        delay(2);
      } else {
        e();
        delay(2);
        counter(cargo);
        delay(2);
      }
    }
  } else {
    ledOff();
  }
}

//------------- Serial communication -------------

void serialInput() {

  String input = Serial.readString();
  if (on) {
    if (input.substring(0, 4) == "load") {
      if (!loaded) {
        load();
      }
    } 
    if (input.substring(0, 6) == "unload") {
      if (loaded) {
        unload();
      }
    }
  }
}

In such case, you may follow the following strategy:

Send just 1 frame (one character or one byte) or multiple frames (2 or more) to the destination UNO
Refresh the multiplexed display
Repeat the above two steps until all data bytes have been transferred.

CapeOmnia:
but it brought another with it: It interrupts a different proces, the multiplexing of two 7 segment displays.

Please explain that in more detail.

Which of the two programs has the problem?

In your second program you are using Serial.readString() which blocks the Arduino from doing other things until it completes. Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R

GolamMostafa:
In such case, you may follow the following strategy:

Send just 1 frame (one character or one byte) or multiple frames (2 or more) to the destination UNO
Refresh the multiplexed display
Repeat the above two steps until all data bytes have been transferred.

And how would the receiving end know when the command is complete?
I guess a predetermined character?

Robin2:
Please explain that in more detail.

Which of the two programs has the problem?

First of I started with only Arduino 2 and me giving the commands over the serial monitor. At that time the the multiplexing wasn't interrupted. Then when I made the infinite loop in Arduino 1 and connected the two the problem surfaced.

EDIT: Just tested with the serial monitor again and the interruption is there. So adding the loop was not the cause. But I can honestly not remember what else I changed since yesterday.

Robin2:
In your second program you are using Serial.readString() which blocks the Arduino from doing other things until it completes. Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R

I started using readString after my robotics teacher gave me the advice to do so (only thing he wanted to say about me fixing the communication). Before i was using serial.write and serial.read to send single bytes over, but those were never read.

I'll be going over the links you gave me, thank you.

CapeOmnia:
And how would the receiving end know when the command is complete?
I guess a predetermined character?

Yeah! This will work.