Send serial commands and wait for respective replies

I am new to Arduino and have tried all kinds of code for attempting to achieve this. None with any luck, however. I feel that it should be a relatively easy task and therefore, figured that someone out there with more proficiency with an Arduino than me, would be able to help.

Essentially, I have two commands sent to a device via the Leonardo serial port. One is the single character "R", and the other is the single character "O". The device then sends back 8 binary bytes (non ASCII) in floating point format per command. So if I send O, it will return 8 binary bytes, and then the same goes for if I sent R.

The commands O and R need to be simultaneously sent via the serial every 250ms and wait for their respective responses before sending the next command.

I also need to store the device's response to O and the device's response to R in respective variables that will have a new value every 250ms. I am not familiar with single point format and therefore am unaware of what variable system to use.

Here is my best, yet unsuccessful attempt:

unsigned long previousMillis = 0;
const long interval = 250;
int responseO;
int responseR;

void setup() {

Serial.begin(9600);
while (!Serial);

}

void loop() {

unsigned long currentMillis = millis();

if (currentMillis - previousMillis >= interval) //timer for every 250ms
{

previousMillis = currentMillis;

Serial.println("R"); //Figured that "println" with a string for the character R should be ok
if(Serial.available() >0) //Don't know if I am correct here, I was hoping that the serial would only be read if the device responded to the command R
{responseR = Serial.read();} //Read serial for device's response to command R and save it in a variable

Serial.println("O"); //Do the same thing for the command O
if(Serial.available() >0)
{responseO = Serial.read()}

}

}
However, whenever I test this, it appears that the program is unable to differentiate between which responses are due to one command, and treats one response as if both commands requested it when only one did. Also is a floating point format variable just a float?

Thank you so so much, I really need some help this has been burning away at me for days........

Cheers, Harry

The commands O and R need to be simultaneously sent via the serial every 250ms and wait for their respective responses before sending the next command.

You can NOT send two characters simultaneously.

Sending these characters every 250 ms, and then waiting for replies, are mutually exclusive concepts.

Serial.println("R");               //Figured that "println" with a string for the character R should be ok

You figured that sending three characters, 'R', carriage return, and line feed, to a device that expects 1 is OK?

The device then sends back 8 binary bytes (non ASCII) in floating point format per command.

A float is 4 bytes on a Leonardo.

if(Serial.available() >0)
{responseO = Serial.read()}

Reading one byte is not going to get all 8 bytes.

Also on stackexchange.

Harry_Stuart:
I have two commands sent to a device via the Leonardo serial port.
...
Serial.begin(9600);

Do you realize that "Serial" is the virtual com port (USB) and not the hardware UART ("Serial1")? Unless the "device" you're talking about is the computer, you probably want to use "Serial1".

My approach would be:

  • flush receive buffer
  • send R
  • wait for 8 bytes (Serial.available() >= 8 ); or timeout (using millis())
  • if timeout, send R again
  • if successfully received 8 bytes, save them
  • flush receive buffer
  • send O
  • wait for 8 bytes or timeout
  • if timeout, send O again
  • if successfully received 8 bytes, save them
  • do something with the data you received
  • repeat

Please use `` tags when posting code.

Pieter

PaulS:

Serial.println("R");               //Figured that "println" with a string for the character R should be ok

You figured that sending three characters, 'R', carriage return, and line feed, to a device that expects 1 is OK?

How would I best send the single character R then? I am not sure. Again, I am unsure on how to go about this I am very new to coding.

Thanks, Harry

Harry_Stuart:
How would I best send the single character R then? I am not sure. Again, I am unsure on how to go about this I am very new to coding.

Serial.println(data) adds a newline after the printing the data, it's basically equivalent to

Serial.print(data); 
Serial.print("\r\n");

('\r' is a carriage return, CR and '\n' is a line feed, LF).

Use Serial.print('R');

Pieter

Thanks, I will change it all to Serial.print('R or O'). Is it normal for the serial monitor not to display a Serial.print()? For some reason, only Serial.println() actually show in the serial monitor for me. Also, if four bytes is a float, should I change my integer variables responseR and responseO to floats?

Harry

Harry_Stuart:
Is it normal for the serial monitor not to display a Serial.print()? For some reason, only Serial.println() actually show in the serial monitor for me.

No that's not normal. Please post the code that shows this behavior.

Why are you trying to use the serial monitor? How can it send an 8-byte binary float?

Pieter

I have been using the Bridge library and doing console.x rather than serial.x because I am using the Yun shield. Would that make a difference? Here is the modified code:

#include <Console.h>
#include <Bridge.h>

unsigned long previousMillis = 0;
const long interval = 4000;
String responseO;
String responseR;
int bytesToReadFromR;
int bytesToReadFromO;

void setup() {

Bridge.begin();
Console.begin();
while (!Console);

}

void loop()
{
    unsigned long currentMillis = millis();

    if(currentMillis - previousMillis >= interval) { //timer for every 250ms
        previousMillis = currentMillis;

        Console.print('O');               
        bytesToReadFromR = 8;              //mark that there is data to read from Serial for R

        Console.print('O');               
        bytesToReadFromO = 8;              //Do the same thing for the command O
    }   

    if(bytesToReadFromR){
        while(bytesToReadFromR && Console.available()){
           responseR[--bytesToReadFromR] = Console.read();       //Read serial for device's response to command R and save it in a char array
        }
        if(bytesToReadFromR){
             //finished transfer, trigger what you need
        }
    }
    if(bytesToReadFromO){
        while(bytesToReadFromO && Console.available()){
           responseO[--bytesToReadFromR] = Console.read();       //Read serial for device's response to command O and save it in a char array
        }
        if(bytesToReadFromO){
             //finished transfer, trigger what you need
        }
    }
}

Also, if four bytes is a float, should I change my integer variables responseR and responseO to floats?

It won't make any difference, since you are not collecting all 4 bytes and putting them in the proper place in the variables.

Harry_Stuart:
Essentially, I have two commands sent to a device via the Leonardo serial port. One is the single character "R", and the other is the single character "O". The device then sends back 8 binary bytes (non ASCII) in floating point format per command. So if I send O, it will return 8 binary bytes, and then the same goes for if I sent R.

The commands O and R need to be simultaneously sent via the serial every 250ms and wait for their respective responses before sending the next command.

I am building a project that has many similarities. In my project there is one master and a number of slaves (all connected by Serial, the master is a Mega). The user will operate switches connected to the Mega and it will send a command to a slave to do something (turn on an LED or move a servo). I am designing it so that the slave must respond and if there is no response within a timeout interval the whole thing comes to a halt. This is the code in my loop()

void loop() {
 readSwitches();
 updateSlaves();
 recv1WithStartEndMarkers();
 checkSlaveResponse();
 checkSlaveTimeout();
}

There is a state variable called waitingForResponse and when a command is sent (by the updateSlaves() function) that variable is set to the ID of the slave to which the command was sent. When the slave responds that variable is set to 'R' (for Ready) and only then can the next command be sent (to the same or another slave). As well as changing the variable to the ID of the slave the sending function also saves the value of millis() and that is used by the checkSlaveTimeout() function which keeps checking for a timeout as long as waitingForResponse is not 'R'

The code in recv1WithStartEndMarkers(); is exactly as in Serial Input Basics except that it works with Serial1.

Note that none of the functions called in loop() is a blocking function.

I have not yet experimented to find the ideal timeout interval (shorter is better) but it seems to be working with 20 millisecs.

...R