Reading Values from SDHC card into an Array

Hi All,

I was hoping that someone can help me out, as I have been trying to do this, but I can’t seem to get the right combination right, as I am surely missing something. I am new to Arrays and reading data from an SDHC card. So far, I have the card working properly, and as you can see from my sketch, it does seem to read the data.

What I want to do, is to use a 2D array, but I want to populate this array within setup when board first gets power. I will then use this array during my program execution as a simple look-up table. I will supply it a value from a sensor, and then I will quickly search the array, that will then return 3 values, from the index value (search term) supplied. These are simple lookup values, and something which can not be done in a mathematical way…again, simple and fast lookup: Provide a value, return the three values.

My file on the SD card, will be in a .csv format, in other words, will be separated by commas. Here is what this file on the SDHC card will look like: (as you can see, the initial size of this array is [6][4]. I do know that arrays are zero indexed).

21300,30,2,5
14250,25,6,7
7350,36,38,10
3267,41,43,50
28350,53,64,81
10101,63,65,23

#include <SD.h>
#include<SPI.h>
File myFile;
void setup()
{
  pinMode(53, OUTPUT);
  pinMode(SS, OUTPUT);
  //
  //Will try to initialize an array as an example: This is the array I want to Read from SD card.
  //
  /*   int Cap1Val, Cap2Val, IndVal, Freq;
   int Main_Array [6][4] = {
   {21300,30,2,5},
   {14250,25,6,7},
   {7350,36, 38,10},
   {3267,41,43,50},
   {28350,53,64,81},
   {10101,63,65,23}
   };*/
  int Main_Array [6][4];
  int freq = 10101;
  int cap1value, cap2value, indvalue;
  char in_char;
  int i=0;
  int j=0;
  //
  //
  Serial.begin(9600);
  Serial.println("Let's see ow this will work out....");
   if (!SD.begin(53)){
    Serial.println("Card Failed you Douche");
    return;
  }
  //
  myFile = SD.open("test.txt");
  if (myFile){
    while (myFile.available()){
      in_char=(myFile.read());
      if (in_char == ','){
        int i=i+1;
      }
      else if(in_char == '\n'){
        int j=j+1;
        i=0;
      }
      Main_Array[j][i]=int(in_char);
      Serial.write(Main_Array[i][j]);
    }
    myFile.close();
    Serial.println("test of the value");
    cap1value=(Main_Array[0][0]);
    Serial.println(cap1value);
  }
  //
  for (int i=0; i<=5; i++){
    if ( Main_Array[i][0] == freq){
      cap1value= Main_Array [i][1];
      cap2value= Main_Array [i][2];
      indvalue=  Main_Array [i][3];
    }
  }
  Serial.println("The values for cap1, cap2 and ind are:");
  Serial.println(cap1value);
  Serial.println(cap2value);
  Serial.println(indvalue);
}
void loop()
{
  // nothing happens after setup
}

And this is the output I get:

Let’s see ow this will work out…
21300,30,2,5
14250,25,6,7
7350,36,38,10
3267,41,43,50
28350,53,64,81
10101,63,65,23
test of the value
10
The values for cap1, cap2 and ind are:
10
16961
7831

As you can see, I think the Array is being populated correctly, as I can see form the output, but I am screwing up the conversion I guess from char to int? This is where I have done numerous searches, and I can’t seem to come up with the right answer to make this work. Basically I want the Array to look like the example in my comments above in the code, but I want to read this from an SD card.

Can someone please point me in the right direction? Banging my head against the wall :blush:

Thank you in advance for any help, greatly appreciate it!

Why this way??

      Main_Array[j][i]=int(in_char);
      Serial.write(Main_Array[i][j]);

Keep in mind that the SD object reads data a byte at a time. If j = 0 and i = 1, the line becomes:

      Main_Array[0][1]=int(in_char);
      Serial.write(Main_Array[1][0]);

All I can think of is this is some kind of attempt to solve an endian problem. If that's the case, and ints are two bytes, then you might try something like:

union {
   byte array[5];   // Since a text file, and largest int in text is DDDDD
   int val;
} myUnion;
byte inChar;
// some code that is looping through your text file...
   i = 0;
   while (myFile.available()) {
      inChar = myFile.read();
      if (inChar != '\n' && inChar != ',") {   // Have we read all bytes for this value??
         myUnion.array[i++] = inChar;        // Nope.
      } else {
         Main_Array[j][k] = myUnion.val;   // Yep...
         i = 0;
      }
   }

What this attempts to do is read the byte data from the file into a buffer named myUnion as an array of bytes, and when the delimiter is read (',') or a newline is read ('\n'), it assumes that the array[] member of the union holds the int data. We then extract that byte data from the buffer as an int. I'm not sure this will work, and a lot depends upon how you laid the data down in the file. If test.txt is actually ASCII data, then you would need to read the data into a char array, translate the newline or comma into a null, the use atoi() to convert the char array to an int.

      Main_Array[j][i]=int(in_char);

Casting a character implicitly to an int is unnecessary. An explicit cast will be performed, which should be a big clue that reading one character and expecting that to be somehow interpreted as an integer value is NOT going to happen.

You need to read all the data from the card, storing each character in an array, until an end of record marker is read (probably a carriage return or line feed). When that happens, you need to use strtok() and stoi() or atof() to convert the tokens to ints or floats.

The parsing process doesn’t care about white space. Butpeopledo.Don’tjamallthdatainthefiletogether.

Thank you Paul....

I have been googling like mad, and I am trying to understand the functions you mention. I did think that my conversions from one to another are probably screwed up...but I also though this sort of thing might be simpler with some function or library...

I have never used those functions before,and I do appreciate it you pointing me in the right direction. Do you have an example of how something like that might be crafted? Again, my file is rather simple, and I am not going to have massive amounts of data...

I just want to be able to index a value in the first column, and then read the next three values in the rows, after having read that file and imported into an array... Any examples of what you mean, would GREATLY help me!

Thank you again.

Reading the data from the card, and storing it in an array is easy.

char buffer[30];
byte index = 0;

while(file.available() > 0)
{
   char digit = file.read();
   if(digit == '\n')
      parseData(buffer);
   else if(digit != '\r') // ignore line feeds
   {
      buffer[index++] = digit;
      buffer[index] = '\0';
   }
}

Parsing the data is quite simple, too.

void parseData(char *buffer)
{
   char *token = strtok(buffer, ",");
   while(token)
   {
       int someValue = atoi();
       // Store someValue someWhere

      token = strtok(NULL, ","); // Keep parsing same string
   }
}

Wow…Pointers make my head SPIN! I am not a guru on C programming, and even though this will work, I am struggling to understand it…I guess I have to keep reading and searching until the construct you mention makes sense…

One more question: I was wondering if it would be possible to do something with parseInt();

Here is an example, which I am testing now:

//
 myFile = SD.open("test2.txt"); 
   while (myFile.available()){
     for (fieldIndex = 0; fieldIndex <11; fieldIndex ++){
       Main_Array[fieldIndex] = myFile.parseInt();}
       Serial.print( fieldIndex);
       Serial.println(" fields received:");
       for(int i=0; i< 11; i++){
         Serial.println(Main_Array[i]);}
   }
   myFile.close();
}
  void loop()
  {
  }

It is a 1D array, but I am thinking I might be able to make this work with a 2D…

Thoughts?

BTW: Appreciate it very much…searching these forums, I have learned a TON from your posts!!!

I guess I have to keep reading and searching until the construct you mention makes sense…

Or ask questions.

For a long time, you’ll struggle with pointers. Then, one day, you’ll go “Oh, I get it”. From then one, you’ll have a hard time understanding why anyone would have problems with pointers.

It is a 1D array, but I am thinking I might be able to make this work with a 2D…

Sure.

       Main_Array[fieldIndex] = myFile.parseInt();
} // Down here where the damned thing belongs

becomes:

   for(int toad = 0; toad < 3; toad++)
   {
       Main_Array[fieldIndex][toad] = myFile.parseInt();
   }
}

(You might prefer a more meaningful name for the index of the inner loop.)

Since I know how to read and parse data, I don’t need the help of the parseInt() or parseFloat() functions, so I forget which classes implement them.

Yeap…Thank God for the ParseInt() Function! :smiley: :smiley: :smiley: :smiley:

SUCCESS!!

 myFile = SD.open("test.txt"); 
   while (myFile.available()){
       for (int i=0; i<=5; i++){
         for(int j=0; j<=3; j++){
           Main_Array[i][j] = myFile.parseInt();
           Serial.println(Main_Array[i][j]);}
       }
  myFile.close(); }

//
   Serial.print("A test Value is:");
   Serial.println(Main_Array[4][3]);    
       
}     
  void loop()
  {
  }

This works like a charm on a comma delimited file, and the 2D array populates at it should!

Thank you very much for your guidance!

This works like a charm on a comma delimited file, and the 2D array populates at it should!

Presuming that there are at least 24 values in the file.