Writing data to file on SD card

Hi,

Firstly, apologies for the very clunky coding attempt that I will attach to this post but am still very high on the learning curve. You'll probably recognise Blink in the sketch and see that I've progressed from that. Here is the code:

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */
 
#include <Wire.h>
#include "RTClib.h"
#include <SPI.h>
#include <SD.h>
#include <AcceleroMMA7361.h>


AcceleroMMA7361 accelero;
int x;
int y;
int z;



// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
RTC_Millis rtc;

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

File dataFile;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT); 
Serial.begin(9600);

accelero.begin(13, 12, 11, 10, A0, A1, A2);
  accelero.setARefVoltage(3.3);                   //sets the AREF voltage to 3.3V
  accelero.setSensitivity(HIGH);                   //sets the sensitivity to +/-6G
  accelero.calibrate();
  
  
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }  
  
  rtc.begin(DateTime(__DATE__, __TIME__));
  
    Serial.println("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);


  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  while (!card.init(SPI_HALF_SPEED, 4)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
  } 
  
  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }
 
  
  //Serial.print("Time  Ch0,Ch1,Ch2");
  //Serial.println("\n");
}

// the loop routine runs over and over again forever:
void loop() {
  
  x = accelero.getXRaw();
  y = accelero.getYRaw();
  z = accelero.getZRaw();
  Serial.print("\nx: ");
  Serial.print(x);
  Serial.print("\ty: ");
  Serial.print(y);
  Serial.print("\tz: ");
  Serial.print(z);
  delay(250);    //(make it readable)
  
  Serial.print("\t");              // prints a tab
  
  String dataString = "";
  
  DateTime now = rtc.now();
  
  dataString += now.day();
  dataString += "/";
  dataString += now.month();
  dataString += "/";
  dataString += now.year();
  dataString += " ";
  dataString += now.hour();
  dataString += ":";
  dataString += now.minute();
  dataString += ":";
  dataString += now.second();
  
  
  //dataString += " ";
  //dataString += " ";
  
  //dataString += String(analogRead(0));
  //dataString += ",";
  //dataString += String(analogRead(1));
  //dataString += ",";
  //dataString += String(analogRead(2));
  
  
  
    dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
   
  }
  
    Serial.println(dataString);
  dataFile.println(dataString);
  //dataFile.flush();
  
  int i = 0;  //Use this for the counter

  
   // print to the serial port too:
  //Serial.println(' ');
  // The line dataFile.flush() will 'save' the file to the SD card after every
  // line of data - this will use more power and slow down how much data
  // you can read but it's safer!
  // If you want to speed up the system, call flush() less often and it
  // will save the file only when called and every 512 bytes - every time a sector on the
  // SD card is filled with data. However, don't depend on the automatic flush!
  i++;
  if (i>50){  //Call every 50 times
    dataFile.flush();
    i = 0;
  }
  
  
  
  while (dataFile.available()) {
      Serial.write(dataFile.read());
    }
  
  
  
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(250);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(250);               // wait for a second
}

My aim is to take the data from an MMA 7361 analogue accelerometer and a DS1307 RTC and write the x, y and z values with a date and time stamp to a file, datalog.txt, on the SD card.

I haven't currently been able to do that and I can't work out why.

Using the serial monitor I can see the data presented in the format I want so the Mega/MMA7361 and RTC are all working correctly. See attachment.

Grateful for advice on how to achieve the data write to the card.

Once I have the data being captured on the card I would like to progress this project by closing the file at 23:59:59 and creating a new file at 00:00:05 the next day with a file name of the new date. Is that possible?

Finally I want to add an Ethernet capability to allow the files to be accessed remotely.

But at current rate of progress I think tat is a long way off >:(

wtfdika:
I haven't currently been able to do that and I can't work out why.

Don't try too much at once!

What type of Arduino board are you using?
What type of SD-module are you using?

Do you try to use the SD card slot on an Ethernet-Shield? Or maybe you use the same module as the guy in this thread does?

Did you try to run some of the SD library programming examples that came with the SD library?
Did that work?

Hi,

Am using a Mega and the SD card is in the Ethernet shield attached to it.

Interesting thought about running some of the SD card examples. Hadn't done but will get onto that right now.

Appreciate the input.

wtfdika:
Am using a Mega and the SD card is in the Ethernet shield attached to it.

Interesting thought about running some of the SD card examples. Hadn't done but will get onto that right now.

When using the MEGA and the Ethernet-Shield and you want to use the SD-Card with some of the examples of the SD-library or with your own code, please be sure that you change this line from the example code:

pinMode(10, OUTPUT); // Atmega328 boards only

to such a line

pinMode(SS, OUTPUT); // set Slave Select as OUTPUT

Only on the Atmega328 boards pin-10 is the hardware Slave-Select (aka "Chip-Select") pin. To be compatible with different boards, do no set pin-10 as OUTPUT, but the pre-defined SS pin.

Hi,

Just finished doing the tests and attached the screen grabs.

Using those examples both the SDTest and the SD Read/Write worked perfectly (That said the first version of SD Read/Write I used didn't have the line #include <SPI.h> so I got a compile error.

Will adjust the sketch in accordance with your advice and get back to you.

Have modd'ed the sketch as per your suggestion with no discernible ill effects but, having checked the SD card (by plugging it into my laptop) the only file I can see on it is the TEST.TXT file written during the example read/write.

Having looked at the sketch I can see that the read/write sketch has a line myFile.close() Could it be that the data is only written to the file on receipt of a close command and that my datalog file is not population as I'm not sending a close command?

I had hoped that using the code below would write the data to the file every 50 writes

 Serial.println(dataString);
  dataFile.println(dataString);
  //dataFile.flush();
  
  int i = 0;  //Use this for the counter

  
   // print to the serial port too:
  //Serial.println(' ');
  // The line dataFile.flush() will 'save' the file to the SD card after every
  // line of data - this will use more power and slow down how much data
  // you can read but it's safer!
  // If you want to speed up the system, call flush() less often and it
  // will save the file only when called and every 512 bytes - every time a sector on the
  // SD card is filled with data. However, don't depend on the automatic flush!
  i++;
  if (i>50){  //Call every 50 times
    dataFile.flush();
    i = 0;
  }

Seems I might have been wrong?

wtfdika:
Having looked at the sketch I can see that the read/write sketch has a line myFile.close() Could it be that the data is only written to the file on receipt of a close command and that my datalog file is not population as I'm not sending a close command?

With the FAT file system, the data is written in "sectors" of 512 bytes each.
So while a file is open, the SD library will buffer all the writes until 512 Bytes are sent to the SD card, then the full sector of 512 bytes will be written to the SD card.

BUT: The FAT (File Allocation Table) is NOT updated while the file is not closed. So the file size stored in the FAT will always be the same while the file is open. Only after a file is closed:

  • partially filled sector data (below 512 bytes) will be written to the card
  • the new file size will be written to the FAT

So if a file is open and not closed correctly and you remove the card, you might find, that the file size is the same size as the file had when it was correctly closed the last time before.