Pages: [1]   Go Down
Author Topic: Converting Incoming Serial Data to a String  (Read 1476 times)
0 Members and 1 Guest are viewing this topic.
England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
« Last Edit: July 07, 2011, 07:32:52 am by roryc » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  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.
Logged

England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your code simply needs to add one line and remove one line.
Code:
  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
Logged

England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My solution was to remove the array entirely.

Code:
String getCommand()
{

  String output;

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

  return output;

}

This seems just as effective, but simpler.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
char incomingSerialData[32];
getCommand(incomingSerialData);
// Now, incomingSerialData contains the data, NULL terminated
Logged

England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a huge help - again, thank-you, Paul.

I've inserted your code like so:

Code:
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?
« Last Edit: July 07, 2011, 09:05:48 am by roryc » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48569
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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].
Logged

England
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That makes sense. Thanks Paul!
Logged

Pages: [1]   Go Up
Jump to: