Go Down

Topic: Converting Incoming Serial Data to a String (Read 1 time) previous topic - next topic

Rory C

Jul 07, 2011, 01:22 pm Last Edit: Jul 07, 2011, 02:32 pm by roryc Reason: 1
Hi,

I'm attempting to take incoming data from the serial port, convert it into a string object, then print it once to the serial monitor. My code is below, and should clarify what I'm trying to do.


Code: [Select]
void setup()
{
 Serial.begin(9600);
}

String get()
{

 char incomingSerialData[25]; // A character array to store received bytes
 int incomingSerialDataIndex = 0; // Stores the next 'empty space' in the array

 while(Serial.available() > 0)
 {
   incomingSerialData[incomingSerialDataIndex] = Serial.read(); // Add the incoming byte to the array
   incomingSerialDataIndex++; // Ensure the next byte is added in the next position
 }

 return incomingSerialData;

 Serial.flush(); // Clear the serial buffer

}

void loop()
{

 String command = get(); // Calls the 'get' function

 if(command.length() > 0) // If there is a command, print it
 {
   Serial.println(command);
 }

}


The results are unexpected. Any text sent to the Arduino is repeatedly printed to the serial monitor, despite using Serial.flush() to remove it from the buffer. Also, the beginnings and ends of strings are often cut off.

If anybody knows how to do this, I'd be really grateful for any suggestions on improving my code.

Thanks!


Update: Fixed this on my own.

PaulS

Code: [Select]
  while(Serial.available() > 0)
  {
    incomingSerialData[incomingSerialDataIndex] = Serial.read(); // Add the incoming byte to the array
    incomingSerialDataIndex++; // Ensure the next byte is added in the next position
  }

  return incomingSerialData;

  Serial.flush(); // Clear the serial buffer

When the while loop ends, the serial buffer is empty. Flushing it after that is a sign that the programmer is clueless (about serial processing).

Putting executable code after the unconditional return statement is another clue.

Not properly terminating the character array is another. That the String class manages that to your satisfaction is pure luck on your part. I would not count on that luck holding.

In my opinion, you have a ways to go.

Rory C

I'm experienced with PHP, but completely new to Arduino as a platform. Dealing with processing and handling text on such a fundamental level is a new area to me.

Anyway, thank-you for the advice.

PaulS

Your code simply needs to add one line and remove one line.
Code: [Select]
  while(Serial.available() > 0)
  {
    incomingSerialData[incomingSerialDataIndex] = Serial.read(); // Add the incoming byte to the array
    incomingSerialDataIndex++; // Ensure the next byte is added in the next position
     incomingSerialData[incomingSerialDataIndex] = '\0'; // Add this line
  }

  return incomingSerialData;

  // Remove this one

Rory C

My solution was to remove the array entirely.

Code: [Select]
String getCommand()
{

  String output;

  while(Serial.available())
  {
    delay(5);
    output += char(Serial.read());
  }

  return output;

}


This seems just as effective, but simpler.

PaulS

Quote
This seems just as effective, but simpler.

Until you examine scope. The variable output goes out of scope when the function ends, so its destructor will be called. But, you returned that object. What exactly did you return? When will that memory get overwritten?

What you were doing before was creating and returning a new object, which is far safer.

Even better, though, is to use a reference variable (the array to store the data in) as input to the getCommand() function, which would then have a void type.
Code: [Select]
void getCommand(char *&incomingSerialData)
{
  int incomingSerialDataIndex = 0; // Stores the next 'empty space' in the array

  while(Serial.available() > 0)
  {
    incomingSerialData[incomingSerialDataIndex] = Serial.read();
    incomingSerialDataIndex++; // Ensure the next byte is added in the next position
    incomingSerialData[incomingSerialDataIndex] = '\0';
  }
}


Then:
Code: [Select]
char incomingSerialData[32];
getCommand(incomingSerialData);
// Now, incomingSerialData contains the data, NULL terminated

Rory C

#6
Jul 07, 2011, 04:00 pm Last Edit: Jul 07, 2011, 04:05 pm by roryc Reason: 1
This is a huge help - again, thank-you, Paul.

I've inserted your code like so:

Code: [Select]
void getCommand(char *&incomingSerialData)
{

 int incomingSerialDataIndex = 0;

 while(Serial.available())
 {
   incomingSerialData[incomingSerialDataIndex] = Serial.read();
   incomingSerialDataIndex++;
   incomingSerialData[incomingSerialDataIndex] = '\0';
 }

}

void loop()
{

 char incomingSerialData[32];
 getCommand(incomingSerialData);

}


But there are errors when I compile:

Control:38: error: invalid initialization of non-const reference of type 'char*&' from a temporary of type 'char*'
Control:18: error: in passing argument 1 of 'void getCommand(char*&)'


Is this something I'm doing?

PaulS

Removing the & in the function declaration allows the code to compile. In the case of passing an array to a function, for the function to fill, passing by reference is not really required, since arrays are passed by reference by default.

Rory C

I'm vaguely familiar with those concepts. Final question, then. I need to clear the array to allow for new content being passed to it. Is a loop that clears each row one by one the best way to do this?

PaulS

A string in C/C++ is a NULL terminated array of characters. A NULL in any position in the array terminates the array.

Calling that function sets the index to 0, writes in the 0th position, and puts a NULL in the 1st position.

You shouldn't need to initialize the array before calling that function again. If you have some other need, though, simply put a NULL ('\0') in array[0].

Rory C


Go Up