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.

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