Serial.read() to string?

So I decided to make some more advance "talking" with my arduino and I found a piece of code which I transform into this:

char inData[20]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character
String reads;
int words = LOW;


void setup(){
  Serial.begin(9600);
}


void loop()
{
   while(Serial.available() > 0)
   {
       if(index < 19) // One less than the size of the array
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           inData[index] = '\0'; // Null terminate the string
       }
       words = HIGH;
   }
   
   for(int i=0; i<=index; i++)
       {
         reads += inData[i];
         inData[i] = 0;
       }
   
   delay(10);
   if(words)
   {
     Serial.println(reads);
     words = LOW;
     reads = "";
   }
   
   
   index = 0;
   
}

the thing is that in the serial monitor the words that I wrote and send to the arduino get all scattered on the serial monitor separated by spaces like this:
test test
test test t
est
something like that, how can I make it so that they come like:
test
test
test
...
???

Thanks

You need to wait for the string to finish by detecting a string terminated like a CR.
Only when the string is all in should you attempt to print it out.
You are thinking that if one byte of the string has arrive then they all have. They have not.

Thanks for replying,
I understand the logic, but what is a CR?

Carriage Return
Look at the options for line ending in the Serial Monitor.

I see it, I selected it, but how do I use it?

Set it to Carriage Return and test for '\r' in the incoming serial data or set it to Newline and test for '\n'

See http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=11425&page=1

So after looking at that code I made some litle modfications to my and here it is:

char inData[20]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character
String reads;
int words = LOW;


void setup(){
  Serial.begin(9600);
}


void loop()
{
   while(Serial.available() > 0)
   {
       if(index < 19) // One less than the size of the array
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           inData[index] = '\0'; // Null terminate the string
       }
       words = HIGH;
   }
   
   for(int i=0; i<=index && inChar=='\n'; i++)
       {
         reads += inData[i];
         inData[i] = 0;
       }
   
   delay(10);
   if(words && inChar=='\n')
   {
     Serial.println(reads);
     words = LOW;
     reads = "";
   }
   
   
   index = 0;
   
}

Now the first word is on the right place but the second gets again scattered.
How can I fix that?

You're reading the data into a string (a null terminated array of chars). Why are you then creating a String (a memory fragmenting object) out of what you read? Why not just print the char array?

Pseudo code:

if there is a character to read
  read it
  if the character is a newline
    do something with the string
    clear the buffer
    reset the index
  else
    put the character into the buffer
    increment the index
    null terminate the buffer
  end if
end if

The idea of using a terminating character is, that while there is at least one character available you read it and, if it is not the terminator and you have not read as many characters as the target array will hold, you put it in the array, advance the index, put in the '\0' and read the next character then do the same thing again. When you get the terminating character or have read the maximum number of characters then you print the string in the target array.

There is no need to move what you have read into the target array (a C style, null terminated string, lowercase s) to a String (uppercase S) before you print it.

I moved it into a String object because I want to use functions that only strings have like reads.indexOf() or things like that.

pedroply:
I moved it into a String object because I want to use functions that only strings have like reads.indexOf() or things like that.

Don't.
There is a problem with the memory allocation and strings on the compiler used for the arduino. All those functions can be done by hand if you want.

OK, if you must, you must, but the same principle will apply. Read the string until it is complete, then copy it to the String.

What version of the IDE are you using ? The problems with Strings are supposedly fixed in 1.0.4 but, as Mike says, avoid Strings if you can.

I am using version 1.0.3 but I will update now and see what happens.
....
Nop, the same erro.

Grumpy_Mike:
All those functions can be done by hand if you want.

Not too difficult either (untested):

int char_indexOf(char *toSearch, char *toFind)
{
  int index = 0;
  while (toSearch[index] != '\0')
  {
    if (strncmp(toSearch+index, toFind, strlen(toFind)) == 0)
      return index;
    index++;
  }
  return -1;
}

pedroply:
I am using version 1.0.3 but I will update now and see what happens.
....
Nop, the same erro.

This is because the error is yours not the compiler's.

Might I suggest that you print stuff intelligently?

Serial.print("reads: [");
Serial.print(reads);
Serial.println("]");

will convey a LOT more information than

Serial.println(reads);

It just might even provide a clue or two.

Insulting and irrelevant replies removed.

  • moderator

Sorry for not being able to reply earlier but I have made some improvements :

This is because the error is yours not the compiler's.

I already suspected that

PaulS:
Might I suggest that you print stuff intelligently?

Serial.print("reads: [");

Serial.print(reads);
Serial.println("]");




will convey a LOT more information than 



Serial.println(reads);




It just might even provide a clue or two.

I already suspected that the problem was in the string, more precisely at the point of converting the char into the string and I made this little modification:

if(index < 19 && inChar!='\n') // One less than the size of the array -/ added the  "&& inChar!='\n'" so that it stops when it reages the last char.
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           inData[index] = '\0'; // Null terminate the string
       }

But it wouldnt work becouse at the first time the code is running, the inChar is nothing so here is my last code:

char inData[50]; // Allocate some space for the string
char inChar = 'c'; // Where to store the character read
byte index = 0; // Index into array; where to store the character
String reads;
int words = LOW;


void setup(){
  Serial.begin(9600);
}


void loop()
{
   while(Serial.available() > 0)
   {
       if(index < 49 && inChar!='\n') // One less than the size of the array
       {
           inChar = Serial.read(); // Read a character
           inData[index] = inChar; // Store it
           index++; // Increment where to write next
           //inData[index] = '\0'; // Null terminate the string
       }
       words = HIGH;
   }
   
   for(int i=0; i<=index && inChar=='\n' && inData[i]!='\n'; i++)
       {
         reads += inData[i];
         inData[i] = 0;
       }
   
   delay(10);
   if(words && inChar=='\n')
   {
     Serial.print("reads: [");
     Serial.print(reads);
     Serial.println("]");
     words = LOW;
     reads = "";
   }
   
   
   index = 0;
   inChar = 'c'; // make it so that it is different from '\n' 
}

It got some errors like you type "test" and it only returns "est" or "arduino" and it returns "duino" but it works.

So the question then becomes, why are you testing the value of inChar before reading it?

Because if I don't test its value when the word I send finishes, it continues to add blank spaces to the string.