2
\$\begingroup\$

I have this Arduino Sketch:

#define UART_BUFLEN 50
char uartBuf[UART_BUFLEN] = { '0円' };
void setup() 
{
 Serial.begin(9600);
}
void loop() 
{
 int numBytes = Serial.available();
 int i = 0;
 for (; i < numBytes; i++) 
 {
 uartBuf[i] = Serial.read();
 }
 uartBuf[i + 1] = '0円';
 if (numBytes > 0) {
 Serial.print("Received: ");
 Serial.flush();
 Serial.print(uartBuf);
 Serial.flush();
 memset(uartBuf, '0円', UART_BUFLEN);
 }
}

When I type into the Arduino Console, something like "Hello" (without the "), the following output is generated:

Received: HReceived: ello

I know that the loop may execute way faster than my serial communication and thus there could be overlaps. However, I do call Serial.flush(), which should wait for the outgoing buffer to be empty. Why is it then still entering a second time and writing my messages so weirdly?

I could add a delay into my code, and then it somehow works fine. But that is not what I want. I want the input buffer to be completely read, then write "Received: " and then write the buffer.

I tried writing the buffer to the serial output to see what in there, and its really weird. I did it this way:

int x = 0;
while(uartBuf[x] != '0円' && uartBuf <= UART_BUFLEN)
{
 Serial.print(uartBuf[x++]);
}

It seems as if the '\n' is not recognized as a character and not read into the buffer. Then, the buffer is displayed (all '0円'), followed by the input I gave in the console - not the buffer with the input, but just the input, and then followed by the buffer with an '\n'`.

Even flushing the input buffer in between like this didn't work:

while(Serial.available())
{ 
 Serial.read();
}

Even doing something like this results in the same odd behaviour:

if (numBytes > 0) {
 char str[UART_BUFLEN + PREFIX_LEN + 1] = {'0円'};
 strcat(str, "Received: ");
 strcat(str, uartBuf);
 str[UART_BUFLEN + PREFIX_LEN] = '0円';
 Serial.print(str);
 Serial.flush();
 memset(uartBuf, '0円', UART_BUFLEN);
 }

And yes, I know this code is unsafe, but I this is a MWE. What am I doing wrong? I got this to work before, even with safety and all. But this is very odd behaviour in my opinion.

Also, code that worked before on another board (not Arduino) was something like this:

#define UART_BAUD_RATE 115200
#define UART_DATA_LEN 77
void setup()
{
 Serial.begin(UART_BAUD_RATE);
}
void loop()
{
 /* Check UART buffer */
 while(Serial.available())
 {
 char inChar = Serial.read();
 uartBuffer[uartBufferCursor++] = inChar;
 uartNewData = true;
 }
 if(uartNewData)
 {
 if(uartBufferCursor >= UART_DATA_LEN)
 {
 /* Do stuff with the buffer */
 /* ... */
 }
 // Clear UART Buffer
 memset(uartBuffer, '0円', UART_BUF_LEN);
 // Reset uartNewData
 uartNewData = false;
 uartBufferCursor = 0; 
 }
}
asked Apr 16, 2023 at 13:21
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Firstly, in the first code, this line:

uartBuf[i + 1] = '0円';

should be:

uartBuf[i] = '0円';

otherwise you would be including one byte of garbage in the buffer. You are being careful of zeroing the buffer, so it is probably not an issue.

Most importantly, you should not rely on the full command being available in the serial input as soon as the first byte is available. Some form of flow control should be implemented and, for the specific issue here, the message should be explicitly terminated. It could be as simple as searching for the '\n' character (or whatever byte is being transmitted when you hit "enter").

A possible flow to parse the input from the beginning of the command would look like:

  1. While there is a byte available, put it into the receiving buffer (one call to the 'loop' function may finish here, before the completed command is available)
  2. Is the received byte the command termination? If yes, stop filling the receiving buffer and break the loop to handle the command.
  3. Has the buffer filled before the termination was received? If yes, handle the situation accordingly.
  4. At the end of the 'loop' function: is there a complete command in the input buffer? If yes, handle it and clear the input buffer.
answered Apr 16, 2023 at 13:56
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thank you for your exhaustive answer! What you say makes sense and I should have known that. I will check on it once I am able to work on the project again. Thank you! \$\endgroup\$ Commented Apr 18, 2023 at 17:11
1
\$\begingroup\$

That's what your code does.

As soon as there is even one byte available, you go and print a long string that one byte has arrived and flush the transmit buffer.

Meanwhile your code waits fot transmit buffer to be sent, the rest of the bytes are received, and then you print them out.

If you don't want that, then do it differently. You seem to want to wait until a linefeed character is received before you print, then don't print until linefeed arrives.

answered Apr 16, 2023 at 14:33
\$\endgroup\$
1
  • \$\begingroup\$ Thank you, that makes sense! \$\endgroup\$ Commented Apr 18, 2023 at 17:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.