SD card always displays a common Date Modified

The SD card I’m using whilst learning how to work with Arduino always displays the same Date Modified (1/1/2000), irrespective of when I complete a piece of work.

I would appreciate help to try to resolve this.

4 Likes

You need to implement a callback function so that the file system can obtain the current date and time as required.

See: file creation date and time in sd card ? - Using Arduino / Project Guidance - Arduino Forum

5 Likes

Thank you, Jeff.

I ran the sketch in post #5 of the above link and the Date Modified reflected today’s date and the time I ran the sketch.

I wasn’t sure whether that action re-set the microSD card, so I subsequently ran another sketch (known to be reliable) and today’s data was captured on the SD card, but the Date Modified was shown as 1/1/2000. I assume therefore that to capture the correct Date Modified, I need to include the code in the sketch from post #5 of the above link. Is that correct?

2 Likes

You need to include the function :
void dateTime(uint16_t* date, uint16_t* time) {

}

and you need to indicate that it is the callback for the SD Card File System:
SdFile::dateTimeCallback(dateTime);

3 Likes

Hi Jeff,

Good find! Judging by the length of that forum thread I’d say there are a few gotchas involved with the SD card timestamping.
Thanks for sharing your knowhow :slight_smile:

2 Likes

Jeff,

Thank you for clarifying the portions of code I needed. I have tried inserting them in the sketch you assisted me with a couple of days ago, but I’ve got some errors which, despite much research and experimentation, I can’t resolve.

From the Serial Monitor:

In function ‘void loop()’:

64:11: error: ‘class RTC_DS1307’ has no member named ‘read’
if (RTC.read™) // Get Time/Date from RTC1307
^~~~

exit status 1

Compilation error: ‘class RTC_DS1307’ has no member named ‘read’

Code

#include <SPI.h>
#include <SD.h>  // SD card library
#include <Wire.h>  // I2C
#include <TimeLib.h>
#include <RTClib.h>

File file;  // test file
const uint8_t SD_CS = 10; // SD chip select
RTC_DS1307 RTC;  // define the Real Time Clock object

 char timestamp[30];

//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
 DateTime now = RTC.now();
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(),now.minute(),now.second(),now.month(),now.day(),now.year()-2000);
 Serial.println("yy");
 Serial.println(timestamp);
 // return date using FAT_DATE macro to format fields
 *date = FAT_DATE(now.year(), now.month(), now.day());

 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

// constants won't change. They're used here to set pin numbers:
const int SWITCH_PIN = 2;       // the number of the microswitch pin
char timedatebuf[65];  // Time and Date string buffer
int year4digit;  // 4 digit year
char shutterStatus[24];

void setup()
{
  Serial.begin(9600);  // Serial monitor used for testing
  // Micro switch code
  pinMode (SWITCH_PIN, INPUT_PULLUP);
  Serial.println("Micro switch project");
  pinMode(10, OUTPUT);
  
  if (!SD.begin(10)) {  // check if card is installed
    Serial.println("No SD Card present in module");
    return;
  }
 // set date time callback function
 SdFile::dateTimeCallback(dateTime);

  Serial.println("SD Card Ready");
}

void loop()
{
  tmElements_t tm;
  // Micro switch code
  int microSwitch = digitalRead(SWITCH_PIN);
  if (microSwitch == LOW)
  {
    strcpy(shutterStatus, "Shutters Open");
  }
  else
  {
    strcpy(shutterStatus, "Shutters Closed");
  }
  if (RTC.read(tm))   // Get Time/Date from RTC1307
  {
    year4digit = tm.Year + 1970;  // 4 digit year variable

    // Format Time & Date string in timedatebuf
    sprintf(timedatebuf, "%s Time: %02d:%02d:%02d   Date:  %02d/%02d/%02d", shutterStatus, tm.Hour, tm.Minute, tm.Second, tm.Day, tm.Month, year4digit);

    File dataFile = SD.open("SHUTTERS.txt", FILE_WRITE);  // Open or Create file
    if (dataFile)   // Check if file exist on SD Card
    {
      dataFile.println(timedatebuf);
      dataFile.close();  // Close file
      Serial.println(timedatebuf);
    }
    else
    {
      Serial.println("error opening shutters.txt"); // if file not on SD Card
    }
  }
  delay(1000);
}

I can always use the sketch in its previous format, but I want to learn how to get the file on the SD card to show the correct Date Modified.

Thank you, in anticipation.

P.S. I just attempted to upload this post and got the ‘apply backticks to code’ message. I’ve tried to do that, but apparently unsuccessfully. Hopefully the code is legible nonetheless.

1 Like

It seems that two different libraries have got mixed up.

The tm variable and the read() method are applicable to a different library than the one for the example I suggested.

You can set the library back to the one used in the original sketch, and modify the callback to use the tm variable and the read() method, or leave the library as it is and change the code in the loop to use the now variable and the now() method.

Other than the declaration of the timedate variable and the method of populating it, the usage of the two libraries appears to be identical, with .hour, .minute etc properties.

RTClib: RTC_DS1307 Class Reference (adafruit.github.io)

2 Likes

Jeff,

I am most grateful to you for your assistance with this issue, but having spent much of the weekend trying to implement the amendments you’ve suggested - with each option (outlined in the previous post) - all I’ve managed to do is create numerous variations of this basic code, with many error messages.

I feel very self-conscious about asking for further guidance - effectively, ‘spoon feeding’ - but I am clearly floundering, due to a lack of comprehension of Arduino language and protocols.

I have some time pressure to complete the two components of the project I mentioned when I joined this Forum (of which, this is one) and given that they are both variations of existing sketches, I hoped to learn something about Arduino programming whilst adapting the sketches to suit my needs. Then, with less time pressure, to educate myself about Arduino properly, and in an orderly fashion.

My immediate need is to resolve this current coding issue, so that the sketch compiles AND creates an accurate File Modified date on my SD card.

To Jeff - and any other Forum member interested in this topic - please let me know if anything is unclear in respect of my current unresolved sketch.

Thank you, in anticipation.

1 Like

You haven’t shown the change you made. I offered two options - which one did you choose? I would recommend the second, but you might have reasons for preferring the first.

There is no reason to be embarrassed about asking for assistance at any level, but you must provide the essential details or we can end up going around in circles. Also, always mention the MCU you are using, because these libraries don’t always work the same on different processors.

This code compiles for me:

#include <SPI.h>
#include <SD.h>  // SD card library
#include <Wire.h>  // I2C
#include <TimeLib.h>
#include <RTClib.h>

File file;  // test file
const uint8_t SD_CS = 10; // SD chip select
RTC_DS1307 RTC;  // define the Real Time Clock object

 char timestamp[30];

//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
 DateTime now = RTC.now();
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(),now.minute(),now.second(),now.month(),now.day(),now.year()-2000);
 Serial.println("yy");
 Serial.println(timestamp);
 // return date using FAT_DATE macro to format fields
 *date = FAT_DATE(now.year(), now.month(), now.day());

 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

// constants won't change. They're used here to set pin numbers:
const int SWITCH_PIN = 2;       // the number of the microswitch pin
char timedatebuf[65];  // Time and Date string buffer
int year4digit;  // 4 digit year
char shutterStatus[24];

void setup()
{
  Serial.begin(9600);  // Serial monitor used for testing
  // Micro switch code
  pinMode (SWITCH_PIN, INPUT_PULLUP);
  Serial.println("Micro switch project");
  pinMode(10, OUTPUT);
  
  if (!SD.begin(10)) {  // check if card is installed
    Serial.println("No SD Card present in module");
    return;
  }
 // set date time callback function
 SdFile::dateTimeCallback(dateTime);

  Serial.println("SD Card Ready");
}

void loop()
{
  // Micro switch code
  int microSwitch = digitalRead(SWITCH_PIN);
  if (microSwitch == LOW)
  {
    strcpy(shutterStatus, "Shutters Open");
  }
  else
  {
    strcpy(shutterStatus, "Shutters Closed");
  }
  DateTime now = RTC.now();   // Get Time/Date from RTC1307
  {
    year4digit = now.year() + 1970;  // 4 digit year variable

    // Format Time & Date string in timedatebuf
    sprintf(timedatebuf, "%s Time: %02d:%02d:%02d   Date:  %02d/%02d/%02d", shutterStatus, now.hour(), now.minute(), now.second(), now.day(), now.month(), year4digit);
    
    File dataFile = SD.open("SHUTTERS.txt", FILE_WRITE);  // Open or Create file
    if (dataFile)   // Check if file exist on SD Card
    {
      dataFile.println(timedatebuf);
      dataFile.close();  // Close file
      Serial.println(timedatebuf);
    }
    else
    {
      Serial.println("error opening shutters.txt"); // if file not on SD Card
    }
  }
  delay(1000);
}

I haven’t run it yet because I don’t have a RTC set up at the moment and I would prefer to confirm that compile errors were your problem before testing the code. The part that might have created problems is that you have to declare now as a type DateTime in the main loop - the declaration in the callback function is unique to that function and has no meaning when now is used in the main loop - they are two separate variables referring to separate instances of the object (and perhaps they should be named differently to reduce confusion). The other transcribing errors should have generated messages that provided the required change.

If the problem was in the execution, not the compilation, then post the code you are using, what you expected to happen, and what actually happened.

2 Likes

Jeff,

Thank you for your consideration and your offer of further assistance.

I am using an Arduino Uno. The label on the microprocessor says it is an ATMEGA328P U

As mentioned, I tried many variations of the code discussed previously in this thread, none of which compiled. As I recall, this (see code below) is the version I tried most recently. It incorporated
the original library and my attempt to “change the code in the loop to use the now variable and the now() method”.

#include "SD.h"  // SD card library
#include "Wire.h"  // I2C
#include "Time.h"  // Time Manipulation
#include "DS1307RTC.h"  // DS1307 RTC

File file;  // test file
const uint8_t SD_CS = 10; // SD chip select
RTC_DS1307 RTC;  // define the Real Time Clock object

 char timestamp[30];

//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
 DateTime now = RTC.now();
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(),now.minute(),now.second(),now.month(),now.day(),now.year()-2000);
 Serial.println("yy");
 Serial.println(timestamp);
 // return date using FAT_DATE macro to format fields
 *date = FAT_DATE(now.year(), now.month(), now.day());

 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

// constants won't change. They're used here to set pin numbers:
const int SWITCH_PIN = 2;       // the number of the microswitch pin
char timedatebuf[65];  // Time and Date string buffer
int year4digit;  // 4 digit year
char shutterStatus[24];

void setup()
{
  Serial.begin(9600);  // Serial monitor used for testing
  // Micro switch code
  pinMode (SWITCH_PIN, INPUT_PULLUP);
  Serial.println("Micro switch project");
  pinMode(10, OUTPUT);
  
  if (!SD.begin(10)) {  // check if card is installed
    Serial.println("No SD Card present in module");
    return;
  }
 // set date time callback function
 SdFile::dateTimeCallback(dateTime);

  Serial.println("SD Card Ready");
}

void loop()
{
  tmElements_t tm;
  // Micro switch code
  int microSwitch = digitalRead(SWITCH_PIN);
  if (microSwitch == LOW)
  {
    strcpy(shutterStatus, "Shutters Open");
  }
  else
  {
    strcpy(shutterStatus, "Shutters Closed");
  }
  if (RTC.read(tm))   // Get Time/Date from RTC1307
  {
    year4digit = tm.Year + 1970;  // 4 digit year variable

    // Format Time & Date string in timedatebuf
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.Hour(),now.Minute(),now.Second(),now.Month(),now.Day(),now.Year()-2000);

    File dataFile = SD.open("SHUTTERS.txt", FILE_WRITE);  // Open or Create file
    if (dataFile)   // Check if file exist on SD Card
    {
      dataFile.println(timestamp);
      dataFile.close();  // Close file
      Serial.println("yy");
      Serial.println(timestamp);
    }
    else
    {
      Serial.println("error opening shutters.txt"); // if file not on SD Card
    }
  }
  delay(1000);
}

I have just run the code in your post immediately above and I attach a screen shot of the Serial Monitor report of that upload using my equipment (Arduino UNO, DS1307 module and microSD card module).
Jeff105671 code 17-01-2023 - Serial Monitor.pdf (175.5 KB)

Please let me know if you require more information.

1 Like

You changed to using the now variable but you never initialized it - roughly what I suspected.

The console output suggests that the Arduino is restarting in the middle of the message print process. There are two things I can think of that cause this. One is that some procedure is causing memory to be accessed incorrectly. This seems unlikely during a println() with a string literal, but you can check whether it might happen by looking at the compile report. Mine says:

Sketch uses 15498 bytes (48%) of program storage space. Maximum is 32256 bytes.
Global variables use 1374 bytes (67%) of dynamic memory, leaving 674 bytes for local variables. Maximum is 2048 bytes.

That indicates there is ample memory.

The other possibility is power - if the voltage drops the Arduino will restart. If you are using USB power make sure the PC can deliver it, or connect a 9V supply to the power port.

I can’t think of any reason why, but you could try changing the Serial baud rate. Also, try some of the examples that print to console and see if there is a similar problem.

2 Likes

Thank you, again, Jeff.

Just to be clear, I assume your comments relate to when I ran your code (of earlier today) .

Yes, I got a similar report to you: sketch uses 48% of program space, etc.

I tried changing the baud rate - both above (mainly) and below 9600 - and the best result I got (which I attached previously) was at 9600.

I have also tried a much shorter USB cable (the one supplied with my Arduino UNO board). It made no difference.

Re your suggestion to try a 9v power supply: I have a 9v DC supply, but I’ve never used it before. Can I leave the USB cable attached while supplying the board with 9v? If not, is there a sequence to upload the sketch, disconnect the USB cable/connect to 9v and then disconnect 9v/reconnect USB.

I realise I will have to become conversant with such a process when I apply the sketch to my ‘real’ project, where I will have the UNO board and attachments remote from my PC and powered by 9v DC.

1 Like

Yes - the board is designed handle this configuration. It will use the 9V supply via the on-board regulator for 5V. There might be a protocol for how you connect and disconnect the 9V supply and the USB, but I have never followed any particular procedure and have never had a problem. The only difference is that with USB connected the PC can (and does) reset the Uno, for instance when you open a console window. Of course that won’t happen when USB is not connected, and there might be cases where you need to press the reset button.

1 Like

Thanks, Jeff, I’ll try that.

Before I do, I overlooked passing one bit of information on to you: when I uploaded the sketch we’re discussing, while it was compiling, I received the following message in the lower portion of the Arduino screen.

INSTRUCTIONS (link): unable to watch for file changes in this large workspace. Please follow the instructions link to resolve this issue.

I’m not sure how relevant this issue is. I didn’t understand the volumes of information on the page displayed when I clicked on the INSTRUCTIONS (link) button, so I just proceeded to upload.

1 Like

Jeff,

Two things:
I’ve tried adding the 9v supply and there’s no change; and
I tried the same basic sketch - but WITHOUT the SD card ‘correct Date Modified’ alteration which is embedded in the sketch we’ve been discussing today - and that previously created sketch worked perfectly: date, time and shutters open or closed displaying as expected on the Serial Monitor (and captured on the SD card - albeit with the 1/1/2000 Date Modified!!).

I could live with the incorrect Date Modified on my SD card files, but as I also want to fine tune the other sketch I’m working on (with 4 temperature sensors) - including getting its code to reflect the correct Date Modified - I would like to resolve whatever the issue is, if possible.

1 Like

Hi Chris

Excuse me for butting here but why don’t you get the basics working first. That is start from the ground up.

You are talking about working on another sketch which, if it has some basic thing wrong the same as the one in question, is going to do something similar. Then it is talking to 4 sensors.

I feel that if you are going down this path you will go in ever decreasing circles for some time yet. Until you do go back to basics and fix the first problem.

It is interesting that you have other (2) quite recent posts which are probably about the same problem. In one of these you enquire about Arduino IDE language tutorials due to your stated lack of knowledge on the subject. Why not go back and start from there.

But keep going, you will get there.
Cheers Bob

1 Like

The program is failing at the
DateTime now = RTC.now();
line. It appears that the libraries are incompatible - probably a conflict between RTClib and SD. I can’t explain the odd failure mode, but it definitely responds to deleting that line.

So it seems the first option I offered is the better one after all. Starting with the version that works, add the callback function and the line to set it as the callback for the SD update. Then change the lines in the callback that get and print the time and date so they match what’s working in the main loop. That gives you the hour, minute etc variables. Plug them into the lines that create the return values. So they will look something like (from memory - check it):

  // return date using FAT_DATE macro to format fields
*date = FAT_DATE(tm.Year, tm.Month, tm.Day);
 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(tm.Hour, tm.Minute, tm.Second());
2 Likes

Thank you for your advice, Bob. I agree that going back to first principles is the logical way to learn. However, I’ve given a commitment to complete these two small related projects in a fairly tight time frame, so my ‘proper learning’ will need to occur out of sequence.

I apologise for taking up people’s valuable time with my queries, but although there may not be much evidence of it, I am learning as we work through this, as I’m doing a lot of Googling and other research behind the scenes.

I would prefer to sort this sketch out first so that hopefully, what’s learnt in terms of being able to identify both projects’ files captured on SD cards can be readily identified by Date Modified, rather than having the common, erroneous date, 1/1/2000.

2 Likes

Thank you, Jeff.

In fact I’ve just been delving into one of my errors: RTC_DS1307 does not name a type. Google has led me to an Arduino Forum where someone explained the conflict caused by two RTC libraries with similar nomenclature, that can apparently confuse Arduino (precis in my words). I suspect you’re highlighting a similar issue.

I’ll work on your suggested solution.

2 Likes

Not quite. Using two different libraries for the same device in one sketch will create a problem. For instance, one library might change a setting in the device, the other library doesn’t know about the change and makes an assumption about how it should work, and failure is pretty much guaranteed.

Libraries for two different devices should be quite independent. However a common area of conflict is where two libraries compete for the same built-in resource, such as an Arduino timer. Obviously, using the same ports creates a conflict, but that is usually manageable. If a library has a compatibility requirement it is usually noted in the documentation. In this case I can see one report of a similar problem, but it was at the compile level (like the naming issue you found) where the cause of the conflict is usually obvious. A reboot in the middle of a console print is a lot harder to diagnose.

2 Likes