SD datalogging fail.

Hello All:

I'm sure you've heard this a few times before. I'm new to the Arduino platform and need some help. I'm using the Sparkfun Inventor's kit which uses an Arduino Uno along with a Sparkfun MicroSD shield. Using the template application under SD->Datalogger, I get a file with random numbers as is expected. (The Datalogger reads three analog sensors (not attached) and writes their values to the SD card in a txt file called "datalog.txt".

The issue is that I wrote another application for it using a temperature sensor. The hardware and measuring sides of the app work fine however the only thing that does not work is the SD card write routine. When I let the logger run for a bit then stick the SD card into my computer, the computer shows an empty datalog.txt file despite the serial output and the sd card write are within the same block of code. (I'm not writing NULL values to the SD card).

A question I have concerning the SD card is that although I can see the sd.start command, there doesn't seem to be any command to stop or to flush the SD card. Is there such a command or workaround that might explain the lack of data in the datafile?.

Please find my code below.

Thanks in advance.

FIRESTORM_v1

=============================

/*

This is a basic SD card temperature monitor logger. It uses the SD card shield for datalogging,
two pushbuttons, two LEDs and the TMP36 temperature sensor to detect and log temperatures to the SD card.

Pin definitions are as follows:

A0 - Temperature sensor (D14)
D0 - Red LED
D1 - Yellow LED
D2 - SD card switch (BTN1)
D3 - Datalogger Start/Stop (BTN2)
D8 - CS for SD card
D11- MOSI for SD card
D13- SCK for SD card
*/

// Includes
#include <SD.h>

// Variable Declarations
  // This is required per the SD documentation. Without it, the SD library will not work.
  const int chipSelect = 4;
  
  //Physical devices
  int SDmount = 6;  //SD card mount LED
  int Heartbeat = 7; // Heartbeat LED
  int SDbutton = 2; // Bottom button
  int DLbutton = 3; // Top Button
  int TempSensor = 14;  //analog 0 Temperature Sensor

  //Other Variables
  boolean SDEnable = 0;    // SD card mounted?
  boolean DLRun = 0;    // Datalogger running?
  int val = 0; // Temporary variable for reading buttons
  File datafile; // File structure for datafile

void setup() {
  // Start Serial communications for debugging.
  Serial.begin(9600);
  Serial.print("Device ready. Hit SW1 to mount SD card.\n");
  pinMode(SDmount, OUTPUT);
  pinMode(Heartbeat, OUTPUT);
  pinMode(SDbutton, INPUT);
  pinMode(DLbutton,INPUT);
}

void loop() {

  if (SDEnable == 1 ) {
    if (DLRun == 1) {
      digitalWrite(Heartbeat, HIGH); // Turn on Heartbeat LED.
      
      // Read the temp sensor, perform basic math to convert to fahrenheit.
      float temperature = getVoltage(TempSensor);
      temperature = (temperature -.5 ) * 100; // convert from 10mv/deg
      temperature = ((temperature * 9 ) / 5) + 32; // Convert to fahrenheit
      
      // Write our acquired data to the SD card's datalog.txt file.
      File datafile = SD.open("datalog.txt", FILE_WRITE);  //Open file
      if (datafile) {
        datafile.println(temperature);  //Print to file
        Serial.println(temperature);  // Print to serial port
        datafile.close();  //Close file
      } else {
        Serial.println("Something went horribly wrong. You managed to start the SD card but can't write.");
      }
      
      // Turn off the heartbeat LED.
      digitalWrite(Heartbeat, LOW);
    }
  }
  
  val=digitalRead(SDbutton);
  if (val == LOW) {
    if(SDEnable == 0) {
      Serial.print("Initializing the SD card....\n");
        if (!SD.begin(chipSelect)) {
          Serial.println("Card failed, or not present");
        } else {
          Serial.println("Card is mounted.");
          if (SD.exists("datalog.txt")) {
            Serial.println("datalog.txt exists, continuing.");
          } else {
            Serial.println("datalog.txt did not exist, creating it now.");
            datafile= SD.open("datalog.txt", FILE_WRITE);
            datafile.close();
          }
          digitalWrite(SDmount, HIGH);
          SDEnable = 1; 
        }
    } else {
      if(DLRun== 1) {
        Serial.print("Stop the datalogger before unmounting!\n");
      } else {
      Serial.print("Here is where we would unmount the SD card.\n");
      digitalWrite(SDmount,LOW);
      SDEnable = 0;
      }
    }
  }

  val=digitalRead(DLbutton);
  if (val == LOW ) {
    if(DLRun == 0) {
      Serial.print("Starting Datalogger.\n");
      if(SDEnable == 0) {
        Serial.print("Warning! Datalogger will not start with SD card not mounted.\n");
      } else {
        DLRun = 1;
      }
    } else {
      Serial.print("Stopping Datalogger.\n");
      DLRun = 0;
    }
  }
  delay(1000);
}

/* getVoltage function
*/
float getVoltage(int pin) {
  return(analogRead(pin) * .004882814);
  // convert from 0 to 1024 digital range to 0-5VDC each 1 reading = ~5mV 
}

suggest you open the datafile in setup()
and just write to it in loop()

file.flush () is all you need to sync the cards contents - no need to close the file each time.

@mmcp42:

I'll give it a shot and move the SD.open command from the datalogging loop to the SD mount operations loop. Thanks for the tip. Due to the fact that I'm trying to make the SD card field-removable, I can't put the SD.open command into the setup loop, but I can put it into the SD mount loop so that the file is opened or closed upon SDmount press.

@MarkT

I'm guessing the syntax is {filename}.flush(); or in my application datafile.flush(); ?
Is there any risk to damaging the SD card if I flush after write (roughly once a second while the datalogger is running) or is it better to flush before close?


Thank you both for your suggestions, I will try the code out within the next few days and let you know how it all goes.

close() automatically flushes. Flush at the points where you want the data on the card (once per datalogging event?).

Well, I'm definitely a n00b at Arduino and I guess this would be my first n00b mistake. After re-reading the SD demo code (the working datalogger) and comparing it with my SD datalogger code, I found that the CS pin was off. In the documentation, it's set up for the SD/Ethernet shield which uses CS pin 4, however since I'm using the Sparkfun MicroSD Shield, it uses CS pin 8. It didn't hit me until I had printed out the schematic. Once I changed the CS pin to 8 for the shield, it started working correctly and when I plugged the SD card into my PC, the file contained the exact values I had seen in the Serial monitor. Well I definitely learned something, always check your pin defines and print all schematics for shields you'll be using. :stuck_out_tongue:

I went ahead and heeded your suggestions about the location of the open and close statement. Pressing the SD mount button now starts the SD card and then opens the file for writing. Pressing it again closes the file. This way the Arduino isn't constantly opening and closing the file on every datalogging event.

Now the only issue I have is figuring out how to reinitialize an SD card when it's been removed. The idea was that one button would "mount" the card, and when pressed again would "unmount" the card however I have found out that once the card is unmounted and swapped, the Arduino has to be reset before pressing the button mounts the card.

Do you have any suggestions on how I can dynamically start and stop the SD card without having to resort to an Arduino reset?

Thank you all for your help and suggestions!

You need to patch the SD.h library. Add root.close() to begin().

Here is a link to more info: http://arduino.cc/forum/index.php/topic,66415.0.html