Go Down

Topic: Storing calibration tables on an SD card (Read 4 times) previous topic - next topic



Thank you everyone for your help so far. I am very close.

I have my code successfully reading the CSV-formatted text file from the SD card, parsing that data, and inserting the floats into my array. Yeah.

Now, I have two strange things happening:

1) My code seems to be inserting the values correctly, but when I read them from the array a second time, the first 3 or so are off. Initially, the values go in as 00.00, 00.08, -0.10, 00.56 correctly. But, when I run some Serial.println()s to check what is in the array, the first 3 or so come out as 0.00. Any idea why that is happening?

2) My function to calculate the length of the responseArray[] seems to have stopped working as well. It returns a length of 0 now. Not sure why that is happening either. This code used to work.

Current code:
Code: [Select]

#include <SdFat.h>
#include <SdFatUtil.h>

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

float responseArray[] = {};
char CSV_SEPARATOR = ',';
int elementIdx = 0;
char code[] = "0000000000";
int csvSeparatorCount;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
  PgmPrint("error: ");
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    Serial.println(card.errorData(), HEX);

void setup(void)
    Serial.println("\nType any character to start");
    while (!Serial.available());
    String tmpString = "";
    boolean equalsReadToken = false;
    // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
    // breadboards.  use SPI_FULL_SPEED for better performance.
    if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
    // initialize a FAT volume
    if (!volume.init(&card)) error("volume.init failed");
    // open the root directory
    if (!root.openRoot(&volume)) error("openRoot failed");
    // open a file
    if (file.open(&root, "CSV.TXT", O_READ)) {
      Serial.println("Opened CSV.TXT");
      error("file.open failed");
    int16_t c;

    while ((c = file.read()) > 0)

      if ((char)c == CSV_SEPARATOR)
        char carray[tmpString.length() + 1]; //determine size of the array
        tmpString.toCharArray(carray, sizeof(carray)); //put readStringinto an array
        float n = atof(carray); //convert the array into an Integer
        responseArray[elementIdx] = n;
        Serial.print("Retrieved element ");
        Serial.print(" with a value of ");

        tmpString = "";
        if (csvSeparatorCount == 2) {
          csvSeparatorCount = 0;
          elementIdx = 0;
        } else {
      } else {
        csvSeparatorCount = 0;
        if (((char)c != '\n')&&((char)c !='\r')) {  //prevent newline chars to end up in tmpString
          tmpString += (char)c;                    //accumulate the chars to eventually hold the contents of one element
    int responseArrayLength = ((sizeof(responseArray)/sizeof(char *))/2);
    responseArrayLength = 30; //Why isn't the dynamic version working?
    Serial.print("\nSuccessfully loaded a reponse array from the SD card that is ");
    Serial.println(" elements long.\n");
    for (int loopIteration = 0; loopIteration < responseArrayLength; loopIteration++)
      Serial.print("] = ");

void loop(void) {}


This declares an array of zero length:
Code: [Select]

float responseArray[] = {};

Which explains your point two. It also explains point one - you're stepping on memory that's being used for other things and when other code writes on them too, your results are lost. Try:
Code: [Select]
float responseArray[30];


Setting responseArray[30] definitely solves my problem, but what if the values on the SD card change?

I would like to support being able to increase the "accuracy" of the sensor by having a CSV text file on the SD card that is N values long.

Is there a way to dynamically append the array length so I don't have to worry about not knowing how long the array is before reading the TXT file?


You can use malloc or its siblings to dynamically allocate memory for your array. Don't forget that the Arduino doesn't have very much of it though. For best results, you will need to know up front how many readings you have, although you can use realloc if you don't. In this situation though, best to either count the entries by pre-reading the file, or make the first element in the file be the number of readings it contains.

Go Up