Reading integers from SD card

Hi working on a program that needs to pull data from an SD card. The file is a .csv and i have 2 columns and multiple rows(about 400). The data is 4 or 5 digit numders eg 2568, 45876.
I have a counter in my program and want to pull the first row at say count 5, then at count 10 pull the second row and so on. Any tips on how to do this, I have seen examples of 1 column and 1 row but not multiple. I could separate the columns into 2 files if that makes it easier.

Thanks for your help

The arduino does not under stand file types, at all, or at least in any thing like the way a PC does. Windows associates a file type with a program and then calls then calls that program to deal with the file. I can't think what application a .cvs file is for.

But I would try this,

Export the file from the application (and I mean export not save) as a text file. You can the see the format of data in the file with notepad.

After that its not to hard ( :roll_eyes:) to read the data from the file.

Mark

You're going to need a state machine and basic string reading techniques to read in the values. Posting what code you have so far is going to make it a lot easier to help.

Your sketch will read the file as a sequence of characters and it will need to step through it looking for line separators until it gets to the line of interest, then step through the line looking for column separators (i.e. commas) until it gets to the field of interest, and then extract the characters containing the decimal digits and parse them to get the corresponding number.

If you can separate the columns into separate files (one column per file) that reduces the amount of work needed to parse the file contents.

Do you have any performance constraints for this - do you care how long it takes to read the values?

I am going to simplify the code and post it. As for speed it will need to be read in under .1 second.

Thanks for the replies

Maybe this article will give you good clue to do that :

Read Config File from an SD Card

I can't think what application a .cvs file is for.

It's csv, not cvs. The csv extension stands for comma-separated values, and is often used when the data is to be parsed by applications that don't need all the overhead of something like Excel, and don't need the data in binary format.

csv files ARE text files.

If you can separate the columns into separate files (one column per file) that reduces the amount of work needed to parse the file contents.

But, since parsing is trivial, why bother?

PaulS:
But, since parsing is trivial, why bother?

Once you know how to do it, sure. But getting it working the first time is not trivial.

If the need can be avoided, why suffer the extra complexity?

Yes I am a total noob, so parsing is not trivial to me. I had another idea but can't get it to work. If I could write one number in many files, I could open each file one at a time when needed. See this code - I can't index the file name, is this even possible?

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <SD.h>

#define SD_CS 5
#define LCD_RESET A4

Adafruit_TFTLCD tft;
int8_t saved_spimode;

void disableSPI(void) {
  saved_spimode = SPCR;
  SPCR = 0;
}

void enableSPI(void) {
  SPCR = saved_spimode; 
}

const int buttonPin = 2;
int cycles = 0;
unsigned long serialTimer;
int cyclecount = 0;
int B = 0;


void setup()
{
  Serial.begin (9600);
  pinMode (buttonPin, INPUT);
  tft.reset();
  uint16_t identifier = tft.readID();
  tft.begin(identifier); 
  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
  Serial.println("initialization failed!");
  return;
  }
  Serial.println("initialization done.");
  disableSPI(); 
  serialTimer =millis();
}

void loop ()
{
  
  cycles++;
  while (digitalRead(buttonPin) == HIGH);
  while (digitalRead(buttonPin) == LOW);
  delay (50);
  Serial.println(cycles);
   for (B=0; B<2000; B+=5){
   if (cycles == B)
   test ();
  }
} 


void test ()
{
enableSPI();
   char D = (B);
   File myFile2;
   myFile2 = SD.open("(D).txt", FILE_WRITE);
   if (myFile2) {
   Serial.print("Writing to test.txt...");
   myFile2.println(B);
   myFile2.close();
   Serial.println("done.");
  } else {
    Serial.println("error opening test.txt");
  }
  disableSPI();  
}

Crebsyn:
See this code - I can't index the file name, is this even possible?

I'm not sure what you mean by 'index the file name', or in what respect the sketch fails to do it.

File2 = SD.open("(D).txt", FILE_WRITE);

I want "D" to index.

Crebsyn:
I want "D" to index.

And still I don't know what that means. Please try to describe what you're trying to do, without using the word "index".

Unless SD.open() has special powers to read "(D).txt" and replace D with a value, you need to build a file name before the call to open.

sprintf() is the easy way to format text into a char or byte array.
I think you don't even need to include stdlib to use sprintf().
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

As a beginner you would do well to look it up on a C++ website and screw around with it for a while, sprintf() can turn none to many numeric variables into tightly formatted text.

The strtok() command is good for parsing buffered text. It will take a little longer to learn if you choose to use it. The reality is that strtok is both clean and simple in action.
IIRC you need to include string.h to get strtok.
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

Ok I know this code is a mess. But can someone shown me how it should look. Not sure how to arrange sprintf.

void test ()
{
enableSPI();
   char D = (B); //B is a counter
   File newfile;
   File myFile2;
   myFile2 = SD.open((sprintf (newfile, "sensor%d.txt", (D) )) , FILE_WRITE); //know idea of how to arrange this, do I use D or B?
   if (myFile2) {
   Serial.print("Writing to test.txt...");
   myFile2.println(B);
   myFile2.close();
   Serial.println("done.");
  } else {
    Serial.println("error opening test.txt");
  }
  disableSPI();  
}

Try this instead:

int D = 1; // obviously you can set D however you want, but it should be an int
char fileName[13];
sprintf(fileName, "sensor%d.txt", D);
myFile2 = SD.open(fileName, FILE_WRITE);

That's okay as it is but good practice says that when it's possible to get an error you really should check for and handle it even if the handling is to stop the program.

I see wayyyyy too little error trapping in most of the code here, it's all written as if it's going to work right and be used right every time. By the time something wrong is noticed you might have a nice set of symptoms to have to fixing what ain't broke, a great way to add bugs to code. But that's not the worst. Worse is when the program doesn't appear to behave wrong and has people trusting bad output as good.

I'm only putting this out so the beginners can get an idea of why to trap errors without having to find out completely the hard way. Completely because no matter how you try not to, you will find ways to be wro---errrr---end up with bugs if you write much non-trivial code. :smiley:

Thank you Dan! That works just how i want.

PeterH:

Crebsyn:
See this code - I can't index the file name, is this even possible?

I'm not sure what you mean by 'index the file name', or in what respect the sketch fails to do it.

index filename means 001.txt, 002.txt......etc