Here is a data logging sketch that I developed for a shield with an SD card and an optional DS1307 RTC.
It illustrates new features in V2 of the SdFat library. It can be easily modified for specific applications.
It has time stamped files - Windows dir listing:
C++ style I/O for simpler and better data formatting.04/06/2011 07:30 AM 684 LOGGER15.CSV
04/06/2011 07:51 AM 4,954 LOGGER16.CSV
04/06/2011 07:55 AM 606 LOGGER17.CSV
04/06/2011 08:02 AM 9,665 LOGGER18.CSV
Code to print time and date to Serial.
DateTime now = RTC.now();
cout << now << endl;
The result is:
Sample logfile - note zero fill in minutes and seconds2011/4/6 7:57:41
Better error handling and messages.millis,date time,sens0,sens1,sens2
141000,2011/4/6 7:59:58,211,209,203
142000,2011/4/6 7:59:59,211,209,203
143000,2011/4/6 8:00:00,211,208,203
144000,2011/4/6 8:00:01,211,208,203
145000,2011/4/6 8:00:02,211,208,203
146000,2011/4/6 8:00:03,210,209,203
init failure message:
To use this sketch install RTClibCan’t access SD card. Do not reformat.
SD errorCode: 1
No card or SPI problem?
https://github.com/adafruit/RTClib
Install the new beta version of SdFat
http://code.google.com/p/beta-lib/downloads/list
// A simple data logger for the Arduino analog pins
#define LOG_INTERVAL 1000 // mills between entries
#define SENSOR_COUNT 3 // number of analog pins to log
#define ECHO_TO_SERIAL 1 // echo data to serial port
#define WAIT_TO_START 1 // Wait for serial input in setup()
#define ADC_DELAY 10 // switch ADC and delay for high impedence sensors
#define USE_DS1307 1 // shield has DS1307 RTC
#include <SdFat.h>
#include <SdFatUtil.h> // define FreeRam()
// file system object
SdFat sd;
// text file for logging
ofstream logfile;
// Serial print stream
ArduinoOutStream cout(Serial);
// buffer to format data - makes it eaiser to echo to Serial
char buf[80];
//------------------------------------------------------------------------------
#if SENSOR_COUNT > 6
#error SENSOR_COUNT too large
#endif // SENSOR_COUNT
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
//------------------------------------------------------------------------------
#if USE_DS1307
#include <Wire.h>
// get RTClib from Adafruit here
// https://github.com/adafruit/RTClib
#include "RTClib.h"
RTC_DS1307 RTC; // define the Real Time Clock object
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
DateTime now = RTC.now();
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(now.year(), now.month(), now.day());
// return time using FAT_TIME macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second());
}
// format date/time
ostream& operator << (ostream& os, DateTime& dt) {
os << dt.year() << '/' << int(dt.month()) << '/' << int(dt.day()) << ' ';
os << int(dt.hour()) << ':' << setfill('0') << setw(2) << int(dt.minute());
os << ':' << setw(2) << int(dt.second()) << setfill(' ');
return os;
}
#endif // USE_DS1307
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// pstr stores strings in flash to save RAM
cout << endl << pstr("FreeRam: ") << FreeRam() << endl;
#if WAIT_TO_START
cout << pstr("Type any character to start\n");
while (!Serial.available());
#endif // WAIT_TO_START
#if USE_DS1307
// connect to RTC
Wire.begin();
if (!RTC.begin()) error("RTC failed");
// set date time callback function
SdFile::dateTimeCallback(dateTime);
DateTime now = RTC.now();
cout << now << endl;
#endif // USE_DS1307
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
// if SD chip select is not SS, the second argument to init is CS pin number
if (!sd.init(SPI_HALF_SPEED)) sd.initErrorHalt();
// create a new file in root, the current working directory
char name[] = "LOGGER00.CSV";
for (uint8_t i = 0; i < 100; i++) {
name[6] = i/10 + '0';
name[7] = i%10 + '0';
if (sd.exists(name)) continue;
logfile.open(name);
break;
}
if (!logfile.is_open()) error("file.open");
cout << pstr("Logging to: ") << name << endl;
//format header in buffer
obufstream bout(buf, sizeof(buf));
bout << pstr("millis");
#if USE_DS1307
bout << pstr(",date time");
#endif USE_DS1307
for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
bout << pstr(",sens") << int(i);
}
logfile << buf << endl;
#if ECHO_TO_SERIAL
cout << buf << endl;
#endif // ECHO_TO_SERIAL
}
//------------------------------------------------------------------------------
void loop() {
uint32_t m;
// wait for time to be a multiple of interval
do {
m = millis();
} while(m % LOG_INTERVAL);
// use buffer stream to format line
obufstream bout(buf, sizeof(buf));
// start with time in millis
bout << m;
#if USE_DS1307
DateTime now = RTC.now();
bout << ',' << now;
#endif
// read analog pins and format data
for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
#if ADC_DELAY
analogRead(ia);
delay(ADC_DELAY);
#endif // ADC_DELAY
bout << ',' << analogRead(ia);
}
bout << endl;
// log data
logfile << buf;
// flush data to SD
logfile.flush();
// check for error
if (!logfile) error("write data failed");
#if ECHO_TO_SERIAL
cout << buf;
#endif // ECHO_TO_SERIAL
// don't log two points in the same millis
if (m == millis()) delay(1);
}