Two-way serial communication with multiple devices

The overall project I am working on is a controller for LED lighting on a vehicle and is comprised of 4 individual Nanos: A status display unit with buttons for sending specific commands and 3 other units which read inputs from the vehicle (e.g. head lights, brake lights, turn signals) alongside the commands sent by the status display unit, and actually do the lighting control. I have been working with Arduinos for a few years now off and on, and this is by far the most complex project I have attempted.

The reason I am asking for help here is that my code doesn't work the way I expect... but it also "doesn't not work". That is, I am able to send and receive serial communications, but they only sometimes do what I think they should. I will post code below for both the Status Display and the Front controller (code for the Rear and TC bar will be almost identical to the Front controller, only with some different input/output configurations), but here is an example of the trouble I am facing.

When started up with just the Front controller connected, the Status display will acknowledge that it is connected (LCD screen shows "All off" versus "N/C"). Good so far. If I input a signal for driving lights at the Front controller, the driving lights output goes high, and the LCD screen on Status display says "Driving". Great - obviously the two are communicating. I turn driving lights back off, screen shows All Off. So THAT part of things seems to work out. When I then press the "Flash Front" button on Status display, Front controller starts flashing... But the screen still shows "All off".... wait for it... about 5-10 seconds later, the screen THEN shows "Flash". Why did it take so long for that to happen? And, if I press the button again to turn the flashing off, nothing happens... Debug LCD shows that I turned off the mode when I pressed the button, but screen says "Flash" and the unit still flashes.... For anywhere between 5-30 seconds.... Eventually it will usually stop flashing though, and screen back to "All Off".

So, my question is, what is taking so long for things to happen? I would understand that if the code was totally broken and things didn't work at all, I would know where to start troubleshooting that. But, when code eventually does the things I want but takes random amounts of time on the order of seconds to minutes, I just don't know what to think other than that it is more of an optimization problem than a troubleshooting problem.

Apologies for the long winded post. Any help is appreciated. Will reply with the code following this post.

Code for “Status Display” unit (modified due to post char limit, removing some functions for rear/TC but these are all functionally similar to the functions for Front):

#include <LiquidCrystal.h>
//Set LCD Pins as  lcd(rs, en, d4, d5, d6, d7)
LiquidCrystal lcd2(12, 11, 5, 4, 3, 2); //The "top" screen
LiquidCrystal lcd(12, 13, 5, 4, 3, 2); //The "bottom" screen

#include <SoftwareSerial.h>
//Setup software serial port:  SofwareSerial portName(RX, TX);
SoftwareSerial frontSerial(8, 9);
SoftwareSerial rearSerial(6, 7);
SoftwareSerial tcSerial(A5, A4);

//Pin Define
int frontBtn = 10;
int rearBtn = A3;
int tcFlashBtn = A2;
int tcEnBtn = A1;
int tcRevBtn = A0;

//Setup LCD Strings for LCD1
String lcdTopDefault = "  Front | Rear  ";
String lcdBottomDefault = "        |       ";
String lcdTop = lcdTopDefault;
String lcdBottomLeft;
String lcdBottomRight;
String lcdBottom = lcdBottomDefault;

//Setup LCD Strings for LCD2
String lcd2TopDefault = " TrafCon Status ";
String lcd2BottomDefault = " [1|2|3][4|5|6] ";
String lcd2Top = lcd2TopDefault;
String lcd2Bottom = lcd2BottomDefault;

//Setup Serial Containers
char frontData = '@';
char frontOld;
char rearData = '@';
char rearOld;
char tcData = '@';
char tcOld;

//Setup Button Reads
int frontBtnRead;
int rearBtnRead;
int tcFlashBtnRead;
int tcEnBtnRead;
int tcRevBtnRead;

//Setup Button Olds
int frontBtnOld = LOW;
int rearBtnOld = LOW;
int tcFlashBtnOld = LOW;
int tcEnBtnOld = LOW;
int tcRevBtnOld = LOW;

//Setup Button States
int frontBtnState;
int rearBtnState;
int tcFlashBtnState;
int tcEnBtnState;
int tcRevBtnState;

//Setup Output States
bool flashFront;
bool flashRear;
bool flashTC = false;
bool enableTC = false;
bool reverseTC = false;

//Setup Requestor States
bool sendFrontStatus;
bool sendRearStatus;
bool sendTCStatus;

//Setup Debounce Timers
unsigned long lastDebounce1 = 0; //Front Button
unsigned long lastDebounce2 = 0; //Rear Button
unsigned long lastDebounce3 = 0; //TC Flash Button
unsigned long lastDebounce4 = 0; //TC Enable Button
unsigned long lastDebounce5 = 0; //TC Reverse (L to R) Button
unsigned long frontDebounce = 0; //Front State Change
unsigned long rearDebounce = 0; //Rear State Change
unsigned long tcDebounce = 0; //TC State Change
unsigned long debounceDly = 50;

//Other Vars
bool firstRun;
int serWait = 50;

void setup()
{
//Set firstRun
firstRun = true;

//Setup LCD (cols, rows)
lcd.begin(16, 2);
lcd2.begin(16,2);

//Start SW serial
tcSerial.begin(19200);
rearSerial.begin(19200);
frontSerial.begin(19200);

//Pin Modes
pinMode(frontBtn, INPUT);
pinMode(rearBtn, INPUT);
pinMode(tcFlashBtn, INPUT);
pinMode(tcEnBtn, INPUT);
pinMode(tcRevBtn, INPUT);
//intro();
skipIntro();
}

void skipIntro()
{
lcd.setCursor(0,0);
lcd.print(lcdTop);
lcd.setCursor(0,1);
lcd.print(lcdBottom);
lcd2.setCursor(0,0);
lcd2.print(lcd2Top);
lcd2.setCursor(0,1);
lcd2.print(lcd2Bottom);
}

void loop()
{
readButtons();
getFrontData();
processFrontData();
sendFrontSerial();
processLCD();
writeLCD();

readButtons();
getRearData();
processRearData();
sendRearSerial();
processLCD();
writeLCD();

readButtons();
getTCData();
processTCData();
sendTCSerial();
processLCD();
writeLCD();
};

void readButtons()
{
//Read buttons
int frontBtnRead = digitalRead(frontBtn);
int rearBtnRead = digitalRead(rearBtn);
int tcFlashBtnRead = digitalRead(tcFlashBtn);
int tcEnBtnRead = digitalRead(tcEnBtn);
int tcRevBtnRead = digitalRead(tcRevBtn);

//Front Button Reading
if (frontBtnRead != frontBtnOld)
  {
    lastDebounce1 = millis();
  };
  
if ((millis() - lastDebounce1) > debounceDly)
  {
    if (frontBtnRead != frontBtnState)
      {
        frontBtnState = frontBtnRead;
        if (frontBtnState == HIGH)
          {
            flashFront = !flashFront;
          }
      }
  };

//Rear Button Reading
if (rearBtnRead != rearBtnOld)
  {
    lastDebounce2 = millis();
  };
if ((millis() - lastDebounce2) > debounceDly)
  {
    if (rearBtnRead != rearBtnState)
      {
        rearBtnState = rearBtnRead;
        if (rearBtnState == HIGH)
          {
            flashRear = !flashRear;
          }
      }
  };
  
//TC Flash Button Reading
if (tcFlashBtnRead != tcFlashBtnOld)
  {
    lastDebounce3 = millis();
  };
if ((millis() - lastDebounce3) > debounceDly)
  {
    if (tcFlashBtnRead != tcFlashBtnState)
      {
        tcFlashBtnState = tcFlashBtnRead;
        if (tcFlashBtnState == HIGH)
          {
            flashTC = !flashTC;
          }
      }
  };
//TC Enable Button Reading
if (tcEnBtnRead != tcEnBtnOld)
  {
    lastDebounce4 = millis();
  };
if ((millis() - lastDebounce4) > debounceDly)
  {
    if (tcEnBtnRead != tcEnBtnState)
      {
        tcEnBtnState = tcEnBtnRead;
        if (tcEnBtnState == HIGH)
          {
            enableTC = !enableTC;
          }
      }
  };
//TC Reverse Button Reading
if (tcRevBtnRead != tcRevBtnOld)
  {
    lastDebounce5 = millis();
  };
if ((millis() - lastDebounce5) > debounceDly)
  {
    if (tcRevBtnRead != tcRevBtnState)
      {
        tcRevBtnState = tcRevBtnRead;
        if (tcRevBtnState == HIGH)
          {
            reverseTC = !reverseTC;
          }
      }
  };

//Archive Btn Reads
frontBtnOld = frontBtnRead;
rearBtnOld = rearBtnRead;
tcFlashBtnOld = tcFlashBtnRead;
tcEnBtnOld = tcEnBtnRead;
tcRevBtnOld = tcRevBtnRead;
};

void getFrontData()
{
frontSerial.listen();
frontSerial.println('?');
delay(serWait);
if (frontSerial.available() > 0)
  {
  frontData = frontSerial.read();
  }
};

void processFrontData()
{
switch (frontData)
  {
  case 'F':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "*Flash* ";
  break;
  case 'L':
  lcdTop = "< Front | Rear  ";
  break;
  case 'R':
  lcdTop = "  Front | Rear >";
  break;
  case 'B':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "Lwr Only";
  break;
  case 'D':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "Driving ";
  break;
  case 'E':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = " Error  ";
  break;
  case 'G':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "Grl Only";
  break;
  case 'H':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "HaloOnly";
  break;
  case 'O':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "All Off ";
  break;
  case '@':
  lcdTop = lcdTopDefault;
  lcdBottomLeft = "   N/C  ";
  break;  
  case '?':
  sendFrontStatus = true;
  break;
}
};

void sendFrontSerial()
{
if (sendFrontStatus == true)
{
  switch (flashFront)
  {
  case true:
  frontSerial.println('1');
  break;
  case false:
  frontSerial.println('0');
  break;
  }
sendFrontStatus = false;
}
};


void processLCD()
{
//Format LCD1 Bottom Data
//BottomLeft to 8 Char
int leftL = lcdBottomLeft.length();
for (int i = leftL; i < 8; i++ )
  {
  lcdBottomLeft = lcdBottomLeft + " ";
  };
//BottomRight to 7 Char
int rightL = lcdBottomRight.length();
for (int i = rightL; i < 7; i++ )
  {
  lcdBottomRight = " " + lcdBottomRight;
  };
//Combine bottoms
lcdBottom = lcdBottomLeft + "|" + lcdBottomRight;

//Top to 16 Char
int tL = lcdTop.length();
for (int i = tL; i < 16; i++ )
  {
  lcdTop = lcdTop + " ";
  };

//Botom to 16 Char
int bL = lcdBottom.length();
for (int i = bL; i < 16; i++ )
  {
  lcdBottom = lcdBottom + " ";
  };
};

void writeLCD()
{
if (frontData != frontOld || rearData != rearOld || firstRun == true)
{
  lcd.setCursor(0,0);
  lcd.print(lcdTop);
  lcd.setCursor(0,1);
  lcd.print(lcdBottom);
  rearOld = rearData;
  frontOld = frontData;
}

//PRINT TO LCD2 FOR DEBUG
String f;
String r;
String tcf;
String tce;
String tcr;
if (flashFront == true)
{f = '1';} else {f = '0';};
if (flashRear == true)
{r = '1';} else {r = '0';};
if (flashTC == true)
{tcf = '1';} else {tcf = '0';};
if (enableTC == true)
{tce = '1';} else {tce = '0';};
if (reverseTC == true)
{tcr = '1';} else {tcr = '0';};
lcd2.setCursor(0,0);
lcd2.print("F  R TcF TcE TcR");
lcd2.setCursor(0,1);
String tempPrint = f + "  "+r+"   "+tcf+"   "+tce+"   "+tcr;
lcd2.print(tempPrint);
};

Code for “Front Controller” (Rear and TC will eventually be functionally similar but are not built/coded yet):

//Setup Software Serial
#include <SoftwareSerial.h>

SoftwareSerial serialPort(12,11); // RX, TX

//Customizables
bool combineInputs = true; //Make Halo/Grl/Lwr inputs all the same
int serWait = 50; //Wait for serial comms
int dlyTime = 85; //Speed of flash seq

//Pin Define
  //INPUTS
int LTurn = A0;
int RTurn = A1;
int Halo = A2;
int Grille = A3;
int Flash = A4;
int Lower = A5;
  //OUTPUTS
int RingL = 2;
int RingR = 3;
int RingYL = 4;
int RingYR = 13;
int LowerL = 5;
int LowerR = 6;
int GrilleL = 7;
int GrilleR = 8;
int Extra1 = 9;
int Extra2 = 10;

//Globals
int LTurnState;
int RTurnState;
int HaloState;
int GrilleState;
int FlashState;
int LowerState;
bool serFlashState;
char CurrentStatus;
char serialData;
bool sendData;

void setup()
{
//Begin Serial
serialPort.begin(19200);

//Set Pin Modes
  //Input
pinMode(LTurn, INPUT);
pinMode(RTurn, INPUT);
pinMode(Halo, INPUT);
pinMode(Grille, INPUT);
pinMode(Flash, INPUT);
pinMode(Lower, INPUT);

  //Output
pinMode(LowerL, OUTPUT);
pinMode(LowerR, OUTPUT);
pinMode(RingL, OUTPUT);
pinMode(RingR, OUTPUT);
pinMode(RingYL, OUTPUT);
pinMode(RingYR, OUTPUT);
pinMode(GrilleL, OUTPUT);
pinMode(GrilleR, OUTPUT);
}

void loop()
{
checkSerial();
processSerial();
readInputs();
configureStatus();
sendSerial();
checkMode();
//Either flashMode(); or normalMode(); initiated from above
};

void checkSerial()
{
serialPort.listen();
serialPort.println('?');
delay(serWait);
if (serialPort.available() > 0)
{
  serialData = serialPort.read();
}
};

void processSerial()
{
switch (serialData)
  {
  case '0':
  serFlashState = false;
  break;
  case '1':
  serFlashState = true;
  break;
  case '?':
  sendData = true;
  break;
  }
};

void readInputs()
{

LTurnState = digitalRead(LTurn);
RTurnState = digitalRead(RTurn);
HaloState = digitalRead(Halo);
GrilleState = digitalRead(Grille);
FlashState = digitalRead(Flash);
LowerState = digitalRead(Lower);

//Combine?
if (combineInputs == true)
{
  if (HaloState == HIGH || GrilleState == HIGH || LowerState == HIGH)
  {
    HaloState = HIGH;
    GrilleState = HIGH;
    LowerState = HIGH;
  }
}
};

void configureStatus()
{
  if (serFlashState == true)
  {
    CurrentStatus = 'F';
  }
  else if (LTurnState == LOW && RTurnState == LOW && HaloState == LOW && GrilleState == LOW && FlashState == LOW && LowerState == LOW)
  {
    CurrentStatus = 'O';
  }
  else if (FlashState == HIGH)
  {
    CurrentStatus = 'F';
  }
  else if (LTurnState == HIGH && RTurnState == LOW)
  {
    CurrentStatus = 'L';
  }
  else if (RTurnState == HIGH && LTurnState == LOW)
  {
    CurrentStatus = 'R';
  }
  else if (GrilleState == HIGH && HaloState == LOW && LowerState == LOW)
  {
    CurrentStatus = 'G';
  }
  else if (GrilleState == LOW && HaloState == HIGH && LowerState == LOW)
  {
    CurrentStatus = 'H';
  }
  else if (GrilleState == LOW && HaloState == LOW && LowerState == HIGH)
  {
    CurrentStatus = 'B';
  }
  else if (GrilleState == HIGH ||  HaloState == HIGH || LowerState == HIGH)
  {
     CurrentStatus = 'D';
  }
  else 
  {
      CurrentStatus = 'E';
  }
};

void sendSerial()
{
if (sendData == true)
{
serialPort.println(CurrentStatus);
sendData = false;
}
};

void checkMode()
{
//Check for Flash or Normal Mode
if (CurrentStatus == 'F')
{
  flashMode();
}
else
{
  normalMode();
}
};

void flashMode()
{
//First All Outputs LOW
  digitalWrite(RingL, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
  delay(dlyTime);
//Flash Cycle 1 - Stage 1
  digitalWrite(RingL, HIGH);
  digitalWrite(RingYR, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(GrilleR, HIGH);
  digitalWrite(LowerL, HIGH);
  delay(dlyTime);
  digitalWrite(RingL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  delay(dlyTime);
//Flash Cycle 1 - Stage 2
  digitalWrite(RingL, HIGH);
  digitalWrite(RingYR, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(GrilleR, HIGH);
  digitalWrite(LowerL, HIGH);
  delay(dlyTime);
  digitalWrite(RingL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  delay(dlyTime);
//Flash Cycle 1 - Stage 3
  digitalWrite(RingL, HIGH);
  digitalWrite(RingYR, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(GrilleR, HIGH);
  digitalWrite(LowerL, HIGH);
  delay(dlyTime);
  digitalWrite(RingL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  delay(dlyTime);
//Flash Cycle 2 - Stage 1
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, HIGH);
  digitalWrite(RingL, HIGH);
  digitalWrite(GrilleL, HIGH);
  digitalWrite(LowerR, HIGH);
  delay(dlyTime);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingL, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(LowerR, LOW);
  delay(dlyTime);
//Flash Cycle 2 - Stage 2
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, HIGH);
  digitalWrite(RingL, HIGH);
  digitalWrite(GrilleL, HIGH);
  digitalWrite(LowerR, HIGH);
  delay(dlyTime);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingL, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(LowerR, LOW);
  delay(dlyTime);
//Flash Cycle 2 - Stage 3
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, HIGH);
  digitalWrite(RingL, HIGH);
  digitalWrite(GrilleL, HIGH);
  digitalWrite(LowerR, HIGH);
  delay(dlyTime);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingL, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(LowerR, LOW);
//End of Flash Code
};

void normalMode()
{
switch (CurrentStatus)
{
case 'L':
  digitalWrite(RingYL, HIGH);
  digitalWrite(RingL, HIGH);
  digitalWrite(RingYR, LOW);
  digitalWrite(RingR, LOW);
break;
case 'R':
  digitalWrite(RingYR, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingL, LOW);
break;
case 'D':
  digitalWrite(RingL, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, HIGH);
  digitalWrite(GrilleR, HIGH);
  digitalWrite(LowerL, HIGH);
  digitalWrite(LowerR, HIGH);
  digitalWrite(Extra1, HIGH);
  digitalWrite(Extra2, HIGH);
break;
case 'H':
  digitalWrite(RingL, HIGH);
  digitalWrite(RingR, HIGH);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
break;
case 'B':
  digitalWrite(RingL, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, HIGH);
  digitalWrite(LowerR, HIGH);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
break;
case 'G':
  digitalWrite(RingL, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, HIGH);
  digitalWrite(GrilleR, HIGH);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
break;
case 'O':
  digitalWrite(RingL, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
break;
default:
  digitalWrite(RingL, LOW);
  digitalWrite(RingR, LOW);
  digitalWrite(RingYL, LOW);
  digitalWrite(RingYR, LOW);
  digitalWrite(GrilleL, LOW);
  digitalWrite(GrilleR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(LowerL, LOW);
  digitalWrite(LowerR, LOW);
  digitalWrite(Extra1, LOW);
  digitalWrite(Extra2, LOW);
break;
  }
//End of normal mode
};

what is taking so long for things to happen?

Could it be the multiple delay()s of 85 milleseconds each ? There are 12 of them in the flashMode() function alone amounting to a total delay of over one second

You seem to have 3 instances of SoftwareSerial. That is unlikely to work well - I’m surprised it works at all because only one instance can work at any one time.

For your sort of project I would treat one of the devices as master and connect all of the devices using HardwareSerial. If you put a diode on the Tx pin of each of the slaves oriented so it cannot pass 5v from the slave and put a pullup resistor on the Rx pin of the master (something like 5600 ohms would be fine) then all of the slaves will be able to receive data directly from the master and one slave at a time will be able to reply to the master.

The idea of the diodes is to prevent the slaves pulling the TX line HIGH - that is done by the pullup resistor. At the same time the diode allows a slave to pull the line low when it is sending data.

If the messages sent by the master include an ID for the slave the message is addressed to then when the slave receives its ID it will know it has permission to respond within the next N millisecs.

I am using this system with code from the 3rd example in Serial Input Basics - simple reliable ways to receive data.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

…R

UKHeliBob: Could it be the multiple delay()s of 85 milleseconds each ? There are 12 of them in the flashMode() function alone amounting to a total delay of over one second

I understand that the delay is obviously going to delay things a bit (thats what it does), so that is probably contributing to the problem. However, I don't see how a "total delay of over one second" would amount to parts of the program being delayed on the order of tens of seconds to even a full minute. I do intend, now, after some more research to re-write flashMode function with millis instead of delay, similar to "Blink without Delay", as I can see how all those delays that worked well in my early days of programming are not going to work forever, and I feel like this is definitely the time to learn to do it "right" with millis() so I will work on that and post here my results in the next few days.

Robin2:
You seem to have 3 instances of SoftwareSerial. That is unlikely to work well - I’m surprised it works at all because only one instance can work at any one time.

I guess I didn’t realize I couldn’t do this. I knew only one port would work at a time, but I thought the “master” (with all 3 instances of SwSerial) would send a “request” on one swserial port and wait to get a response on that port before moving to the next port and repeating the process. That is what I thought I was programming for but perhaps this was the wrong way to go about it.

Robin2:
If you put a diode on the Tx pin of each of the slaves oriented so it cannot pass 5v from the slave and put a pullup resistor on the Rx pin of the master (something like 5600 ohms would be fine) then all of the slaves will be able to receive data directly from the master and one slave at a time will be able to reply to the master.

So something like the attached crude schematic?

My plan moving forward is still to rewrite the flashMode() function to be millis instead of delay as well, but I guess I am just not entirely understanding of why the 3 serial ports doesn’t work as an option? I have parts on hand to try the master/slave single HW serial method, so I will definitely give that a go and let you know how it works out, but I would still like to understand if my 3 port method could be made to work, or if its just entirely the wrong thought process?

arduino.png

As a quick update, I did rewrite flashMode() to work without delays, and that improved the performance to an extent. Before I entirely change the hookup to a master/slave single HW serial, I plan to proceed with using the 3 software ports until I have a chance to actually hook the whole system together and see how it works (if for no other reason than pure curiosity). If there is a slight delay of even around 2-3s between pushing a button, the action happening, and the status updating on the screen, that is acceptable to me provided that the delay is consistent and predictable. The results I was getting previously were sporadic and inconsistent so obviously not acceptable.

That said, however, I will be building the final boards in such that I can switch them to the new configuration easily to test that as well. (As it stands currently, only the Front and Status display boards are in what was intended to be final versions. I should have no problem converting those over though as I always avoid pins 0/1 until needed as a last resort, so connecting to the HW serial wont be a huge issue. The TC board was from a previous unfinished iteration of this project and is going to be rebuilt anyway, and the rear board is buried in my vehicle running lights as a standalone unit that gets its “instructions” from an off-the-shelf wireless relay/remote, but will be integrated into this project eventually and probably get an entirely new board at that time).

New flashMode function:

//Globals
unsigned long startTime;
unsigned long currTime;
int count = 0;
const int dlyTime = 85; //Flash speed
const int blinks = 3; //Number of flashes per side in a cycle

//Setup
void setup()
{
//Other setup stuff here as well
startTime = millis();
}

void flashMode()
{
currTime = millis();
if (count < blinks * 2)
{
  if (currTime - startTime >= dlyTime)
  {
    digitalWrite(RingL, !digitalRead(RingL) );
    digitalWrite(RingYR, !digitalRead(RingYR) );
    digitalWrite(RingR, !digitalRead(RingR) );
    digitalWrite(GrilleR, !digitalRead(GrilleR) );
    digitalWrite(LowerL, !digitalRead(LowerL) );
    startTime = currTime;
    count++;
  }
}

if (count >= blinks * 2 && count < blinks * 4)
{
  if (currTime - startTime >= dlyTime)
  {
    digitalWrite(RingR, !digitalRead(RingR) );
    digitalWrite(RingYL, !digitalRead(RingYL) );
    digitalWrite(RingL, !digitalRead(RingL) );
    digitalWrite(GrilleL, !digitalRead(GrilleL) );
    digitalWrite(LowerR, !digitalRead(LowerR) );
    startTime = currTime;
    count++;
  }
}
if (count >= blinks * 4)
  {
    count = 0;
  }
};

Image from Reply #6 so we don't have to download it. See this Simple Image Guide

...R

Yes, that diagram is what I have in mind.

…R