Serial.read question

Hello,

I've just started a new project. I have a game pad that communicates with my arduino using a VB.net interface.

The data that is send to the arduino looks something like this (depending on what button is pressed): ~ButtonLeft#

Where ~is the Header, # is the footer and ButtonLeft is the button being pushed on the game pad.

I use the following code to read the serial data, but something goes wrong and at the moment I am completely lost....... :-?

const char HEADER = '~';
const char FOOTER = '#';

// Serial read constants
const byte INPUT_MAX_LENGTH = 10; 

//Serial read variables 
char StringIn[INPUT_MAX_LENGTH] = {
  '\0'};

void ReceivedSerialData(){

  if(Serial.available() > 0) {

    char IncomingByte = 0;
    char CharIn = 0;

    IncomingByte = Serial.read();

    if (IncomingByte == HEADER) {

      int i = 0;//index of char array

      StringIn[i++] = HEADER; //add the header to the char array

      do {
        CharIn = Serial.read();
        StringIn[i++] = CharIn;
      } 
      while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1); //we can not exceed the MAX_LENGTH

      for (int j=i; j<INPUT_MAX_LENGTH; j++) {
        StringIn[j] = '\0';    // null out string
      }
      Serial.flush();
    } 
  }
}


void setup()
{
  Serial.begin(9600);
  Serial.print("~SetupOK#");
  Serial.flush();
}

void loop(){
  ReceivedSerialData();
}

The problem is if I send ~test# in the arduino serial monitor it is displayed the right way, but right after the display of ~test# a lot of rubbish is printed?

What's wrong with the code? It is a modified version from a previous project and a far as I can see, it looks OK ( but I've been staring to it for a long time......). So a fresh look will help :stuck_out_tongue:

You only check that there are any available bytes in the serial buffer when you read the header.

You should also check (with serial.available() ) before this statement:

CharIn = Serial.read();

Arduino is very fast compared to serial communication, so there might not be any bytes ready when you request it.

I do check serial.available :slight_smile:

void ReceivedSerialData(){

  if(Serial.available() > 0) {

remaining code......

Perhaps the code is a bit buggy so other suggestions are very welcome!!

We should get sticky posts on topics like this, I think many people are looking for similar code.

Cheers.

You checked that there was at least one byte to read.

How many characters do you then read?

do {
        CharIn = Serial.read();
        StringIn[i++] = CharIn;
      }
      while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);

All this code comes after you made sure that there was some data. There may have been only one byte available, which was the header.

This is unnecessary:

for (int j=i; j<INPUT_MAX_LENGTH; j++) {
        StringIn[j] = '\0';    // null out string
      }

One NULL is sufficient. Printing will stop when the first NULL is encountered.

Why are you doing this?

Serial.flush();

Any pending serial that has not yet been read just got dumped. Unless you know what you are doing, and there is a real reason to do this, don't.

The problem is if I send ~test# in the arduino serial monitor it is displayed the right way, but right after the display of ~test# a lot of rubbish is printed?

I don't see where you are printing the received data.

I want to read characters until the FOOTER ("#" ). That what I am doing using this code I assume:

do {
        CharIn = Serial.read();
        StringIn[i++] = CharIn;
      }
      while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);

Ok, so only one NULL ('/0') is necessary in an array of chars. Should this be after the last char in the array or at the last position of the array?

Serial.flush();

The Serial.flush(); was just a desperate attempt to stop the Arduino from printing rubbish.

Another thing: The serial.available() can hold 128 bytes. What will happen when more characters are send to the Arduino (200)? Will it overflow and cause a reset for example? Or will byte 129 until 200 be lost?

Well the printing code code lost when i made this post... It looks like this:

Serial.print("~")
for (int j=0; j=INPUT_MAX_LENGTH; j++) {
        Serial.print(StringIn[j])
      }
Serial.print("#")

The rubbish is probably the monitor's attempt to interpret all the null characters or 0xFFs you're printing.

Ok what is the best approach to optimize the code? I have defined the serial.read(); variables and char, is this really necessary?

Do you have any other suggestion?

Thanks in advance.

do {
        CharIn = Serial.read();
        StringIn[i++] = CharIn;
      }
      while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);

For reading serial data, a do/while loop is really a bad idea. The reason is that the body of the do/while loop is executed at least once. In the case of reading serial data, it might be that the body should not be executed at all, in the case of there being no data to read.

Instead, use a plain while loop.

CharIn = '\0';
while(Serial.available() > 0 && CharIn != FOOTER && i<INPUT_MAX_LENGTH-1)
{
   CharIn = Serial.read();
   StringIn[i++] = CharIn;
   StringIn[i] = '\0'; // Append a NULL so the string is NULL terminated
}

Hi Paul and all other Arduino users,

based on you suggestions I've modified the code. Please note that I am not an professional coder!! The code may contain some non efficient structure. But I just want to show it and share it.

If you have got any suggestions (more efficient routine) please let me know.

Thanks a lot!!

Cheers.

/*This example reads serial data. 
 The serial data should contain a one character header and a  one character footer.
 */

// Header and Footer
const char HEADER = '~';
const char FOOTER = '#';

// Maximum number of elements allowed in StringIn
const int INPUT_MAX_LENGTH = 30;

//Serial read variables
char StringIn[INPUT_MAX_LENGTH] = {
  '\0'};

void setup()
{
  Serial.begin(9600);
  Serial.println("~SetupOK#");
  Serial.flush();
}

void loop(){

  if(Serial.available() > 0) {

    // Read the first byte in the buffer
    char IncomingByte = Serial.read();

    Serial.println(IncomingByte);

    // Check if first char is footer
    if (IncomingByte == HEADER) { 

      Serial.println("Header found!!"); //Debugging code

      int i = 0;//index of char array

      StringIn[i++] = HEADER; //add the header to the char array

      // This loop reads the remaining bytes based on certain criteria.
      while(Serial.available() > 0)

      {
        //Check if String in still has elements available. If not array will be termindated
        if (i != (INPUT_MAX_LENGTH - 1)){

          //If serial data is in buffer read the next char
          IncomingByte = Serial.read();

          Serial.println(IncomingByte);

          // Check if read char is footer, if yes add to array and add NULL
          if (IncomingByte == FOOTER) {

            Serial.println("Footer found!!");

            StringIn[i++] = FOOTER; //add footer to the char array
            StringIn[i++] = '/0'; // add NULL

            Serial.println(i); // print the amount of elemnts in array. Debugging code.

            // Print the array. Debugging code
            for(int j=0; j < i ; j++){
   
              Serial.println(StringIn[j]);
            }

            break; // stop the while loop
          }

          // No footer found yet but character in between. It will be added to the array.
          else
          {
            Serial.println("Other char added to array!!"); //Debugging code
            StringIn[i++] = IncomingByte;
          }
        }

        // Array full. Probably no footer found.
        else
        {
          StringIn[i++] = '/0'; // add NULL
          Serial.println("~Warning: Array overflow, no footer found!! Serial buffer flushed!!#");
          Serial.flush();
          break; // Break the loop.
        }
      }
    }
  }
}

I only had a quick scan of your sketch, but I'd say it's too complex.
Look at the level of nesting of "if"s and "while"s - it's difficult to follow.
I don't think the "flush" is necessary.

Maybe think about how you'd implement this, if all you had was a single function "getChar" that returned a single, received character.

(and maybe try to implement that function)

Hi AWOL,

I have to admit that this code is probably too cumbersome!! My coding skills are just to basic...

The problem is I want to keep the header and footer check routine and I want to check if the array is overflows. With my skills this is the only way.

Maybe you can give me some suggestions how to create the function (I have never made one before...)

I need to learn how to code more efficient.... :-/

Thanks in advance,

Cheers