// A simple data logger for the Arduino analog pins with optional DS1307 // uses RTClib from https://github.com/adafruit/RTClib #include #include "SdFat.h" #include "FreeStack.h" #define SD_CHIP_SELECT SS // SD chip select pin #define USE_DS1307 0 // set nonzero to use DS1307 RTC #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 if nonzero #define WAIT_TO_START 1 // Wait for serial input in setup() #define ADC_DELAY 10 // ADC delay for high impedence sensors // 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(F(s)) //------------------------------------------------------------------------------ #if USE_DS1307 // use RTClib from Adafruit // https://github.com/adafruit/RTClib // The Arduino IDE has a bug that causes Wire and RTClib to be loaded even // if USE_DS1307 is false. #error remove this line and uncomment the next two lines. //#include //#include 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); // Wait for USB Serial. while (!Serial) { SysCall::yield(); } // F() stores strings in flash to save RAM cout << endl << F("FreeStack: ") << FreeStack() << endl; #if WAIT_TO_START cout << F("Type any character to start\n"); while (!Serial.available()) { SysCall::yield(); } // Discard input. do { delay(10); } while(Serial.available() && Serial.read() >= 0); #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 at the highest speed supported by the board that is // not over 50 MHz. Try a lower speed if SPI errors occur. if (!sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) { 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 << F("Logging to: ") << name << endl; cout << F("Type any character to stop\n\n"); // format header in buffer obufstream bout(buf, sizeof(buf)); bout << F("millis"); #if USE_DS1307 bout << F(",date,time"); #endif // USE_DS1307 for (uint8_t i = 0; i < SENSOR_COUNT; i++) { bout << F(",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 // USE_DS1307 // 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 and flush to SD logfile << buf << 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); } if (!Serial.available()) { return; } logfile.close(); cout << F("Done!"); SysCall::halt(); }