Data Logging on event only

Hi

I am relatively new to the Arduino and programming so my request may sound simple.

I have a very simple switch that i would like to monitor (on and off) and i can easily monitor this by serial and logging over time. However, i need to log this only when the change occurs (1 or 0) and also record the time between each change. The current method that im using which cycles every so many seconds throws up too much data.

Any help or recommendations would be very helpful.

My current sketch is below and is based on the ladyada logger

#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

// A simple data logger for the Arduino analog pins

// how many milliseconds between grabbing data and logging it. 1000 ms is once a second
#define LOG_INTERVAL  500 // mills between entries (reduce to take more/faster data)

// how many milliseconds before writing the logged data permanently to disk
// set it to the LOG_INTERVAL to write each time (safest)
// set it to 10*LOG_INTERVAL to write all data every 10 datareads, you could lose up to 
// the last 10 reads if power is lost but it uses less power and is much faster!
#define SYNC_INTERVAL 500 // mills between calls to flush() - to write data to the card
uint32_t syncTime = 0; // time of last sync()

#define ECHO_TO_SERIAL   1 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()

// the digital pins that connect to the LEDs
#define redLEDpin 12
#define greenLEDpin 13


const int buttonPin = 2;   


// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

RTC_DS1307 RTC; // define the Real Time Clock object

// for the data logging shield, we use digital pin 10 for the SD cs line
const int chipSelect = 10;

// the logging file
File logfile;

void error(char *str)
{
  Serial.print("error: ");
  Serial.println(str);
  
  // red LED indicates error
  digitalWrite(redLEDpin, HIGH);

  while(1);
}

void setup(void)
{
  Serial.begin(9600);
  Serial.println();
  
  // use debugging LEDs
  pinMode(redLEDpin, OUTPUT);
  pinMode(greenLEDpin, OUTPUT);
  
#if WAIT_TO_START
  Serial.println("Type any character to start");
  while (!Serial.available());
#endif //WAIT_TO_START

  // initialize the SD card
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    error("Card failed, or not present");
  }
  Serial.println("card initialized.");
  
  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      break;  // leave the loop!
    }
  }
  
  if (! logfile) {
    error("couldnt create file");
  }
  
  Serial.print("Logging to: ");
  Serial.println(filename);

  // connect to RTC
  Wire.begin();  
  if (!RTC.begin()) {
    logfile.println("RTC failed");
#if ECHO_TO_SERIAL
    Serial.println("RTC failed");
#endif  //ECHO_TO_SERIAL
  }
  

  logfile.println("millis,stamp,datetime,buttonState");    
#if ECHO_TO_SERIAL
  Serial.println("millis,stamp,datetime,buttonState");
#endif //ECHO_TO_SERIAL
 
  // If you want to set the aref to something other than 5v
 
}

void loop(void)
{
  DateTime now;

  // delay for the amount of time we want between readings
  delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
  
  digitalWrite(greenLEDpin, HIGH);
  
  // log milliseconds since starting
  uint32_t m = millis();
  logfile.print(m);           // milliseconds since start
  logfile.print(", ");    
#if ECHO_TO_SERIAL
  Serial.print(m);         // milliseconds since start
  Serial.print(", ");  
#endif

  // fetch the time
  now = RTC.now();
  // log time
  logfile.print(now.unixtime()); // seconds since 1/1/1970
  logfile.print(", ");
  logfile.print('"');
  logfile.print(now.year(), DEC);
  logfile.print("/");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print(" ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  logfile.print('"');
#if ECHO_TO_SERIAL
  Serial.print(now.unixtime()); // seconds since 1/1/1970
  Serial.print(", ");
  Serial.print('"');
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  Serial.print('"');
#endif //ECHO_TO_SERIAL

 
  buttonState = digitalRead(buttonPin);
 
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH)   { 
       logfile.print(", ");            // (",") Starts a new column for next data series
       logfile.print("HIGH");
       logfile.println(buttonState,0); // println returns each reading and starts a new row
       Serial.print(", ");
      Serial.print("HIGH");
      Serial.println (buttonState,0);  // ,0 = dictates number of decimal places
}
  else {
    logfile.print(", ");
    logfile.print("LOW");
    logfile.println(buttonState,0);
    Serial.print(", ");
    Serial.print("LOW");
    Serial.println(buttonState,0);
    
  }

  digitalWrite(greenLEDpin, LOW);

  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses a bunch of power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();
  
  // blink LED to show we are syncing data to the card & updating FAT!
  digitalWrite(redLEDpin, HIGH);
  logfile.flush();
  digitalWrite(redLEDpin, LOW);
 }

Surely all you need to do is record the time (from the real time clock or from millis()) whenever the switch is thrown?

...R

The problem i have is the number of times the switch is thrown (1000+). As it records the switch state every 5000 milli seconds (over a period of up to 7 days (n = 1,209,600 readings), i then have to aggregate all the highs and lows when i collect the data before i can process it. If it just recorded the state every time the switch was triggered and then gave me the time it spent in each state, that would give me data that could be processed immediately.

As i previously mentioned i am new to this and trying to learn very fast. I'm still trying to get my head round some of the terminology, how the system works and limitations.

I appreciate any help, just remember i am a novice :)

Start with the state change detection example - this shows you how to detect when the switch input has changed state.

Each time it changes state, write a message to the log. If you need to know the interval since the previous change you can calculate that by recording the time of the previous change and subtracting it from the current time, and include that in the message; remember to update the saved time to 'now' afterwards, ready for the next event. If you want to include a wallclock time in the log, use the usual techniques to get this from the RTC. However, don't use the RTC to calculate intervals and elapsed time and so on over short timescales - just use it to generate a timestamp for the data at the point of logging.

If you wrote the logged data directly to the serial port and stored it on a PC, you could do all this timestamping on the PC e.g. using the timestamping option in Realterm.

chrissybing:
The problem i have is the number of times the switch is thrown (1000+). As it records the switch state every 5000 milli seconds (over a period of up to 7 days (n = 1,209,600 readings), i then have to aggregate all the highs and lows when i collect the data before i can process it. If it just recorded the state every time the switch was triggered and then gave me the time it spent in each state, that would give me data that could be processed immediately.

That seems a very different requirement from your original post.

Would it be sufficient just to have two unsigned long variables (one for ON time and one for OFF time) and whenever the switch state changes just add the elapsed time to the relevant variable. You could also keep a count of the events in another variable. At the end of 7 days you have three values to work with.

And rather than test the switch position every 5 seconds, just do stuff when the switch changes.

If I have misunderstood your requirement please explain it in more detail.

…R