Go Down

Topic: Read CSV or TXT from SD card into string or array (Read 36807 times) previous topic - next topic

fat16lib

Use a floating type for the variable and use strtod() in place of strtol();

Code: [Select]

  //  int array[ROW_DIM][COL_DIM];

  //  change array type to float or double (both are 32-bit floating point on AVR)
  double array[ROW_DIM][COL_DIM];

  // ...

  //  array[i][j] = strtol(str, &ptr, 10);

  //  convert filed to floating point instead of long.
      array[i][j] = strtod(str, &ptr);


hiramvillarreal

Hi fat16lib, great solution to read a CSV, I need to output almost the same but I need to output a line once and never output it again.

I am using a CSV to load a list of "user" and "password" from a PC, then insert the SD card into the Arduino card reader, after push a bottom it will output on a LCD an unused line, the next time the push bottom it will press, it will give the next line.

I been thinking  to use an extra file to save the last position read it and stop the while loop keeping that X,Y value for the display, after that the "index" file will be saved with an increment of the last position.
Do you have an advice to do so?

Thanks  sorry for my English.

pussimus

Here is a simple sketch that reads a CSV file with two numbers on each line.  It doesn't use the dangerous String class.
Code: [Select]

#include <SD.h>
File file;

bool readLine(File &f, char* line, size_t maxLen) {
  for (size_t n = 0; n < maxLen; n++) {
    int c = f.read();
    if ( c < 0 && n == 0) return false;  // EOF
    if (c < 0 || c == '\n') {
      line[n] = 0;
      return true;
    }
    line[n] = c;
  }
  return false; // line too long
}

bool readVals(long* v1, long* v2) {
  char line[40], *ptr, *str;
  if (!readLine(file, line, sizeof(line))) {
    return false;  // EOF or too long
  }
  *v1 = strtol(line, &ptr, 10);
  if (ptr == line) return false;  // bad number if equal
  while (*ptr) {
    if (*ptr++ == ',') break;
  }
  *v2 = strtol(ptr, &str, 10);
  return str != ptr;  // true if number found
}

void setup(){
  long x, y;
  Serial.begin(9600);
  if (!SD.begin(SS)) {
    Serial.println("begin error");
    return;
  }
  file = SD.open("TEST.CSV", FILE_READ);
  if (!file) {
    Serial.println("open error");
    return;
  }
  while (readVals(&x, &y)) {
    Serial.print("x: ");
    Serial.println(x);
    Serial.print("y: ");
    Serial.println(y);
    Serial.println();
  }
  Serial.println("Done");
}
void loop() {}
 
Is it just me, or doesnt it work anymore ?
I updated Library SD.H (v1.1.1) after that it wont read files from my SD card.

MikeOrlando02

Here is a simple sketch that reads a CSV file with two numbers on each line.  It doesn't use the dangerous String class.
Code: [Select]

#include <SD.h>
File file;

bool readLine(File &f, char* line, size_t maxLen) {
  for (size_t n = 0; n < maxLen; n++) {
    int c = f.read();
    if ( c < 0 && n == 0) return false;  // EOF
    if (c < 0 || c == '\n') {
      line[n] = 0;
      return true;
    }
    line[n] = c;
  }
  return false; // line too long
}

bool readVals(long* v1, long* v2) {
  char line[40], *ptr, *str;
  if (!readLine(file, line, sizeof(line))) {
    return false;  // EOF or too long
  }
  *v1 = strtol(line, &ptr, 10);
  if (ptr == line) return false;  // bad number if equal
  while (*ptr) {
    if (*ptr++ == ',') break;
  }
  *v2 = strtol(ptr, &str, 10);
  return str != ptr;  // true if number found
}

void setup(){
  long x, y;
  Serial.begin(9600);
  if (!SD.begin(SS)) {
    Serial.println("begin error");
    return;
  }
  file = SD.open("TEST.CSV", FILE_READ);
  if (!file) {
    Serial.println("open error");
    return;
  }
  while (readVals(&x, &y)) {
    Serial.print("x: ");
    Serial.println(x);
    Serial.print("y: ");
    Serial.println(y);
    Serial.println();
  }
  Serial.println("Done");
}
void loop() {}
 

Reading this "TEST.CSV" file.
Results in this output
Here is a simple sketch that reads a CSV file with two numbers on each line.  It doesn't use the dangerous String class.
Code: [Select]

#include <SD.h>
File file;

bool readLine(File &f, char* line, size_t maxLen) {
  for (size_t n = 0; n < maxLen; n++) {
    int c = f.read();
    if ( c < 0 && n == 0) return false;  // EOF
    if (c < 0 || c == '\n') {
      line[n] = 0;
      return true;
    }
    line[n] = c;
  }
  return false; // line too long
}

bool readVals(long* v1, long* v2) {
  char line[40], *ptr, *str;
  if (!readLine(file, line, sizeof(line))) {
    return false;  // EOF or too long
  }
  *v1 = strtol(line, &ptr, 10);
  if (ptr == line) return false;  // bad number if equal
  while (*ptr) {
    if (*ptr++ == ',') break;
  }
  *v2 = strtol(ptr, &str, 10);
  return str != ptr;  // true if number found
}

void setup(){
  long x, y;
  Serial.begin(9600);
  if (!SD.begin(SS)) {
    Serial.println("begin error");
    return;
  }
  file = SD.open("TEST.CSV", FILE_READ);
  if (!file) {
    Serial.println("open error");
    return;
  }
  while (readVals(&x, &y)) {
    Serial.print("x: ");
    Serial.println(x);
    Serial.print("y: ");
    Serial.println(y);
    Serial.println();
  }
  Serial.println("Done");
}
void loop() {}
 

Reading this "TEST.CSV" file.
Results in this output
@fat16lib, I am having a little difficulty in following your code; however with some time/google I think I will figure it out.  If you have a minute, could you look at my post and see if this code you posted would be applicable to my situation?  I have an SD card with the fixed-length HEX and then the username, can I use your code for this case?

https://forum.arduino.cc/index.php?topic=622216.0

Code: [Select]

ba322d387d980d74fc5d0d46, John
ba039b572f612e58d05a8c2d, Katie
979aeeb3ee35360a24d6190, Sandra
78cabc678dc0a503647cb05d, Tim




wildbill

To get started just use the readline function to pull each line in turn into a character array. Then print it to the serial port. Once that's working you can figure out how to parse it into two parts for storage.

voha888

You can read SD card files line-by-line if this helps:

Code: [Select]
String l_line = "";
//open the file here
while (l_SDFile.available() != 0) {
    //A inconsistent line length may lead to heap memory fragmentation
    l_line = l_SDFile.readStringUntil('\n');
    if (l_line == "") //no blank lines are anticipated
      break;
    //

   //parse l_line here
}
//close the file here

  

Cheers

Catweazle NZ
Thank You! But some Arduino functions not work with strings created with
Code: [Select]
.readStringUntil('\n');
 function
Because files on SD have "CR" symbol, best way is using
Code: [Select]
.readStringUntil('\r');
 

//Sorry, for my bad English

sterretje

#21
Sep 22, 2019, 05:03 pm Last Edit: Sep 22, 2019, 05:03 pm by sterretje
Because files on SD have "CR" symbol, best way is using
It depends on the OS and application that wrote the file to SD in the first place. See https://en.wikipedia.org/wiki/Newline#Representation.

PS
This thread is old
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Go Up