You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
5.1KB

  1. // A simple data logger for the Arduino analog pins with optional DS1307
  2. // uses RTClib from https://github.com/adafruit/RTClib
  3. #include <SPI.h>
  4. #include "SdFat.h"
  5. #include "sdios.h"
  6. #include "FreeStack.h"
  7. #define SD_CHIP_SELECT SS // SD chip select pin
  8. #define USE_DS1307 0 // set nonzero to use DS1307 RTC
  9. #define LOG_INTERVAL 1000 // mills between entries
  10. #define SENSOR_COUNT 3 // number of analog pins to log
  11. #define ECHO_TO_SERIAL 1 // echo data to serial port if nonzero
  12. #define WAIT_TO_START 1 // Wait for serial input in setup()
  13. #define ADC_DELAY 10 // ADC delay for high impedence sensors
  14. // file system object
  15. SdFat sd;
  16. // text file for logging
  17. ofstream logfile;
  18. // Serial print stream
  19. ArduinoOutStream cout(Serial);
  20. // buffer to format data - makes it eaiser to echo to Serial
  21. char buf[80];
  22. //------------------------------------------------------------------------------
  23. #if SENSOR_COUNT > 6
  24. #error SENSOR_COUNT too large
  25. #endif // SENSOR_COUNT
  26. //------------------------------------------------------------------------------
  27. // store error strings in flash to save RAM
  28. #define error(s) sd.errorHalt(F(s))
  29. //------------------------------------------------------------------------------
  30. #if USE_DS1307
  31. // use RTClib from Adafruit
  32. // https://github.com/adafruit/RTClib
  33. // The Arduino IDE has a bug that causes Wire and RTClib to be loaded even
  34. // if USE_DS1307 is false.
  35. #error remove this line and uncomment the next two lines.
  36. //#include <Wire.h>
  37. //#include <RTClib.h>
  38. RTC_DS1307 RTC; // define the Real Time Clock object
  39. //------------------------------------------------------------------------------
  40. // call back for file timestamps
  41. void dateTime(uint16_t* date, uint16_t* time) {
  42. DateTime now = RTC.now();
  43. // return date using FAT_DATE macro to format fields
  44. *date = FAT_DATE(now.year(), now.month(), now.day());
  45. // return time using FAT_TIME macro to format fields
  46. *time = FAT_TIME(now.hour(), now.minute(), now.second());
  47. }
  48. //------------------------------------------------------------------------------
  49. // format date/time
  50. ostream& operator << (ostream& os, DateTime& dt) {
  51. os << dt.year() << '/' << int(dt.month()) << '/' << int(dt.day()) << ',';
  52. os << int(dt.hour()) << ':' << setfill('0') << setw(2) << int(dt.minute());
  53. os << ':' << setw(2) << int(dt.second()) << setfill(' ');
  54. return os;
  55. }
  56. #endif // USE_DS1307
  57. //------------------------------------------------------------------------------
  58. void setup() {
  59. Serial.begin(9600);
  60. // Wait for USB Serial.
  61. while (!Serial) {
  62. SysCall::yield();
  63. }
  64. // F() stores strings in flash to save RAM
  65. cout << endl << F("FreeStack: ") << FreeStack() << endl;
  66. #if WAIT_TO_START
  67. cout << F("Type any character to start\n");
  68. while (!Serial.available()) {
  69. SysCall::yield();
  70. }
  71. // Discard input.
  72. do {
  73. delay(10);
  74. } while(Serial.available() && Serial.read() >= 0);
  75. #endif // WAIT_TO_START
  76. #if USE_DS1307
  77. // connect to RTC
  78. Wire.begin();
  79. if (!RTC.begin()) {
  80. error("RTC failed");
  81. }
  82. // set date time callback function
  83. SdFile::dateTimeCallback(dateTime);
  84. DateTime now = RTC.now();
  85. cout << now << endl;
  86. #endif // USE_DS1307
  87. // Initialize at the highest speed supported by the board that is
  88. // not over 50 MHz. Try a lower speed if SPI errors occur.
  89. if (!sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
  90. sd.initErrorHalt();
  91. }
  92. // create a new file in root, the current working directory
  93. char name[] = "logger00.csv";
  94. for (uint8_t i = 0; i < 100; i++) {
  95. name[6] = i/10 + '0';
  96. name[7] = i%10 + '0';
  97. if (sd.exists(name)) {
  98. continue;
  99. }
  100. logfile.open(name);
  101. break;
  102. }
  103. if (!logfile.is_open()) {
  104. error("file.open");
  105. }
  106. cout << F("Logging to: ") << name << endl;
  107. cout << F("Type any character to stop\n\n");
  108. // format header in buffer
  109. obufstream bout(buf, sizeof(buf));
  110. bout << F("millis");
  111. #if USE_DS1307
  112. bout << F(",date,time");
  113. #endif // USE_DS1307
  114. for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
  115. bout << F(",sens") << int(i);
  116. }
  117. logfile << buf << endl;
  118. #if ECHO_TO_SERIAL
  119. cout << buf << endl;
  120. #endif // ECHO_TO_SERIAL
  121. }
  122. //------------------------------------------------------------------------------
  123. void loop() {
  124. uint32_t m;
  125. // wait for time to be a multiple of interval
  126. do {
  127. m = millis();
  128. } while (m % LOG_INTERVAL);
  129. // use buffer stream to format line
  130. obufstream bout(buf, sizeof(buf));
  131. // start with time in millis
  132. bout << m;
  133. #if USE_DS1307
  134. DateTime now = RTC.now();
  135. bout << ',' << now;
  136. #endif // USE_DS1307
  137. // read analog pins and format data
  138. for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
  139. #if ADC_DELAY
  140. analogRead(ia);
  141. delay(ADC_DELAY);
  142. #endif // ADC_DELAY
  143. bout << ',' << analogRead(ia);
  144. }
  145. bout << endl;
  146. // log data and flush to SD
  147. logfile << buf << flush;
  148. // check for error
  149. if (!logfile) {
  150. error("write data failed");
  151. }
  152. #if ECHO_TO_SERIAL
  153. cout << buf;
  154. #endif // ECHO_TO_SERIAL
  155. // don't log two points in the same millis
  156. if (m == millis()) {
  157. delay(1);
  158. }
  159. if (!Serial.available()) {
  160. return;
  161. }
  162. logfile.close();
  163. cout << F("Done!");
  164. SysCall::halt();
  165. }