Serial: Wait for response or Timeout

Hello,
I have two arduinos talking through serial. One is acting like an RS232 device(just simulating query response) and the other is sending the queries. I am trying to get the sending device programmed in a way that it will send the first command and wait for a response…then send the second command and wait for a response…etc. But I am receiving the following:

Response:

12123451234512345A
1234512345B
1234512345C
1234512345D
1234512345E

Sender Code:

int i = 0;
int lastSent = 0;
String readString;
char cmds[5] = {'1', '2', '3', '4', '5'};

void setup() {
  Serial.begin(9600);
}

void loop() {

  for (int i = 0; i < sizeof(cmds); i++){
    Serial.write(cmds[i]);
  }

  if (Serial.available() > 0)  {
  char c = Serial.read();  //gets one byte from serial buffer
    if (c == '\r') {
      Serial.println(readString); //prints string to serial port out
      readString = ""; //clears variable for new input
      Serial.flush();
      i++;
    } 
    else {     
      readString += c; //makes the string readString
    }
  }
  delay(5000);
}

Receiver Code:

void setup()
{
  // Set up both ports at 9600 baud. This value is most important
  // for the XBee. Make sure the baud rate matches the config
  // setting of your XBee.
  Serial.begin(9600);
}
void loop()
{
  String readString;
  if (Serial.available())
  { // If data comes in from XBee, send it out to serial monitor

      byte ch;
      ch = Serial.read();
      switch(ch){
        case '1': 
          Serial.write("A\r");
          break;
          
        case '2': 
          Serial.write("B\r");
          break;
          
        case '3': 
          Serial.write("C\r");
          break;
          
        case '4': 
          Serial.write("D\r");
          break;
          
        case '5': 
          Serial.write("E\r");
          break;
          
        case '6': 
          Serial.write("F\r");
          break;
        
        default:
          break;
      }
  } 
}

What I am looking to get is:

1A2B3C4D5E  

wait for say 20 minutes and repeat

Has anyone had to do this or has an example?

solveetcoagula07:

  for (int i = 0; i < sizeof(cmds); i++){

Serial.write(cmds[i]);
  }

I think you should add a delay in the for loop and immediately after it so that the sender has time to read the receiver output…

Nice code BTW!

Have a look at the examples in Serial Input Basics - simple reliable 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. Just use cstrings - char arrays terminated with 0.

Why not …

char cmds[] = "12345";

and later

Serial.print(cmds);

Or better still …

char cmds[] = "<12345>";

…R

      Serial.flush();

The "commands" are just one character, aren't they? Then why do you try to send all 5 commands before looking for a response?

Think about this as a state machine. Start in the initial "zero commands sent" state. Send a command, now you are in the "waiting for command 1 response" state. When you get that response, you can go forwards to the next state. If you detect that you've stayed in that state more than 5 seconds (or whatever) you can jump to another state - maybe start again from the top if one response is missng.

Thank you for the responses. Robin2 after looking at Serial Input Basics, Example 2 was exactly what I was looking for! Everything works perfect now except the timing(not as accurate as I would like).

If you post your code and your accuracy requirements, then we can help. There may be another method that will work better for you.

However, if it works, then it's probably time to stop playing with it and move on to the next project. Make sure you make an archive copy of this "adequately working" code because you may find you need to refer back to it one year from now.

#include <SoftwareSerial.h>
SoftwareSerial SoftSerial(10, 11);

int rcvCount = 0;

const byte numChars = 64;

char endStr[numChars];
char receivedChars[numChars];
char cmds[6] = {'1', '2', '3', '4', '5', '6'};

bool RTS = true;
bool newData = false;
bool executed = false;

void setup() {
    Serial.begin(9600);
    SoftSerial.begin(9600);
}

void loop() {
  recvWithEndMarker();
  showNewData();
  
  if(executed == false){
    gatherData();
  }
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\r';
    char rc, t;

    while (Serial.available() > 0) {
        t = Serial.read();

        if (t == 'A') {
          executed = false;
          RTS = true;
          rcvCount = 0;
        }
        else {

        }
    }
    
    while (SoftSerial.available() > 0 && newData == false) {
        rc = SoftSerial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            rcvCount++;
            RTS = true;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
      strcat(endStr, receivedChars);     
      if(sizeof(cmds) != rcvCount){
        strcat(endStr, ", ");   
      } else {
        Serial.println(endStr);
        endStr[0] = (char)0;  //clear the char array
        receivedChars[0] = (char)0;  //clear the char array
      }
        newData = false;
    }
}

void gatherData(){
  if(RTS == true){
    SoftSerial.write(cmds[rcvCount]);
    RTS = false;    
  }
  if(sizeof(cmds) == rcvCount){
    executed = true;
  }
}

There aren’t exactly any accuracy requirements. When I had the following code set to an interval of 900000 the arduino was losing somewhere between .5 and 1 second each loop. So I was thinking about using an RTC to pulse every 15 minutes. I would actually like to combine the two sets of code in the future.

#include <XBee.h>
#include <SoftwareSerial.h>

XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
ZBRxResponse rx = ZBRxResponse();

SoftwareSerial SoftSerial(10, 11);
bool RTS = true;
unsigned long previousMillis = 0;
long interval = 60000;

void setup() { 
  Serial.begin(9600);
  SoftSerial.begin(9600);
  xbee.setSerial(SoftSerial);
}

void loop() {
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval){
    previousMillis = currentMillis;
    sendCommands();
  }
  readSer();
}

void readSer(){
    xbee.readPacket();
    if (xbee.getResponse().isAvailable() && xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
        xbee.getResponse().getZBRxResponse(rx);
        // and an ascii representation
        for (int i= 0; i < rx.getDataLength(); i++){
          if (iscntrl(rx.getData()[i]))
            Serial.write("");
          else
            Serial.write(rx.getData()[i]);
            if(rx.getData()[i] == '\r'){
              RTS = true;
            }
        }
        Serial.println();
    }
    else if (xbee.getResponse().isError()) {
      Serial.print("There was an error.  Error code: ");
      Serial.println(xbee.getResponse().getErrorCode(),DEC);
    }
    else {
      // Do nothing
    }
}

void sendCommands(){
  if(RTS == true){
    uint8_t payload[] = {'A'};
    XBeeAddress64 addr64 = XBeeAddress64(1286656, 1086535364);
    ZBTxRequest zbTx = ZBTxRequest(addr64, 0xFFFE, 0x00, 0x00, payload, sizeof(payload), 0x00);
    xbee.send(zbTx);
    RTS = false;
  }
}

If you want accurate timing over a long period then an RTC is the way to go.

...R