Date stamp on a SD file from a real time clock

I am working on a testing system that datalogs the test data to a SD card. The tester can do multiple test without removing the SD card and a new file is made each time. I want to add the date/time to the file when created, just makes a common date for each file now.

I found this thread on the forum. Add DATE and TIME to your SD CARD Files. - Storage - Arduino Forum, and it works great. In this sketch you hard code the date and time in.

For my system I have a realtime clock and would like to have this code read the date/time when the file is created and use that. I have added the RTC library and can read the date/time, I create my instance, "DateTime now;" so now when I log the month I use "(now.month(), DEC)" I tried several ways to convert one to the other but obviously it didn't work or I wouldn't be asking on the forum.

Referencing the code in the mentioned thread I would like to change this line

"byte month = 6;" to "byte month = now.month();"

How would I do that?

Thanks
John

1 Like

you would have to initialize the variables before creating your sd card file. As they are global, they would be used by the call back. You can create a function updateVariablesForTimeStamp() that you would call before creating files.

Assuming you use a DS3231, that's the way to read the 6 values

#include <RTClib.h> // https://github.com/adafruit/RTClib
RTC_DS3231 rtc;

unsigned int year = 2019;
byte month = 11;
byte day = 15;
byte hour = 15;
byte minute = 45;
byte second = 22;

// CALL THIS FUNCTION BEFORE DOING FILE OPERATIONS
void updateVariablesForTimeStamp()
{
  DateTime now = rtc.now();
  // HERE IS THE DATA YOU NEED TO UPDATE BEFORE THE dateTime Callback is called
  year = now.year();
  month = now.month();
  day = now.day();
  second = now.second();
  minute = now.minute();
  hour = now.hour();
}

void setup() {
  Serial.begin(115200);

  if (! rtc.begin()) {
    Serial.println(F("NO RTC"));
    while (1);
  }

  if (rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Need to initialize RTC, we use the last compile time of this sketch
}

void loop() {
}

(typed here, totally untested)

Thanks so much for your reply. Actually the RTC is a PCF8523, not sure if that makes much of a difference. Declaring the variables first then assigning the RTC variable to them makes sense, I will add that tonight.

The if statement you have is that to update the RTC time? I had to use a similar line this morning. Mine was still off by an hour because of daylight savings. Actually I tried it and it didn't work, I had to pull the battery out, put it back in then it worked, but that's another issue than this one.

I'll give your suggestion a try later and let you know how I make out.

Thanks again
John

Stumpy_L:
The if statement you have is that to update the RTC time? I had to use a similar line this morning. Mine was still off by an hour because of daylight savings. Actually I tried it and it didn't work, I had to pull the battery out, put it back in then it worked, but that's another issue than this one.

Yes, some RTCs are able to detect they have not been setup (ie they lost time because the attached battery died or they were never setup). The macros F(__DATE__), F(__TIME__) give you the date and time of the last compilation (binary generation). if your computer has the right time, it should work. You can see those values if you do:

void setup() {
  Serial.begin(115200);
  Serial.println(F(__DATE__));
  Serial.println(F(__TIME__));
}

void loop() {}
1 Like

That's good to know,

Thanks for the info
John

J-M-L

Close but no cigar. I moved the definitions of the variables to be global. I then ran it but there was no difference. I also noticed that the variables in the function were a highlighted color, like Serial.print is, so I thought they must be reserved words. For example "year" in the statement year = now.year(); was highlighted. I changed that to SDyear, added SD to the others as well, made no difference other than SDyear was not highlighted.

The statement that logs the date in the SD file is "logfile.print(now.year(), DEC);" if I used that format, adding the DEC, I get different results. I added print statements to monitor what the values were.

without the DEC
month, day, year, hour, minute,seconds = 10. The date on the file is 10/10/2058 11:10, the date/time in the file is correct

with DEC
month, day = 1, year = 2000, hour, minute, second = 0, The date on the file is 1/1/200 12:00 AM, the date/time in the file is correct.

I'm thinking it has something to do with either how the variables are defined, how the RTC value is set to the SDyear variable as opposed to how the RTC variable is used in the logfile.print statement.

I have the test function on a separate tab in the sketch, it is called when the test is started by pressing a button on the display screen. Here is how I've declared the variables

// for date stamp on SD file
unsigned int SDyear = 2019;
byte SDmonth = 11;
byte SDday = 15;
byte SDhour = 6;
byte SDminute = 11;
byte SDsecond = 00;

and here is the function

// for adding current date and time to SD file
void dateTime(uint16_t* date, uint16_t* time)
{
  DateTime now; // read RTC
  SDyear = now.year();
  SDmonth = now.month();
  SDday = now.day();
  SDhour = now.hour();
  SDminute = now.minute();
  SDsecond = now.second();
  *date = FAT_DATE(SDyear, SDmonth, SDday);
  *time = FAT_TIME(SDhour, SDminute, SDsecond);

  Serial.print("month =   "); 
  Serial.print(SDmonth);    
  Serial.print("  "); 
  Serial.print("day =   "); 
  Serial.print(SDday);    
  Serial.print("  "); 
  Serial.print("year =   "); 
  Serial.print(SDyear);   
  Serial.print("  "); 
  Serial.print("hour =   "); 
  Serial.print(SDhour);  
  Serial.print("  "); 
  Serial.print("minute =   "); 
  Serial.print(SDminute);   
  Serial.print("  "); 
  Serial.print("second =   "); 
  Serial.println(SDsecond);    
 }

// Pump Test logic and data logging
void Pump_Test()
{
  // read limit switches
fwdLS_status = digitalRead(fwdLS);
revLS_status = digitalRead(revLS);

if(cycleStep <= 0){
  cycleStep = 1;
  cycleCount = 0;
  
  // 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)) {
    errorNumb = 1;
    error("Card failed, or not present");
    }
  Serial.println("card initialized.");

 

SdFile::dateTimeCallback(dateTime); // sets file date

// create a new file

  char filename[] = "LogFile00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[7] = i/10 + '0';
    filename[8] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE); 
      strcpy(logFileName, filename);
      break;  // leave the loop!
    } // end if (! SD.exist)
  } // end for (uint8_t i = 0; i < 100; i++)
 
 if (! logfile) { // checks that logfile created
    errorNumb = 2;
    error("couldnt create file");
    } // end (! logfile)

DateTime now; // read RTC

 // fetch the time
  now = RTC.now();

  logfile.print("Test # = ");  
  logfile.print(", ");
  logfile.print(testNumb);  
  logfile.print(", ");
  logfile.print("Serial # = ");  
  logfile.print(", ");
  logfile.print(serialNumb);
  logfile.print(", ");
  logfile.print("Date ");
  logfile.print(", ");
  logfile.print(now.month(), DEC);
  logfile.print("/");
  logfile.print(now.day(), DEC);
  logfile.print("/");
  logfile.print(now.year(), DEC);
  logfile.print(" ");
  logfile.print(", ");
  logfile.print("Time ");
  logfile.print(", ");
  logfile.print(now.hour(), DEC);
  logfile.print(":");
  logfile.print(now.minute(), DEC);
  logfile.print(":");
  logfile.print(now.second(), DEC);
  logfile.print(" ");
  logfile.println();
  logfile.print("Cycle Count,Fwd Time,Rev Time,Voltage");
  logfile.println();

  // Close file
      logfile.close();
      
  }  // end if(cycleStep <= 0)

  switch(cycleStep){
    case 1:
      pulseFwdIn = map(TestBattIn, 0, 1025, 0, 255); // turn fwd on
      analogWrite(pulseFwd,(pulseFwdIn - 25));

      if(fwdPlsStart == 0){
          fwdStart = millis(); // capture forward pulse start time
          fwdPlsStart = 1; // set forward pulse has started bit
      }
      
      pulseRevIn = 0; // turn rev off
      analogWrite(pulseRev,pulseRevIn);
      
        if(fwdLS_status == HIGH){
          pulseFwdIn = 0;
          analogWrite(pulseFwd,pulseFwdIn);
          pulseStartTime = millis();
          fwdTime = (millis() - fwdStart); // time forward pulse was on
          Serial.print("fwdTime =    ");
          Serial.println(fwdTime);
          cycleStep = 2;
          }
          revPlsStart = 0; //clear reverse pulse has started bit
          break;
     case 2:
        if(millis() > (pulseStartTime + dwellPreset)){
          pulseStartTime = millis();
          fwdPlsStart = 0; //clear forward pulse has started bit
          cycleStep = 3;
         }
          break;
     case 3:
        if(millis() > (pulseStartTime + 500)){
          cycleStep = 4;
         }
          break;
     case 4:
      pulseRevIn = map(TestBattIn, 0, 1025, 0, 255); // turn rev on
      analogWrite(pulseRev,(pulseRevIn - 25));

      if(revPlsStart == 0){
          revStart = millis(); // capture reverse pulse start time
          revPlsStart = 1; // set reverse pulse has started bit
      }
                 
        if(revLS_status == HIGH){
          pulseRevIn = 0;
          analogWrite(pulseRev,pulseRevIn);
          pulseStartTime = millis();
          revTime = (millis() - revStart); // time forward pulse was on
          cycleStep = 5;
          cycleCount ++;

          // log data
          logfile = SD.open(logFileName, FILE_WRITE);
          logfile.print(cycleCount);
          logfile.print(", ");
          logfile.print(fwdTime);
          logfile.print(", ");
          logfile.print(revTime);
          logfile.print(", ");
          logfile.print(BattVolts);
          logfile.println();

          // Close file
          logfile.close();
          
          }
          break;
     case 5:
        if(millis() > (pulseStartTime + dwellPreset)){
          
          cycleStep = 6;
          }
          break;
     case 6:
        if(millis() > (pulseStartTime + 500)){
          pulseStartTime = millis();
          cycleStep = 1;
          }
          break;
     
  } // end switch

} // end void Pump_Test

Thanks for your help and time
John

Hi

No they are not reserved keywords but have been declared in one of your library as "known words". Changing the name is fine, but won't get you in trouble if you keep the old ones.

This is not what I had in my original code:
  DateTime now; // read RTCto read the RTC you need to do

  DateTime now = rtc.now();

Also, I would not update the date/time within the call back - because you don't know in which exact context it's called from the SD library, my have some SPI communication, interrupts or whatever going on that could come in the way of reading your RTC - I would keep it as simple as in the other example and as explained, before you mess around with anyfile, call the function I had given you in #1 to update the global variables. this way when you touch your file, the global variables already hold the date/time and all should work fine.

Sorry I missed that you had modified the DateTime, I'll change it. I also misunderstood the update you had included. I asked if that was to update the RTC time, I didn't realize it also updated my global variables.

I'll make all those changes later tonight.

Thank You
John

That was it, works perfect! Made the changes, you had original sent me and clarified in the last post. I only had to make one modification, it may have to do with I am using a different RTC than you had first mentioned. I had to remove this if statement "if (rtc.lostPower())" I got a message that the class doesn't have lostPower. I just removed that part and left the rest of the line as is and it work great.

Thanks again for all your help
John

well done! have fun

J-M-L

Sorry to bother you but I do have a problem with the date stamp, I didn't notice it at first. I have been doing more testing of my system and realized that the date stamp is the same for all files. You do mention it on the comment on the example you first sent me, "we use the last compile time of this sketch" So the date/time I complied the program is the date for each file. I also noticed that one of the data points I log in the file is also the date and time, that also is the complied time.

The way my system works they can do a number of test with out removing the SD card. When a file is created it puts the next sequential number on the file name, logfile00, logfile01, logfile02, etc. So I wanted the date time the file was created to be on the file name, as well as be the correct time that goes in the file. The system will not be attached to a laptop once finished so once the RTC is set I just want it to read the time.

I put everything back as I had it, or commented out some of the lines we added and now it puts the right time in the file but not in the file name.

Thanks for your consideration
John

You need to initialize the RTC only once, then no need to use The macros F(DATE), F(TIME)

I’m not sure of what your question is (and post your code if you have question on the code)

OK that was it. I reset the code as you had original said but left that line commented, and it works just fine. I get the current date and time on the file name and as a data point within the log file. I had question you about that line asking if that's how you set the time, you said it was, but I guess I thought I had to leave it in as part of the logic to get the file date stamp.

Some times you have to bang me on the head a few times before it sinks in but I have learnt much on this project with your help.

Thanks again for your time and patience
John

:))