Pages: [1]   Go Down
Author Topic: serial string to integers  (Read 1025 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a sensor that outputs a serial string of numbers, spaces, and letters.  It's in a format like this:   "525 0 894xcf"

It's basically 3 numbers separated by white spaces.  The numbers can vary from 1 to 4 digits, so I have to use the white spaces as delimiters.  And there are always a few letters tacked onto the last number that I want to throw away.  I need to separate the 3 numbers into integers so that they can be stored or transmitted further down in the script.

I'm able to successfully read in the serial data and store it in a string.  The trouble comes when I try to parse it.

I've searched this forum and got several different examples.  Some people say to use sscanf, others say atoi or strtok.  It seems like there are several ways to do it and everyone has their own opinion about what should or should not be used.   I've tried all 3 of the above by using examples people have posted here, but can't seem to make them work.  So I'm wondering which method I should focus on if somebody has some tips.
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

strtok can be useful to quickly and easily break a string up into the specified tokens (but it doesn't do any datatype conversion, so you still have to use something like atoi to convert the values).  An important side affect to strtok is that it modifies the string it is tokenizing.

sscanf is going to have more compiled overhead than atoi, because it's a much more versatile function.  On small sketches this may not be an issue, but if you're low on flash space, the difference between sscanf and atoi could be the difference between your program fitting on the micro or not.
Logged


New Jersey
Offline Offline
Faraday Member
**
Karma: 67
Posts: 3702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

strtok will do it. Here's a quick & dirty example. Note that it assumes that you have the string with all three numbers & doesn't check that that is really the case:
Code:
char buf[]="525 0 894xcf";
char separator[]=" ";

void setup()
{
  char *ptr;
  int x,y,z;
  Serial.begin(9600);
  ptr=strtok(buf,separator);
  x=atoi(ptr);
  Serial.println(x);
  ptr=strtok(NULL,separator);
  y=atoi(ptr);
  Serial.println(y);
  ptr=strtok(NULL,separator);
  z=atoi(ptr);
  Serial.println(z);
}

void loop()
{
}
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quick and dirty would be sscanf.  1 line of code instead of 6.  This:

Code:
  ptr=strtok(buf,separator);
  x=atoi(ptr);
  ptr=strtok(NULL,separator);
  y=atoi(ptr);
  ptr=strtok(NULL,separator);
  z=atoi(ptr);

becomes this:

Code:
  sscanf(buf, "%d %d %d", &x, &y, &z);

The important difference to be aware of though, the sscanf version is roughly 1500 bytes larger when compiled.  It also doesn't modify the buf string.
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the help.  I'm posting the code I have so far, but  I'm getting the following error on the line with the sscanf function:

Code:
_5TMtest_2:25: error: cannot convert 'String' to 'const char*' for argument '1' to 'int sscanf(const char*, const char*, ...)'

My code:

Code:
#include <NewSoftSerial.h>

NewSoftSerial mySerial(8, 9);
int x,y,z;
String readString;

void setup()
{
  Serial.begin(1200);
   mySerial.begin(1200);
   Serial.println("5TMtest-2"); // so I can keep track of what is loaded
}

void loop() {
 
    while (mySerial.available()) {
    delay(1); 
    if (mySerial.available() >0) {
      char c = mySerial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    }
  }
  if (readString.length() >0) {
   Serial.print("readString = ");
   Serial.println(readString);  //so you can see the captured string
   sscanf (readString, "%d %d %d", &x, &y, &z);
   Serial.print("first= ");
   Serial.println(x);
   Serial.print("middle= ");
   Serial.println(y);
   Serial.print("last= ");
   Serial.println(z);
  }
   readString="";
}
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 303
Posts: 26354
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The error is saying you can't pass a String object to sscanf, which expects a C string (an array of "char", terminated by a zero).
You need to convert your String to a C string if you want to use sscanf.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay, that makes sense.  But how to I convert the string to a C string?  Would it be easier to read the data from the sensor directly into a C string first instead of converting?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 303
Posts: 26354
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://arduino.cc/en/Reference/StringToCharArray
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

New Jersey
Offline Offline
Faraday Member
**
Karma: 67
Posts: 3702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Would it be easier to read the data from the sensor directly into a C string first instead of converting?
No easier, but probably safer - you won't have to worry about string operations fragmenting your heap and failing unexpectedly after you've been running for a while.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's working now, except that the serial data from my sensor apparently has a couple non-numeric characters before the actual numbers I want to read, along with a carriage return after them, and that seems to be throwing things off.  Is there a way to filter out non-numeric things when populating the string during the myserial.read part?

I just captured several lines of the raw serial data from the sensor using a program on my PC called RealTerm to save it to a text file.  I'm attaching a picture of what the raw sensor data looks like when viewed with notepad.  Note the strange character at the beginning of each line and the little box after 642, which I guess is a carriage return. 


* 5tmcapture1.jpg (15.27 KB, 297x167 - viewed 23 times.)
« Last Edit: May 03, 2011, 03:41:51 pm by andywatson » Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 67
Posts: 3702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Test the character you've read to see if it's in the 0-9 range, or is space. Use these, throw everything else away. Something like this fragment:
Code:
  char c;
  if(Serial.available())
    {
      c=Serial.read();
      if((c>='0' and c<='9') || c==' ')
        {
        //use character
        }
    }
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks wildbill, that code worked perfectly for filtering out all the other stuff.  Thanks! 
Logged

Pages: [1]   Go Up
Jump to: