Serial - Issues reading and parsing

Yes. inData[1] returns 2. However, the issue is, as this data is being send over Bluetooth, Serial.available stops being available after a number of values are returned. Using the below code as an even simpler example, I am sending data like this: 25,50\n. When I run this in the Serial Monitor, I get 25 and 50 returned with the below code, it continues until a point and then the Serial Monitor stops showing values? My Android app shows that data is still being sent over Bluetooth to the Arduino.

void setup() {
  // initialize serial:
  Serial.begin(9600);
}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int firstNum = Serial.parseInt(); 
    // do it again:
    int secondNum = Serial.parseInt(); 

    // look for the newline. That's the end of your
    // sentence:
    if (Serial.read() == '\n') {
     
     


      // print the three numbers in one string as hexadecimal:
      Serial.print(firstNum);
      Serial.print("  ");
      Serial.println(secondNum);
    }
  }
}
  while (Serial.available() > 0) {

There is at least one byte to read. You then proceed to read as many as you want. Fail.

One byte available enables one read. There is no way around that.

I don't know how parseInt() behaves and the documentation for it is utterly useless. It might do exactly what you need here, but it might not. What happens if you get extra characters (for example \r) not consumed by parseInt(), or a dropped character, or if the read times out or something? Are you sure your code is going to get back in sync with the incoming stream? It's hard to know, because I don't know what the incoming stream contains or what parseInt() actually does - but it's not at all obvious that it will.

My device sends byte data as follows: s25,50e

Is the e the end of packet marker? Be aware that on the sending end you may need to use a delay to prevent sending data faster than it can be processed on the receiving end.

Thx for the tips... I think it may be an issue with my bluetooth send routine on the Android device. I'm sending a text string (and not by bytes), but to be honest, I'm a bit green on that part. Since I've gotten the above to samples (one of which is pretty much verbatim from Arduino.cc) to receive and show data, I'm going to have to look deeper at how I am sending the data as it seems that at some pt, it just stops sending. Problem is my Android procedures don't show any errors...

How many time are we going to cover this topic? Thanks Nick G for providing that awesome example for handling multiple character with serial communications.
Don

How many time are we going to cover this topic?

At least once more. Today.

No love in the house eh guys... I tried Nick's example, and it too parsed data like the rest of the examples I posted, but it too also craps out after so many iterations through the loop. Serial.Available becomes 0. Not saying there is anything wrong with his code, or the examples I posted above. Just trying to understand what I am missing, so go easy please. It's either the serial buffer is not getting cleared out on the Arduino side, or my Android device stops sending the data but does not throw any errors. Is it possible to fill up the Serial buffer using Nick's example? ie. is it possible for the BT data to come over too quick? I've got my data sending at (what I think is) a reasonable speed of 200ms between packets.

Nicks code wasn't written for your problem. You should read it figure out whats happening and apply it to solve your problem. Try it yourself you have to experiment..

If your data packet is delimited by a e (you failed to answer the question concerning this), then you might try substituting an e for the comma , in the below code.

//zoomkat 3-5-12 simple delimited ',' string parce 
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out
        //do stuff with the captured readString 
        readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

@zoomkat, thx for the example. Tried it and substituted the 'e' and, as all the other examples it too worked, but again crapped out in the serial window after a number of values showed. Maybe I am missing something, but it seems that everyone thinks that I am not getting results from these samples. I am. The issue is that the serial monitor stops reporting them as Serial.Available is no longer true.

I modified the sample above by adding a counter. The serial window stops about about ~180 iterations each time. Below is a dump of the last few values passed:
178 sX=97,Y=-7
179 sX=97,Y=-7
180 sX=97,Y=-7
181 sX=97,Y=-7
182 sX=97,Y=-7
183 sX=97,Y=-7
184 sX=97,Y=-7
185 sX=97,Y=-7
186 sX=97,Y=-7
187 sX=97,Y=-7

//zoomkat 3-5-12 simple delimited ',' string parce 
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}
int i;
void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == 'e') {
      if (readString.length() >1) {
        Serial.print(i);
        Serial.print("  ");
        Serial.println(readString); //prints string to serial port out
        //do stuff with the captured readString 
        readString=""; //clears variable for new input
      }
       i++;
    }  
    else {     
      readString += c; //makes the string readString
    }
    
  }

}
String readString;

Please note that, at present, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

deejayspinz:
No love in the house eh guys...

We love everyone on the forum. :wink:

Well, some more than others.

PaulS patiently answers lots of questions every day. Sometimes though you sense the smoke coming out of his ears. :slight_smile:

Hi Nick. I was just trying that example. Below is the code I am using. Same result as the others I've tried. At some point, Serial.Available becomes false. Also note that I've tested my Android app sending to a BT dongle on a laptop and using Putty to view the data. Left it running for over 5 minutes and the data stream never stopped, so I am fairly certain that my Android app is not crashing and is still sending the data. Again, it seems to me that some sort of buffer is filling up? I've read the docs on Serial and still don't understand how it works. If I am sending BT data to the Arduino does Serial every 'fill up'? I've seen a 64 byte limit. If so, how can I ensure it is clear or flushed often enough? Most of the samples I see just read from the Serial and do something with the data without every having to 'tend' to it. Or they seem that way.

Thx everyone for your help.

#define SOP 's'
#define EOP 'e'

bool started = false;
bool ended = false;

char inData[20];
byte index;
int xVal=0, yVal=0;




void setup()
{
   Serial.begin(9600);
   // Other stuff...

}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 19)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet



        char *name = strtok(inData, "=");
        while(name)
        {
          char *valToken = strtok(NULL, ",");
          if(valToken)
          {
             int val = atoi(valToken);
             if(strcmp(name, "X") == 0)
                xVal = val;
             else if(strcmp(name, "Y") == 0) 
             yVal = val;
             // More else if's go here
          }
        
          name = strtok(NULL, "=");
        }
       
     Serial.print("Xvalue= ");
     Serial.print(xVal);
     Serial.print("  Yvalue= ");
     Serial.println(yVal);     

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
 
}

What does your debugging show? Or if you can't see it, may as well remove it.

The incoming data is caught by an interrupt and place in an internal buffer (64 bytes sounds right). If you promptly remove it (as you seem to be doing) it won't fill up.

I can't see anything obviously wrong.

If you have a second Arduino you might want to shoot some debugging out SPI or I2C and keep track of what is happening.

deejayspinz:
Edit: I noticed that the more info I try to "Serial.Print" to the Serial Montior, the quicker that Serial.Available seems to stop working (=0). i.e. I added Serial.Prints for inData[2] up to [7] and it crapped out sooner?

It takes time to send the data out, and if you stuff the buffer faster than it can send it, it hangs and waits for the buffer to empty. During that time the incoming buffer might fill up before you get a chance to remove its contents. Try keeping the debugging short.

The issue is that the serial monitor stops reporting them as Serial.Available is no longer true.

Doesn't that sound like something on the sending end has failed?

Nick. You're a star! That did the trick. Got rid of my serial prints and threw a few LEDs onto a breadboard to debug and they show it's working. Looks like writing to the Serial Monitor caused the buffer to overflow (or something like that). Thanks!

For prosperity sake, I'll throw the working code up so it can help someone in the future. I'll add that credit goes to those who wrote this code. I've just added my bits to a sample already provided here.

#define SOP 's'
#define EOP 'e'

bool started = false;
bool ended = false;

char inData[20];
byte index;
int xVal=0, yVal=0;

int led1 = 8;
int led2 = 9;

void setup()
{
   Serial.begin(9600);
   // Other stuff...
   pinMode(led1, OUTPUT);   
   pinMode(led2, OUTPUT);   
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    //blink();
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 19)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet



        char *name = strtok(inData, "=");
        while(name)
        {
          char *valToken = strtok(NULL, ",");
          if(valToken)
          {
             int val = atoi(valToken);
             if(strcmp(name, "X") == 0)
             {
                xVal = val;                
                digitalWrite(led1, HIGH);
             }
             else if(strcmp(name, "Y") == 0) 
             {
               yVal = val;
               digitalWrite(led2, HIGH);
             }
             // More else if's go here
             
          }
        
          name = strtok(NULL, "=");
        }
        
        digitalWrite(led1, LOW);
        digitalWrite(led2, LOW);
       
     //Serial.print("Xvalue= ");
     //Serial.print(xVal);
     //Serial.print("  Yvalue= ");
     //Serial.println(yVal);     

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
 
}

void blink()
{
  digitalWrite(led1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(5);               // wait for a second
  digitalWrite(led1, LOW);    // turn the LED off by making the voltage LOW
  delay(5);               // wait for a second 
}