Serial Comms Help

Hi guys,

I'm currently linking 2 arduinos with one being a 'control panel' sending data to the second and the second displaying the data on an LCD screen,

I am trying to send the position of two switches, in this case 1 and 2 (for each switch, only have both in 1 or 2 at the minute), to arduino 2 and printing text relative to the switch position the screen,
I'm having success in one state however I am looking for it to update as the switches are changed but that currently requires a reset of arduino for it to update, any help would be appreciated,

this is the first arduinos code (runs as a test for now)

char test;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial1.begin(9600);
  pinMode(30, INPUT);        //first toggle switch - Feed Through
  pinMode(32, INPUT);        //third toggle switch - Auto Drill

}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(30) == 1 && digitalRead(32) == 1) {

 test = '1';
    Serial1.print(test);
   delay(100);

  }
  else/* if(digitalRead(30) != 1 && digitalRead(32) != 1)*/ {

test = '2';
 
    Serial1.print(test);
    delay(100);
  
  }
}

the section ofarduinos 2 code reading the serial is inside a function that is treat as one of the pages of the LCD screen,

void UserInputs() {
  CurrentPage = 2;
  tft.fillScreen(WHITE);

  tft.setCursor(95, 20);
  tft.setTextColor(BLACK);
  tft.setTextSize(2);
  tft.print("Input Check");

  tft.drawLine(93, 35, 226, 35, BLACK);

  tft.setCursor(19, 80);
  tft.setTextColor(BLACK);
  tft.setTextSize(1);
  tft.print("     Drilling Type: ");

  tft.setCursor(20, 120);
  tft.setTextColor(BLACK);
  tft.setTextSize(1);
  tft.print("Drilling Direction: ");

  tft.fillRect(180, 180, 70, 40, BLUE);
  tft.drawRect(180, 180, 70, 40, BLACK);
  tft.setCursor(191, 191);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print("Next");

  tft.fillRect(70, 180, 70, 40, BLUE);
  tft.drawRect(70, 180, 70, 40, BLACK);
  tft.setCursor(81, 191);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print("Back");

   if (Serial1.read() == '1') {

tft.setCursor(150,80);
tft.setTextColor(BLACK, WHITE);
tft.setTextSize(1);
tft.print("Automatic");
tft.setCursor(150,120);
tft.setTextColor(BLACK, WHITE);
tft.setTextSize(1);
tft.print("Forward");

    
  }
  else if (Serial1.read() == '2'){
    tft.setCursor(150,80);
tft.setTextColor(BLACK,WHITE);
tft.setTextSize(1);
tft.print("MANUAL");
tft.setCursor(150,120);
tft.setTextColor(BLACK,WHITE);
tft.setTextSize(1);
tft.print("BACKWARD");
  }


}

and that is called from inside the loop function as follows

else if (CurrentPage == 2) {

  
      if (p.x > 70 && p.x < 140 && p.y > 180 && p.y < 220) { //back button commands
        ContinuityCheck();
      }
      else if (p.x > 180 && p.x < 250 && p.y > 180 && p.y < 220) { //next button commands
        SkullDepth();
      }
    }

apologies if I haven't explained it great,

any help is greatly apreciated,

thank you

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication.

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

You should NOT have the serial comms code inside some other code - it will eventually come back to bite you by making debugging very difficult. Have a separate function for receiving the data and another function for updating the display. That way you can test them separately.

And please post complete programs rather than snippets.

...R

Hi Robin,

thanks for the reply, I'll have a look now although it's where I looked when I first started and may have exhausted it unless I'm being dumb,

I couldn't post the full code as it surpassed the 9k character limit, apologies

Smiteh:
I couldn't post the full code as it surpassed the 9k character limit, apologies

Then add your .ino file as an attachment.

Even better would be to make a short program that illustrates the problem you want help with.

...R

Don't do this...

if (Serial1.read() == '1') {
  ...
else if (Serial1.read() == '2') {

There are several big problems with this code. First, the Serial.read() takes one incoming character out of the buffer. So the second read will be reading a different character. In your communication scheme there is a continuing stream of 1s and 2s so not really a big problem so long as you realize that they can both be false if you read a 2 followed by a 1.

Read once then compare that value to all the different options expected.

Second, Serial is glacially slow compared to the Arduino's processing speed. The code you have between those two reads will run in just a few microseconds. There is not enough time for the second character to finish transmitting.

Related to this, your sender has a delay(100). That is a hundred thousand microseconds. So there definitely won't be a character available to read at the second if().

That is why we don't read in 2 places.

Third, because we have established how slow Serial is, you should always check Serial.available() before every read.

Fourth, it appears you are only looking at Serial when your display is on page 2. When you are on other pages, the buffer will fill up and start discarding data. Then when you get to page 2, you are reading data from the buffer which could be minutes or hours out of date.

The "one place" that you do Serial.read() should be hit on every loop, thousands of times per second.

While Robin's advice is excellent, your single-character communication scheme does not require that complexity. You can fix these problems relatively easily without starting over.

Hi guys,

as per Robins help yesterday, I have changed the code to the following

void recvOneChar() {

  if (Serial1.available() > 0) {
    receivedChar = Serial1.read();
    newData = true;
  }
}

void showNewData() {

  if (newData == true && Serial1.read() == '1') {
    tft.setCursor(150, 80);
    
    tft.setTextColor(BLACK, WHITE);
    tft.setTextSize(1);
    tft.print("Automatic  ");
    tft.setCursor(150, 120);
    tft.setTextColor(BLACK, WHITE);
    tft.setTextSize(1);
    tft.print("Forward  ");
  
    newData = false;
  }
  else if (newData == true && Serial1.read() == '2') {
    tft.setCursor(150, 80);
    
    tft.setTextColor(BLACK, WHITE);
    tft.setTextSize(1);
    tft.print("Manual    ");
    tft.setCursor(150, 120);
    tft.setTextColor(BLACK, WHITE);
    tft.setTextSize(1);
    tft.print("Backward  ");
    newData = false;
  }


}

the function in the currentpage == 2 function is now

while (Serial1.available() > 0){
  recvOneChar();
  showNewData();
}

which fixed the problem, however would only work when the switches were flicked a few times and then stop working, my Arduino knowledge is somewhat limited and am therefore struggling to find a solution to this as well,
I feel my error lies in my shownewdata function as I'm not checking Serial1.available() or am i completely wrong?,

I have attached the ino file for your viewing

Project_Arduino_2.ino (14.9 KB)

if (newData == true && Serial1.read() == '1') {

If there was new data (recieved some time ago) AND there's a 1 in the incoming buffer, then do something. WRONG.

If there was new data, act upon that new data and then set newData to false to indicate that you did the action. Perhaps you meant to write...

if (newData == true && receivedChar  == '1') {

You are not approaching the serial input properly.

Your function recvOneChar() should be called from loop() like in my example code and the other functions in your program should also be called from loop(). Also your code should be designed to allow loop() to repeat frequently - at least 20 times per second. Faster would be better.

Have a look at how the code is organized in Planning and Implementing a Program. Note how there is very little code in loop() - it is just an overview of the whole program. Also note how each function runs very briefly and returns to loop() so the next one can be called. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R