Read integers from SD card

Hi all. I'm fairly new here so I'm still learning and I hope someone can help me, please!

I need to read sets of 5 integer variables one line at a time from a CSV file stored on an SD card. I have got the SD card working and I can read the file one line at a time. For example, if the data file is as below:

10,15,23,108,65
15,86,97,54,180
178,65,107,65,10
etc.

I can read each line individually (10,15,23,108,65 then 15,86,97,54,180 etc.)

My problem is that I can't figure out how to split the lines (strings) into integer values where the first integer is before the first comma, the second integer is between the first and second comma etc.

My code extract looks like this at the moment:

    while (myFile.available()) {
    char in_char = myFile.read();
    inData += in_char; 
    if (in_char == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.println(inData);
//
// this is where I need to split inData into the five integer values
// and then do something with each individually
// 
            inData = ""; // Clear received buffer      

        }
 }

What am I missing, please? Or is there a better way to do this?

Thanks.

Richard

Hi Richard,
check this post and look for strtok_r
http://arduino.cc/forum/index.php/topic,41215.0.html

beware, I didn´t try it myself. For further questions u maybe should follow up on in the programming forum.
Best, RObert

Hi Robert and thanks for the response.

I've looked at that thread but am battling to find documentation on the strtok_r function / command so I'm battling to adapt it.

Have tou found documentation for strtok_r?

Thanks.

Richard

I'm also wondering if it isn't possible to import integer values directly from the SD card but I have no idea how to start trying to do that :~

Richard

I also can´t find the documentation on arduino.cc but maybe that´s bc it´s a standard C function.
The code below compiles ok in the arduino env, although it doesn´t anything with sense. I didn´t try to run it on Arduino.

for your question on 'getting integers from SD', I would assume that the SD library can do that, but then that wouldn´t match your format with separation via ',' . Maybe you give an overall description what u r trying so we can create some further ideas....

void setup(void)
{
  char test[80]; 
  char* part; 
  
  part = strtok (test, ",");
  
}

void loop(void){
}

Thanks again, Robert!

I can amend the csv file format as long as it is a format that Excel can export to so I could use other delimiters (e.g. ; or space)

The 5 integer values are used to drive servos to pre-determined positions in a pre-detrmined sequence defined by the data in the CSV file.

Richard

OK, I think I've stumbled on a solution - I just hope it is OK!

   while (myFile.available()) {

      int x = myFile.parseInt();
      int y = myFile.parseInt();
      int z = myFile.parseInt();   
      int a = myFile.parseInt();
      int b = myFile.parseInt();
      Serial.print(" X: ");
      Serial.print(x);
      Serial.print(" Y: ");
      Serial.print(y);
      Serial.print(" Z: ");
      Serial.print(z);
      Serial.print(" A: ");
      Serial.print(a);
      Serial.print(" B: ");
      Serial.println(b);
    }

Can anyone see a problem with this approach?

Thanks.

Richard

Richard,

If you want to use strtok(), here is how you can do it.

#define MAXNUMS 10
char string1[] ="1,2,3,4 ,5, 6, 7 ,008, 9,10";
char string2[] ="100,200,300";
char string3[] ="8,6,7,5,3,0,9";
 
void setup()
{
  Serial.begin(9600);
  while(!Serial);
 
  int  nums[MAXNUMS];
  byte count;
 
  count = parseNumbers(string1, ",", MAXNUMS, nums);
  for (int i=0; i<count; i++)
  {
    Serial.println(nums[i]);
  }
 
  count = parseNumbers(string2, ",", MAXNUMS, nums);
  for (int i=0; i<count; i++)
  {
    Serial.println(nums[i]);
  }
 
  count = parseNumbers(string3, ",", MAXNUMS, nums);
  for (int i=0; i<count; i++)
  {
    Serial.println(nums[i]);
  }
}
 
void loop()
{
}
 
//
// Parse a string of numbers separated by a delimeter, and return them in
// an array.
//
byte parseNumbers(char *string, const char *delim, byte maxNums, int *numArray)
{
  char *tokenPtr; // Token pointer.
  byte count;     // Count of how many numbers were parsed.
 
  // For debugging - show what we are persing.
  Serial.print("Parsing: ");
  Serial.println(string);
 
  // Start with a count of 0 numbers parsed.
  count = 0;
 
  // Get a pointer to the first token, or NULL if not found.
  tokenPtr = strtok(string, delim);
  while(tokenPtr!=NULL && count<maxNums)
  {
    numArray[count] = atoi(tokenPtr);  // Convert token to number.
    count++;
 
    // Get a pointer to the next token, or NULL if not found.
    tokenPtr = strtok(NULL, delim);
  }
  return count;
}

You have to specify the upper range (10 numbers per line, in this example), and pass in an array of ints of that size. It will return with that array loaded.

So, if you had 6 values you wanted to get back, you could do this:

int myNumbers[6];

You would read the line from the file, and call it like this:

count = parseNumbers(string, ",", 6, &myNumbers);

Then, myNumber[0] is the first number, myNumber[5] is the sixth number.

I wrote this to use int arrays so it could be -32767 to 32767, but if you were just using 0-255 values, it could be changed to be a byte array, and save memory (if you are dealing with running out of memory).

Hope this helps.

Allen, thank you! This helps explain the use of strtok() but the byte option may also help with a memory problem I am having!

Thanks again!

Richard

Richard, send me a note if you open up another topic about memory issues and I will take a look. I recently learned quite a bit when I converted an old program that used to take about 21K to run (scaled down) in a 2K Arduino, so I had to use a ton of tricks to maximize what little memory I had.

Thanks very much Allen! I seem to have sorted the memory issues at the moment but I will drop you a message if I battle.

Richard

Hi I have the same problem RNG01. I have a csv.file with 3 parameters per line.
This is the format( 1;2;3)
These 3 Parameter i need to control an i2c-device with my arduino That means to control this i should send to this device via the Wire library these 3 parameters at the same time.

Now i have a problem, i need help in these points:

  1. How i can retrieve a line individually and split this so that i can store the parameters in 3 different variables and use this to control the device.

  2. The other problem is , the file contents more than 1 line with parameters, how i can manage this, that i retrieve a selected line that i need to control the device?

I would be very happy about a code example, because i have searched a lot of time, but without result.

RGN01:
Hi all. I'm fairly new here so I'm still learning and I hope someone can help me, please!

I need to read sets of 5 integer variables one line at a time from a CSV file stored on an SD card. I have got the SD card working and I can read the file one line at a time. For example, if the data file is as below:

10,15,23,108,65
15,86,97,54,180
178,65,107,65,10
etc.

I can read each line individually (10,15,23,108,65 then 15,86,97,54,180 etc.)

My problem is that I can't figure out how to split the lines (strings) into integer values where the first integer is before the first comma, the second integer is between the first and second comma etc.

My code extract looks like this at the moment:

    while (myFile.available()) {

char in_char = myFile.read();
    inData += in_char;
    if (in_char == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.println(inData);
//
// this is where I need to split inData into the five integer values
// and then do something with each individually
//
            inData = ""; // Clear received buffer

}
}




What am I missing, please? Or is there a better way to do this?

Thanks.

Richard


My question ist this inData an char Array, because i cant see de declaration oft this?
Is this right-> char inData[] or is it wrong?

Hi,

I ended up using parseInt() like this:

  myFile = SD.open("Servo01.csv");
  while (myFile.available()) {
    S1 = myFile.parseInt();
    S2 = myFile.parseInt();
    S3 = myFile.parseInt();   
    S4 = myFile.parseInt();
    S5 = myFile.parseInt();
    WaitTime = myFile.parseInt();
    servoS1.write(S1);
    servoS2.write(S2);
    servoS3.write(S3);
    servoS4.write(S4);
    servoS5.write(S5);
    delay(WaitTime);
  }
  myFile.close();

Hope this helps.

Richard

Hi thanks a lot , is it function? In other words, do you have the possibility with this solution to read one line individually at time and handle with the parameters, because I can't see the if-statement with the '\n'?
and WaitTime, this is an integer value to in your file, that you extract, to say when you would change the Servo-value?
In other words, after the waitTime-delay you will extract the next 5 parameter with the next wait time? is it right?

And another question, with the first code of you.
You have used inData+=in_char;
What is the meaning of this? -> In other words, inData is an String variable an you put the charachters from in_char until you recieve a '\n'.
Is it possible?

I am just a beginner so please don't ask me anything too difficult :~

My in_char code snippet was copied from the internet and I'm afraid I never got it to work well which is why I stopped using it - but I can't remember what the exact problem was. Sorry I can't help.

Richard

ou ok sorry .

Then a question to the parse int code. :smiley:

Is it necessary to check if ( char == '\n') (newline) to read out one line at time individually to handle with the parameter, or with your code i dont need this? -> Is very important for me.

And what is WaitTime in your code? -> is this an delay time, that is content of the file?

The code I posted is all you need to read 6 integers from the SD card - the last one is a delay I read from the SD card which I use in the program to delay each servo write for a predetermined period. The card contains the input file that has lines of 6 integers each.

I hope that helps.

Richard

Ah ok, that means i dont need to check up the newline, this will do automatically and after the delay the code will retrieve the next 6 integers?

A question, the output of parseInt is int, now i will to convert this to decimal so that i can convert this in byte, thats possible?