SD Card - Data Logger with TimeStamp

Hello everyone,

I made two functions for data logging in my webserver project, and I would like another people opnion about it.
I used this functions to replace the Serial.print and Serial.println, to print the text to the serial and log it to the SD Card (both with timeStamps).

printSDln("Initializing Arduino", true);

void printSD(char *data, boolean stamp) {
  logFile = SD.open("logs.txt", FILE_WRITE);
  if (logFile) {
    if (stamp == true) {
      char timeStamp[22];
      sprintf(timeStamp, "[%02d/%02d/%02d][%02d:%02d:%02d] ", day(), month(), (year() - 2000), hour(), minute(), second());
      Serial.print(timeStamp);
      logFile.print(timeStamp);
    }
    logFile.print(data);
    Serial.print(data);
    logFile.close();
  }
  else {
    Serial.println("printSD failed");
  }
}
void printSDln(char *data, boolean stamp) {
  logFile = SD.open("logs.txt", FILE_WRITE);
  if (logFile) {
    if (stamp == true) {
      char timeStamp[22];
      sprintf(timeStamp, "[%02d/%02d/%02d][%02d:%02d:%02d] ", day(), month(), (year() - 2000), hour(), minute(), second());
      Serial.print(timeStamp);
      logFile.print(timeStamp);
    }
    Serial.println(data);
    logFile.println(data);
    logFile.close();
  }
  else {
    Serial.println("printSDln failed");
  }
}

The only problem I have is printing / logging byte’s, int’s etc., since I passed it as a char array.
I don’t know how to made a function that could print “any type”… I kinda “handled” it using itoa() for int’s, but byte’s I couldn’t even figure anything.

int randomNumber = random(0, 60);
    char Number [2];
    itoa(randomNumber, Number, 10);
          byte IP [4] = {192, 168, 0, 1}
          Serial.print("Client IP: ");
          for (int i = 0; i < 4; i++) {
            Serial.print(clientIP[i]);
            if (i < 3 ) {
              Serial.print(".");
            }
            else {
              Serial.println();
            }
      char timeStamp[22] = {sprintf(timeStamp, "[%02d/%02d/%02d][%02d:%02d:%02d] ", day(), month(), (year() - 2000), hour(), minute(), second())};

Nonsense.

Do it properly!

      char timeStamp[22];
      sprintf(timeStamp, "[%02d/%02d/%02d][%02d:%02d:%02d] ",
              day(), month(), (year() - 2000), hour(), minute(), second());

Adding a space between the time stamp, if present, and the data would be useful.

void printSDln(char *data, boolean stamp) {
  logFile = SD.open("logs.txt", FILE_WRITE);
  if (logFile) {
   }
  else {
    Serial.println("printSD failed");

printSD failed, huh?

Thanks PaulS,

I was trying another way (that didn't work by the way) and I forgot to turn it back before posting.

      char timeStamp[22];
      sprintf(timeStamp, "[%02d/%02d/%02d][%02d:%02d:%02d] ",
              day(), month(), (year() - 2000), hour(), minute(), second());

printSD failed, huh?

I was using a variable filename with the date (24.09.14.txt) so I added this else for the if (logFile), to print an error in case the file wasn't created properly.

I was using a variable filename with the date (24.09.14.txt) so I added this else for the if (logFile), to print an error in case the file wasn't created properly.

But, shouldn't the printSDln() function report that printSDln() failed? It's hard to track down causes of failures when a function says some other function failed. Suppose analogRead() wrote a message saying that digitalRead failed. You'd go crazy trying to figure that one out.

You could have one function that takes three arguments:

void printSD(char *data, boolean stamp, boolean withCRLF) {
  logFile = SD.open("logs.txt", FILE_WRITE);
  if (logFile)
  {
    if (stamp)
    {
      char timeStamp[22];
      sprintf(timeStamp,
           "[%02d/%02d/%02d][%02d:%02d:%02d] ",
           day(), month(), (year() - 2000), hour(), minute(), second());
      Serial.print(timeStamp);
      logFile.print(timeStamp);
    }

    logFile.print(data);
    if(withCRLF)
       logFile.println();
    Serial.print(data);
    if(withCRLF)
       Serial.println();
    logFile.close();
  }
  else
  {
    Serial.println("printSD failed");
  }
}

You are right again, kkkkk...

Actually I tried that but, I end up using two functions like print and println.

But and about the int's and byte's? Do you know anyway of handle "all" kind of data? I had a look at print.h but I couldn't understand how it is done, with the "overloading" (if this is the way to go).

I had a look at print.h but I couldn't understand how it is done, with the "overloading" (if this is the way to go).

Print is a class. There are multiple print() methods defined in the class, each taking a different kind of argument.

Either the function needs to convert the data to a string, the logFile.print() method does, or the caller of your function does. No one way is faster than another. No one way uses fewer resources.

So, there is no real advantage in providing the capability to handle multiple types.

You could have less redundant data in each function if you created a function to make and log the time stamp string. Have a function that opens the file. Then, printSDInt() would call the openFile() function, the logTimeStamp() function, if needed, and then do the unique stuff and close the file. printSDFloat() would do the same. Not pretty, but short of using a template, there is no other way.

I'm sure Nick will be along soon to describe how to use a template.