I have a sensor that writes data over serial about 10 times a second. This is going into the hardware RX of a nano. The hardware TX of the nano is going to an USB-serial converter to a PC. This is possible, because in neither case I need bidirectional communication and generally works fine.
The problem is, when data arrive on the RX from the sensor while a Serial.print() is ongoing (which can happen, I don't know when exactly the sensor will transmit) a subsequent call to Serial.available() does not return the actual number of bytes received, but 0 or at most 1 in rare cases.
Is this a bug in Arduino's Serial library?
No, it is a bug in your code...
Post your code.
Read the forum guidelines to see how to properly post code and some good information on making a good post.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.
Sorry, my fault. I forgot that Serial.print() isn't blocking. I was expecting it to take a certain time, which would have allowed the RX to finish.
if (Serial.available() > 0) {
Serial.print("PLACEHOLDER");
for (uint8_t i = 0; i < 9; i++) {
if (!Serial.available()) {
// premature end of frame; invalidate response
frame.h1 = 0;
DEBUG_Serial.print(i);
break;
}
//PORTB |= LED_S_PIN;
frame.bytes[i] = Serial.read();
//PORTB &= ~LED_S_PIN;
}
}
The PLACEHOLDER print is a placeholder for something useful that will be sent later. I thought it would take at least 11 "character" times to finish, which would have meant that all 9 sensor bytes should have arrived. Well, it obviously doesn't block. I found that after checking the RX/TX lines with a logic analyzer.
Two different "fixes": either "flush" the serial port (waits for all bytes to be sent) or wait after every byte read for the time it takes to receive one byte (about 90µs at 115200 baud).
if (Serial.available() > 0) {
Serial.print("PLACEHOLDER");
Serial.flush(); // <- this or
for (uint8_t i = 0; i < 9; i++) {
if (!Serial.available()) {
// premature end of frame; invalidate response
frame.h1 = 0;
DEBUG_Serial.print(i);
break;
}
//PORTB |= LED_S_PIN;
frame.bytes[i] = Serial.read();
delayMicroseconds(BYTE_TIME); // <- or that
//PORTB &= ~LED_S_PIN;
}
}
Receiving and transmitting data using serial are handled independently of each other, the only time transmitting blocks is if you try to send more characters than the Tx buffer can hold. By trying to write your Rx code to be in some way dependent on what you transmit you are tying yourself in knots and storing up problems, treat Rx and Tx as independent.
if (Serial.available() > 0) {
Guarantees 1 character is waiting to be read from the buffer, it does not guarantee any more than 1, but there might be more. Remember that characters come in very slowly in comparison to how fast the processor can do stuff, it is foolish to wait around for more characters to arrive; save them one at a time as they come in and let the program go off and do other stuff while the others arrive.
Have you read Serial Input Basics - updated ? It's a very good introduction to serial and certainly better than anything I could tell you.
[Edit]
I see nothing in your code that really checks to see if all the data has arrived, you need something to distinguish either the start or end (or both) of the data, such as a null (0x00) at the end or perhaps a $ at the start. Robin's tutorial covers this kind of thing. You can't just assume all the data has / has not arrived because some time interval has elapsed.
+1 for Robin2's serial input basics.
You have quite a few problems with both of those code snippets. Neither will be reliable for any length of time, as they do not deal with the many vagaries of real-world serial data transfer.
You REALLY need to read the Serial Input Basics thread at the top of the forum before going any deeper down the current rat hole.
There isn't really anything I didn't already know on the Serial Input Basics page. Waiting for certain signature bytes to start a frame, converting binary numbers and bitmasking, even checksum calculations are all there in my code, just not in the snippet above, because they are not relevant for the problem. My only problem was forgetting that "Serial.print" doesn't block. I am switching between different microcontrollers, computer OSs, software frameworks and programming languages a lot depending on the project. So one of these "details" is easily lost on me. On the positive side: I've always got something to learn (anew ).
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.