Reverse questionmarks on serialmonitor output

Hi. I wrote some code that's basically a modified version to the default "serial input reader" sample code, and it currently looks like this.

// Example 2 - Receive with an end-marker

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");
}

void loop() {
  recvWithEndMarker();
  showNewData();
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '3';
  char rc;
  while (Serial.available() > 0) {
    rc = Serial.read();
    while (rc != endMarker) {
      Serial.println(rc);
      receivedChars[ndx] = rc;
      ndx++;
      rc = Serial.read();
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    receivedChars[ndx] = '\0'; // terminate the string
    ndx = 0;
    newData = true;
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
    newData = false;
  }
}

The following is the output when I input "2223" into the serial input.

Per my own understanding, the code should stay in the while loop as long as rc is not equal to '3'. However, the line rc = Serial.read(); seems not to be reading the input characters properly and I am not sure why.

My understanding is also that Serial.read() should make rc read the individual characters when it is called. Please let me know if more information is needed to solve this issue. I am using Arduino Uno.

In regards to the common solutions: I am using a baud rate of 9600. Increasing it did not help.

Check you baud rate on the IDE serial monitor (lower right corner) and the program. 9600 is low. 19200 is usually the minimum and most of us use 115200.

I have tried increasing it to 115200 previously. Sadly, it didn't help.

Your problem is provably the second Serial.read that you do. You shoukd only use one Serial.read on that function.

By "that function" do you mean the while (Serial.available() > 0) loop? Or recvWithEndMarker()? I will try to remove a dual Serial.read while maintaining the intent of running the read code in a loop.

Why should we only use one Serial.read on that function?

See Serial input basics - updated

Check example 2 and compare it with your code

Note how recvWithEndMarker() in Robin's code has an if/else to ensure that the string is terminated when the end marker is received and yours doesn't

Yes, I am aware of this, I modelled my code after Robin's and the purpose of this code was to try to replicate the if-else with a while loop that breaks when the end marker (I used '3' in my code as my end marker). What I don't understand is why the input received is a reversed question mark.

Per my understanding, Serial.read() will print the received character into a char and a reversed question mark or -1 output means Serial.read cannot comprehend the input. If there is an issue with string termination, shouldn't the output be something like "222?????????" and not "????????", since the string termination issue should only apply (I think) after the string stops having things to read. Unless string termination also affects Serial.read, which is a consideration not listed in the documentation.

When you do the second

      rc = Serial.read();

you do so without knowing if there is actually something to read

Serial comms is slow compared to the speed at which the processor works so it is more than likely that there will not be a second character to read at that point so you read -1 This will repeat rapidly until ndx equals numChars and the inner while loop is terminated

Your fundamental mistake seems to be the outer while loop that causes the inner while loop to start when it has no reason to

1 Like

Thank you all for your assistance, especially UKHeliBob. I've modified the code accordingly and this works. I have added an extra if-statement that would allow the input to be read only if there is one.

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '3';
    char rc;
    
    while (newData == false) {
      if(Serial.available() > 0){
        rc = Serial.read();

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

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

Why not simply use Robin's code ?

As it is you have created blocking code by using

while (newData == false)

That might be OK in this instance but is not such a good idea generally

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.