writing header to .csv file SD file logging - blum tutorial 11

Is there something erasing my setup header (ID, Voltage, Current) in the CSV file? No biggy with a couple data points, but helpful when you have more. Serial monitor confirms it wrote it, but when I view the file its not there...

//Jeremey Blum - Tutorial 11
//http://www.jeremyblum.com/2011/04/05/tutorial-11-for-arduino-sd-cards-and-datalogging/
//iteadstudio SDCard Shield v1.0

#include <SD.h>

//SPI Settings
//MOSI, MISO, SCLK Set by default
int CS_pin = 10;
//int pow_pin = 8;

//sensor analog inputs
int voltage_pin = 0;
int current_pin = 1;
int sensorCal = 531; //531 manual input raw input at zero amps for Hall Sensor
int sensorSpec = 40; //Hall Sensor, 40 mV per Amp

float refresh_rate = 0.0; //Datalogger Refresh Rate
long id = 1;              //Store the id# of our reading


void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing Card");
  //CS Pin is an output
  pinMode(CS_pin, OUTPUT);
  
  //Card will Draw Power from Pin 8, so set it high
  //pinMode(pow_pin, OUTPUT);
  //digitalWrite(pow_pin, HIGH);
  
  //Check if card ready
  if(!SD.begin(CS_pin))
  {
    Serial.println("Card Failed");
    return;
  }
  Serial.println("Card Ready");
  
  //Read the configuration information (COMMANDS.txt)
  File commandFile = SD.open("COMMANDS.txt");
  if (commandFile)
  {
    Serial.println("Reading Command File");
    
    float decade = pow(10, (commandFile.available() - 1));
    while(commandFile.available())
    {
      float temp = (commandFile.read() - '0');
      refresh_rate = temp*decade+refresh_rate;
      decade = decade/10;
    }
    Serial.print("Refresh Rate = ");
    Serial.print(refresh_rate);
    Serial.println("ms");
  }
  else
  {
    Serial.println("Could not read commande file.");
    return;
  }
  
  //Write Log.csv File Header
  File logFile = SD.open("LOG.csv", FILE_WRITE);
  if (logFile)
  {
    logFile.println(", ,"); //Just a leading blank line, incase there was previous data
    String header = "ID, Voltage, Current";
    logFile.println(header);
    logFile.close();
    Serial.println(header);
  }
  else
  {
    Serial.println("Couldn't open log file");
    return;
  }
}

void loop()
{  

//read voltage divider circuit output r1=10k(really 9.88k) r2=1k
  int voltage_grab = analogRead(voltage_pin);
  float voltRatio = voltage_grab / 1023.00; //find ratio of reading to convert to v where 1023=5v
  float voltFloat = voltRatio * 5.00 * 11.00 * 100.00; //5v * voltage divider measured ratio 11 * mV conversion 100
  int voltage_reading = voltFloat; //convert float reading to integer for the dataString
  
  //convert hall amp sensor reading to actual current
  int ampRead = analogRead(current_pin); //Read hall sensor output
  ampRead = constrain(ampRead, sensorCal, 1023); //constrain to manual sensor calibration
  int current_reading = ampRead - sensorCal; //Declare new int for conversion
  current_reading = (current_reading * 4.9) / sensorSpec; //4.9 * Analog signal =~ mV, divide by example: "ACS756 spec: 40mV/1A"
  //int hallMv = analogRead(hallIn) * 4.9; //debugging to view mV
  
  
  String dataString = String(id) + ", " + String(voltage_reading) + ", " + String(current_reading);
  
  //Open a file to write to
  //Only one file can be open at a time
  File logFile = SD.open("LOG.csv", FILE_WRITE);
  if(logFile)
  {
    logFile.println(dataString);
    logFile.close();
    Serial.println(dataString);
  }
  else
  {
    Serial.println("Couldn't access file");
  }
  //increment ID #
  id++;
  
  delay(refresh_rate);
}

Thank You in advance

I downloaded the Blum tutorial code and compared it to your posted code here is one difference I found, look for the <<<<<<<<<<<<<<<<<.

 //Read the Configuration information (COMMANDS.txt)
  File commandFile = SD.open("COMMANDS.txt");
  if (commandFile)
  {
    Serial.println("Reading Command File");
    
    float decade = pow(10, (commandFile.available() - 1));
    while(commandFile.available())
    {
      float temp = (commandFile.read() - '0');
      refresh_rate = temp*decade+refresh_rate;
      decade = decade/10;
    }
    Serial.print("Refresh Rate = ");
    Serial.print(refresh_rate);
    Serial.println("ms");
    commandFile.close(); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< You are missing this line in your code at this same spot.
    String header = "ID, Voltage, Current";
    logFile.println(header);

What a waste of resources.

    logFile.println("ID, Voltage, Current");

No wasted resources here. It could be even better, using the F() macro, but that is an exercise for the reader.

Thank you cycle and Paul, the header works!!

Now I need to figure out how to increase resolution, I have no delay and can only get about 3 data points per second (float math?). This gets me started so I am happy.

//Based on Jeremey Blum's - Tutorial 11
//http://www.jeremyblum.com/2011/04/05/tutorial-11-for-arduino-sd-cards-and-datalogging/
//Voltage and Amp conversion code created by Steelmesh
//Hardware: duel with a iteadstudio SDCard Shield v1.0

#include <SD.h>

//SPI Settings
//MOSI, MISO, SCLK Set by default
int CS_pin = 10;
//int pow_pin = 8;

//sensor analog inputs
int voltage_pin = 0;
int current_pin = 1;
int sensorCal = 531; //531 manual input raw input at zero amps for Hall Sensor
int sensorSpec = 40; //Hall Sensor, 40 mV per Amp

long id = 1;              //Store the id# of our reading

unsigned long timestamp;

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing Card");
  //CS Pin is an output
  pinMode(CS_pin, OUTPUT);
  
  //Card will Draw Power from Pin 8, so set it high
  //pinMode(pow_pin, OUTPUT);
  //digitalWrite(pow_pin, HIGH);
  
  //Check if card ready
  if(!SD.begin(CS_pin))
  {
    Serial.println("Card Failed");
    return;
  }
  Serial.println("Card Ready");
  
  //Write Log.csv File Header
  File logFile = SD.open("LOG.csv", FILE_WRITE);
  if (logFile)
  {
    logFile.println(", , ,"); //Just a leading blank line, incase there was previous data
    logFile.println("ID, Time (ms), Voltage (mV), Current");
    logFile.close();
  }
  else
  {
    Serial.println("Couldn't open log file");
    return;
  }
}

void loop()
{
  //Grab sensor readings and "immediately" timestamp it
  int voltage_grab = analogRead(voltage_pin); //read voltage divider circuit output r1=10k(really 9.88k) r2=1k
  int ampRead = analogRead(current_pin); //Read hall sensor output
  timestamp = millis();
  
  //convert voltage divider reading to mV
  float voltRatio = voltage_grab / 1023.00; //find ratio of reading to convert to v where 1023=5v
  float voltFloat = voltRatio * 5.00 * 11.00 * 100.00; //5v * voltage divider actual ratio 11 * mV conversion 100
  int voltage_reading = voltFloat; //convert float reading to integer for the dataString
  
  //convert hall amp sensor reading to amps
  ampRead = constrain(ampRead, sensorCal, 1023); //constrain to manual sensor calibration
  int current_reading = ampRead - sensorCal; //Declare new int for conversion
  current_reading = (current_reading * 4.9) / sensorSpec; //4.9 * Analog signal =~ mV, divide by example: "ACS756 spec: 40mV/1A"
  //int hallMv = analogRead(hallIn) * 4.9; //debugging to view mV
  
  
  String dataString = String(id) + ", " + String(timestamp) + ", " + String(voltage_reading) + ", " + String(current_reading);
  
  //Open a file to write to
  //Only one file can be open at a time
  File logFile = SD.open("LOG.csv", FILE_WRITE);
  if(logFile)
  {
    logFile.println(dataString);
    logFile.close();
    Serial.println(dataString);
  }
  else
  {
    Serial.println("Couldn't access file");
  }
  //increment ID #
  id++;
  
  //delay(refresh_rate);
}
  int voltage_grab = analogRead(voltage_pin); //read voltage divider circuit output r1=10k(really 9.88k) r2=1k
  int ampRead = analogRead(current_pin); //Read hall sensor output

voltage_grab and ampRead as outputs from the same function (on different pins, of course). I don't get it. Consistency in naming variables makes your life easier.

  String dataString = String(id) + ", " + String(timestamp) + ", " + String(voltage_reading) + ", " + String(current_reading);

A colossal waste of resources. The File::println() function could be replaced with several calls to File::print() and one call to File::println() to print the individual variables, with no need to have the String class make the same unformatted conversion to a string. Concatenating is most certainly not required. After this line of code, several calls to the String class' destructor are going to be made, any one of which, when calling the defective free() function, can corrupt your memory.

Avoid that potential problem by ditching the String class.

I have no delay and can only get about 3 data points per second (float math?).

No. It is more likely that opening and closing the file for each record added is what is slowing you down. That, and all the constructor and destructor calls and copying memory locations that the String class has to do.