Software serial.println seems to lag behind by 1 message

Hi I'm new to the forum so I hope this is the correct place to post.

What I trying to do is set up an ESP-01 to an Arduino Uno and then read commands over the Serial Port and write those commands to the ESP-01 via a software serial. The issue I seem to be having with my code is the Command seems to be one message behind. For example if I type AT into the serial port I see that monitor reads it and assigned it to command string but it didn't get sent to the ESP. If I hit enter again in the serial monitor then the previous AT command gets sent. And the expected response of OK is received. How do I correct this so that it does lag behind by one command. Thanks

/ Basic serial communication with ESP8266
// Uses serial monitor for communication with ESP8266
//
//  Pins
//  Arduino pin 2 (RX) to ESP8266 TX
//  Arduino pin 3 to voltage divider then to ESP8266 RX
//  Connect GND from the Arduiono to GND on the ESP8266
//  Pull ESP8266 CH_PD HIGH
//
// When a command is entered in to the serial monitor on the computer 
// the Arduino will relay it to the ESP8266
//
 
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(2, 3); // RX | TX

// Wifi configuration details
String _ssid = "yourSSID"; 
String mydata;
String message;
String response;
int cnt=0;

void setup() 
{
    Serial.begin(9600);     // communication with the host computer
    //while (!Serial)   { ; }
 
    // Start the software serial for communication with the ESP8266
    ESPserial.begin(9600);  
    
    Serial.println("");
    Serial.println("Remember to to set Both NL & CR in the serial monitor.");
    Serial.println("Ready");
    Serial.println("");   
    delay(1000);

    Serial.println(""); 
}
 
void loop() 
{

// Serial.flush();
 //ESPserial.flush();

  while(Serial.available()==0)
  {
    //Do nothing until something enters the buffer
  }

  if(Serial.available() > 0)
  {
    String command = Serial.readStringUntil('\n');
    Serial.println("Command Sent: " + command);
    message = readWifiSerialMessage(command);
    delay(1000);
    if(message.length() > 0)
    {
    Serial.println("Response Received:");
    Serial.println(message);
    Serial.println("---------");
    delay(100);
    }
  
  }

}


/*
* Name: readWifiSerialMessage
* Description: Function used to read data from ESP8266 Serial. 
* Returns: The response from the esp8266 (if there is a reponse)
*/
String  readWifiSerialMessage(String command){
  char value[100]; 
  int index_count =0;
  //Serial.println("Message Received:");
  ESPserial.println(command);
  // Serial.println();
  while(ESPserial.available())
  {
    value[index_count]=ESPserial.read();
    index_count++;
    value[index_count] = '\0'; // Null terminate the string
  }
  String str(value);
  str.trim(); //Removes any leading or trailing whitespace
  return str;
}

This is your issue. At 9600 baud you are only going to get 1 character per millisecond. Therefore you will exit this loop before receiving the first first character. By the time you hit the enter key again the "OK" string from the previous command has been buffered up and the while loop reads it.

If you want your code to be non-blocking you will need to restructure to a state machine. If not you will have to block to receive each response.

  while(ESPserial.available() == 0);
  String response = ESPserial.readStringUntil('\n');

You may want to implement a timeout in case there is no response you will not get stuck.

Thanks for the quick response. I tried just doing the code you recommended and you are right it just gets stuck in the while loop since nothing seems to enter the software serial buffer. So I tried adding a timeout to the while loop case but ESPserial.readStringUntil('\n') doesn't seem to return anything.

As for you State Machine comment are you suggesting I have a separate function for sending and receiving messages to and from the ESP module?
Thanks

String  readWifiSerialMessage(String command){
  ESPserial.println(command);
  Serial.println("Hi");
  long int time = millis();
  while( (time+1000)> millis())
  {
    Serial.println("Loop");
   String response = ESPserial.readStringUntil('\n');
  }
  Serial.println("Done");
  Serial.println(response);
  return response;
}

You should have the timeout in the loop waiting for available characters. Also your response variable was scoped inside the while loop so once you exited that loop you couldn't access it. It should not have compiled unless you had a global response variable.

Try this:

bool timeout = false;
unsigned long time = millis();
String response = "";
while(ESPserial.available() == 0)
{
  if((time+1000UL)> millis())
  {
    timeout = true;
    break;
  }
}

if (timeout)
{
    Serial.println("TIME OUT waiting for response!!!");
    // TBD: you might want to return a special sting here or something..
}
else
{
  response = ESPserial.readStringUntil('\n');
}

Thanks for the suggestion. Sorry for the delayed response. I'm not sure what to make of the issue now. I ran your suggestion and it always hits the TIME OUT logic (increased the time in the loop too) so why there isn't something in the buffer for ESPserial I'm at a lost. I'm going to try a couple more ideas but I wanted to give you a response as soon as possible.

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