Delay until Serial TX/RX complete

Hi, I have modified a NCE usb interface to accept the RX and TX pins from Serial1 of my mega. I can send commands to my DCC trains without issue. The usb interface locks up if there are less than 35 millis delay between the commands.

I know flush() makes serial1 wait on the write but the NCE usb interface seems to lockup if more than one command is sent at once so it seems it doesn't like when its sending the ok back. The delay allows it to run but I want to be able to remove it if possible. Maybe after the transfer and receive has completed on the TX1 and RX1, but I'm not sure how to do that

The below code works as I want but obviously pauses the code, which I want to try to limit if possible.

void loop() {
        cmd_buf[0] = 0xa2;
        cmd_buf[1] = LOCO_H;
    cmd_buf[2] = LOCO_L;
    cmd_buf[3] = 0x02;
    cmd_buf[4] = fast;
    Serial1.write(cmd_buf, 5);
    Serial1.flush();
    delay(35);

    cmd_buf[0] = 0xa2;
    cmd_buf[1] = LOCO_H;
    cmd_buf[2] = LOCO_L;
    cmd_buf[3] = 0x01;
    cmd_buf[4] = slow;
    Serial1.write(cmd_buf, 5);
    Serial1.flush();
    delay(35);
}

Any help is greatly appreciated.

Hi there!

I am not entirely experienced with serial communication, but I believe there is something called a "carriage return" which I believe marks the end of a message being sent. You could probably program your device to wait for this carriage return before it sends its 'okay" message.

I'm sure there are articles on google that are way more informative than I, so give them a look!

Good luck

Are you saying the device sends an "OK" return?

Tocs: The usb interface locks up if there are less than 35 millis delay between the commands.

it doesn't like when its sending the ok back. The delay allows it to run but I want to be able to remove it if possible.

Maybe it would be sufficient to wait for the "OK" reply. Perhaps a "Serial1.readBytesUntil('\n', buffer, bufferLength);" between the commands would do the work. You could even look at the buffer to detect command failures.

Carriage return has no special meaning unless you treat is special. Aka, if the device does not, there is no use in using that.

If you just want to send messages 35ms apart you indeed have to delay them. You could use Serial.flush() and delay() if you don't want to do anything in the meantime. Otherwise, just switch to millis(). See Blink without delay.

The OK return currently is a -1 on the serial monitor, but earlier it was a 3. Changing the command doesn't seem to change the return, not sure what I did that changed it to -1. I will have to play around a bit more to see if I can get 'Serial1.readBytesUntil' to work. But I presume I will need to know the return before I can get this working correctly?

I know of the blink without delay but I want it to be based on the send/receive time not me using trial and error. With more testing it eventually locked up using 35 millis delay, so it would seem that the round trip can vary.

Yeah, but if the other end sends nothing back you just have nothing to go on...

Or is that "ok" send back by the other end?

Yeah the ok comes from the serial device but it seems to vary. I've had it report '3' back and '-1'. I will have to play with it more to see if I can get a constant result.

If you get -1 back from Serial.read() it means you try to read Serial without something being available. Aka, that's no response from the device.

bos1714: I believe there is something called a "carriage return"

There speaks someone who has never used or maybe even seen a typewriter

Tocs: The below code works as I want but obviously pauses the code, which I want to try to limit if possible.

Do you mean that you want to write your program so it leaves at least 35msecs betweem messages without using delay() and (perhaps) Serial.flush() ?

You can use Serial.availableForWrite() to see if the Serial Output Buffer is empty without waiting. It will return 64 when the buffer is empty.

And you can use millis() to manage timing without blocking as illustrated in Several Things at a Time. Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

Thank you all for your help, just been able to work through it and came up with a very efficient solution.

After using Serial1.available to read serial1 only when there was something to be read I worked out it returns 33 (0x21 hex) when the command was interpreted correctly.

In my below code it runs each command one after the other without the NCE usb interface locking up and it has pratically no pause between commands.

    byte return_buf[2];

    cmd_buf[0] = 0xa2;
    cmd_buf[1] = LOCO_H;
    cmd_buf[2] = LOCO_L;
    cmd_buf[3] = 0x02;
    cmd_buf[4] = fast;
    Serial1.write(cmd_buf, 5);
    Serial1.readBytesUntil(33, return_buf, 2);

    cmd_buf[0] = 0xa2;
    cmd_buf[1] = LOCO_H;
    cmd_buf[2] = LOCO_L;
    cmd_buf[3] = 0x01;
    cmd_buf[4] = slow;
    Serial1.write(cmd_buf, 5);
    Serial1.readBytesUntil(33, return_buf, 2);

Thanks