Coordinates from SD card -> array

Hi!

I have a programing question for you guys.

I’m using sparkfun’s microSD shield with tutorial (works great)
http://www.sparkfun.com/tutorials/172

Tutorial example of reading a file

//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h> 
#include <ctype.h>

//Create the variables to be used by SdFat Library
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

char name[] = "program1.txt";     //Create an array that contains the name of our file.
char contents[256];           //This will be a data buffer for writing contents to the file.
char in_char=0;
int index=0;                  //Index will keep track of our position within the contents buffer.

void setup(void)
{  
    Serial.begin(9600);        //Start a serial connection.
    pinMode(10, OUTPUT);       //Pin 10 must be set as an output for the SD communication to work.
    card.init();               //Initialize the SD card and configure the I/O pins.
    volume.init(card);         //Initialize a volume on the SD card.
    root.openRoot(volume);     //Open the root directory in the volume. 
}
void loop(void){    
    file.open(root, name, O_READ);    //Open the file in read mode.
    in_char=file.read();              //Get the first byte in the file.
    //Keep reading characters from the file until we get an error or reach the end of the file. (This will output the entire contents of the file).
    while(in_char >=0){            //If the value of the character is less than 0 we've reached the end of the file.
        Serial.print(in_char);    //Print the current character
        in_char=file.read();      //Get the next character
    }
    file.close();    //Close the file
    delay(1000);     //Wait 1 second before repeating the process.
}

My SD card contains a .txt file called program1

That file have coordinate information on each row in the format: X,Y
Example:
10.21,500.42
10.450,510.601
10.63,520.24

Now I want to store this data to array[ x ][ y ]

How to separate the two values and store them correct?

Both amount decimals and total number of rows may differ from the different “programs”

As always, thankful for some help XD

you need

float array[?? ][2];

?? is the amount of coordinates that you want have simultaniously in memory.

Furthermore you need a function to read a line an put it in a given array index, something like

float array[20][2];

...

void getCoordinatesFromFile(unsigned int idx)
{
  char s[24];   // should be long enough to hold one line
  int i = 0;
  int c = -1;
  while (c != '\n')   // end of line
  {
    c = file.read(); 
    s[i++] = c;
  }
  s[i] = '\0';
  sscanf(s, "%f,%f", &array[idx][0], &array[idx][1]);
}

Keep in mind that array indices need to be integers, not floats. You can't parse the string and extract the floats and expect to use them as array indices.

you can also use a structure to store these datas :

typedef struct
{
    float x;
    float y;
} Coords;

Coords coords[20];



void getCoordinatesFromFile(byte idx)
{
  char s[24];   // should be long enough to hold one line
  int i = 0;
  int c = -1;
  float x, y;

  while (c != '\n')   // end of line
  {
    c = file.read();
    s[i++] = c;
  }
  s[i] = '\0';
  sscanf(s, "%f,%f", &x, &y);

  coords[idx].x = x;
  coords[idx].y = y;
}

then you can use these values, as :

byte idx=0;   // byte is enough, the tab is 20 length.

void loop()
{   
    char str2disp[50];

    getCoordinatesFromFile(byte idx);

    sprintf(str2disp, "Coords of #%d are : x = %f / y = %f", idx, coords[idx].x, coords[idx].y);

    Serial.println(str2disp);

    idx++;

    if (idx>19) idx=0;    
}

Thanks for the great reply’s, looks like a team effort to me : )

Unfortunately it doesent work for me atm, have I implimented your code correctly?

Output:

Coords of #0 are : x = ? / y = ?
.
.
.
Coords of #19 are : x = ? / y = ?

Actual code

//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h> 
#include <ctype.h>

//Create the variables to be used by SdFat Library
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

char name[] = "program1.txt";     //Create an array that contains the name of our file.
char contents[256];           //This will be a data buffer for writing contents to the file.
char in_char=0;
int index=0;                  //Index will keep track of our position within the contents buffer.


typedef struct
{
    float x;
    float y;
} Coords;

Coords coords[20];

byte idx=0;   // byte is enough, the tab is 20 length.

void setup(void)
{  
    Serial.begin(9600);        //Start a serial connection.
    pinMode(10, OUTPUT);       //Pin 10 must be set as an output for the SD communication to work.
    card.init();               //Initialize the SD card and configure the I/O pins.
    volume.init(card);         //Initialize a volume on the SD card.
    root.openRoot(volume);     //Open the root directory in the volume. 
}
 
   
void loop()
{   
    char str2disp[50];
 
    getCoordinatesFromFile(idx);  // getCoordinatesFromFile(byte idx); didn't compile, I excluded "byte"

    sprintf(str2disp, "Coords of #%d are : x = %f / y = %f", idx, coords[idx].x, coords[idx].y);

    Serial.println(str2disp);
    delay(1000);     //Wait 1 second before repeating the process.

    idx++;

    if (idx>19) idx=0;    
}
 
 

void getCoordinatesFromFile(byte idx)
{
  char s[24];   // should be long enough to hold one line
  int i = 0;
  int c = -1;
  float x, y;

  while (c != '\n')   // end of line
  {
    file.open(root, name, O_READ);    //Open the file in read mode.
    c = file.read();
    s[i++] = c;
  }
  file.close();    //Close the file
 
  s[i] = '\0';
  sscanf(s, "%f,%f", &x, &y);

  coords[idx].x = x;
  coords[idx].y = y;
}

I’ve tried to understand all steps in your code but aren’t there yet, could you please help me with some comments?

What do the intermediate stages look like? Where is your debug output?

sprintf on the Arduino doesn't handle floats. Instead of trying to create a single string to output, output in multiple steps.

I’ve tried some more and the conclusion is that the code above always outputs x = ? / y = ? independent of the actual .txt file.

AWOL, the absence of debugging is due to the absence of know how :.

Okey PaulS, I understand what you are saying but cant realize it in code, could you give me a hand?

Convert float to string :

#include <stdlib.h>
char *float2s(float f, unsigned int digits=2)
{
  static char buf[16];
  return dtostre(f, buf, digits, 1);
}

From: - avr-libc: <stdlib.h>: General utilities -

char* dtostre ( double __val,
char * __s,

  • unsigned char __prec,*
  • unsigned char __flags*
  • ) *
    The dtostre() function converts the double value passed in val into an ASCII representation that will be stored under s. The caller is responsible for providing sufficient storage in s.
    Conversion is done in the format “[-]d.ddde±dd” where there is one digit before the decimal-point character and the number of digits after it is equal to the precision prec; if the precision is zero, no decimal-point character appears. If flags has the DTOSTRE_UPPERCASE bit set, the letter ‘E’ (rather than ‘e’ ) will be used to introduce the exponent. The exponent always contains two digits; if the value is zero, the exponent is “00”.
    If flags has the DTOSTRE_ALWAYS_SIGN bit set, a space character will be placed into the leading position for positive numbers.
    If flags has the DTOSTRE_PLUS_SIGN bit set, a plus sign will be used instead of a space character in this case.
    The dtostre() function returns the pointer to the converted string s.
    char* dtostrf ( double __val,
  • signed char __width,*
  • unsigned char __prec,*
    char * __s
  • ) *
    The dtostrf() function converts the double value passed in val into an ASCII representationthat will be stored under s. The caller is responsible for providing sufficient storage in s.
    Conversion is done in the format “[-]d.ddd”. The minimum field width of the output string (including the ‘.’ and the possible sign for negative values) is given in width, and prec determines the number of digits after the decimal sign. width is signed value, negative for left adjustment.
    The dtostrf() function returns the pointer to the converted string s.