SdFatで扱うファイルにタイムスタンプを設定する方法 - renesas/Arduino GitHub Wiki

概要

  • 本ガイドではSdFatライブラリとRTCライブラリを連携して、SDカードに作成するファイルのタイムスタンプを設定する方法を解説する

動作環境

  • 本ガイド作成時の動作環境を以下に示す

    【動作環境1】

    • ArduinoIDE: v2.3.2
    • ボード: RL78/G23-64p Fast Prototyping Board
    • RL78/G23 Arduinoライブラリ: v2.3.0
    • SdFatライブラリ: v2.2.2

    【動作環境2】

    • ArduinoIDE: v2.3.2
    • ボード: RL78/G22 Fast Prototyping Board
    • RL78/G22 Arduinoライブラリ: v2.2.0
    • SdFatライブラリ: v2.2.2

    【動作環境3】

    • ArduinoIDE: v2.3.2
    • ボード: RL78/G23-128p Fast Prototyping Board
    • RL78/G23-128p Arduinoライブラリ: v1.0.0
    • SdFatライブラリ: v2.2.2

RTCライブラリを用いてタイムスタンプを設定する手順

  • 使用するライブラリのヘッダファイルをインクルードする
#include "SdFat.h"
#include "RTC.h"
  • RTCライブラリに日付、時刻、曜日を設定する
RTC.setDateTime(yy, mm, dd, hh, mi, ss, ww)
  • タイムスタンプを設定するためのコールバック関数を登録する
FsDateTime::setCallback(dateTime);
  • コールバック関数にRTCライブラリから日付、時刻、曜日を取得して、SdFatライブラリに設定するプログラムを実装する
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
  bool rtn;
  int yy, mm, dd, hh, mi, ss, ww;

  rtn = RTC.getDateTime(yy, mm, dd, hh, mi, ss, ww);
  if (true == rtn) {
    // Return date using FS_DATE macro to format fields.
    *date = FS_DATE(2000+yy, mm, dd);

    // Return time using FS_TIME macro to format fields.
    *time = FS_TIME(hh, mi, ss);

    // Return 0
    *ms10 = 0;
  }
}

タイムスタンプを設定するスケッチ例1

  • プログラム概要: 1つ目のファイルを作成してから64秒後に2つ目のファイルを作成する
// Test of time-stamp callback.
// Set the callback with this statement.
// FsDateTime::setCallback(dateTime);

#include "SdFat.h"
#include "RTC.h"

SdFat sd;
SdFile file;

void dateTime(uint16_t* date, uint16_t* time) {
  int yy, mm, dd, hh, mi, ss, ww;

  // Get the current date and time.
  if (RTC.getDateTime(yy, mm, dd, hh, mi, ss, ww))
  {
    // Return date using FS_DATE macro to format fields.
    *date = FS_DATE(2000+yy, mm, dd);
    
    // Return time using FS_TIME macro to format fields.
    *time = FS_TIME(hh, mi, ss);
  }
  else
  {
    Serial.println("Getting date and time failed.");
  }
}

//------------------------------------------------------------------------------
void setup() {

  Serial.begin(9600);
  FsDateTime::setCallback(dateTime);
  if (!sd.begin()) {
    Serial.println("begin failed");
    return;
  }

  // Wait for USB Serial
  while (!Serial) {
    yield();
  }

  // Set the date and time.
  if (!RTC.setDateTime(24, 3, 1, 17, 0, 0, RTC_WEEK_FRIDAY))
  {
    Serial.println("Set date and time failed.");
    RTC.end();
    while(1);
  }

  if (!file.open("test.txt", O_RDWR | O_CREAT | O_AT_END))
  {
    Serial.print("open_failed");
  }
  file.println("Hello");
  file.close();

  //Wait for 64 seconds
  Serial.println("Wait for 64 seconds");
  delay(64000);

  if (!file.open("test2.txt", O_RDWR | O_CREAT | O_AT_END))
  {
    Serial.print("open_failed");
  }
  file.println("Hello2");
  file.close();

  Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {}

タイムスタンプを設定するスケッチ例2

// Test of time-stamp callback.
// Set the callback with this statement.
// FsDateTime::setCallback(dateTime);
#include "SdFat.h"

#include "RTC.h"

//Slave Select pin : 10
const uint8_t SD_CS_PIN = SS;

// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_CLOCK SD_SCK_MHZ(50)

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)

#endif  // HAS_SDIO_CLASS

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

//------------------------------------------------------------------------------
// Call back for file timestamps.  Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
  bool rtn;
  int yy, mm, dd, hh, mi, ss, ww;

  rtn = RTC.getDateTime(yy, mm, dd, hh, mi, ss, ww);
  if (true == rtn) {
    // Return date using FS_DATE macro to format fields.
    *date = FS_DATE(2000+yy, mm, dd);

    // Return time using FS_TIME macro to format fields.
    *time = FS_TIME(hh, mi, ss);

    // Return 0
    *ms10 = 0;
  }
  else
  {
    Serial.println("Getting date and time failed.");
  }
}
//------------------------------------------------------------------------------
#define error(msg) (Serial.println(F("error " msg)), false)
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
void getLine(char* line, size_t size) {
  size_t i = 0;
  uint32_t t;
  line[0] = '\0';
  while (!Serial.available()) {
    yield();
  }
  while (true) {
    t = millis() + 10;
    while (!Serial.available()) {
      if (millis() > t) {
        return;
      }
    }
    int c = Serial.read();
    if (i >= (size - 1) || c == '\r' || c == '\n') {
      return;
    }
    line[i++] = c;
    line[i] = '\0';
  }
}
//------------------------------------------------------------------------------
void printField(Print* pr, char sep, uint8_t v) {
  if (sep) {
    pr->write(sep);
  }
  if (v < 10) {
    pr->write('0');
  }
  pr->print(v);
}
//------------------------------------------------------------------------------
int getDayweek(int y, int m, int d)
{
  int w;
  int rtn;

  // Zeller's congruence
  if (m < 3) {
    y--;
    m += 12;
  }
  w = (y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 + d) % 7;
  if (w == 0) {
    rtn = RTC_WEEK_SUNDAY;
  } else if (w == 1) {
    rtn = RTC_WEEK_MONDAY;
  } else if (w == 2) {
    rtn = RTC_WEEK_TUESDAY;
  } else if (w == 3) {
    rtn = RTC_WEEK_WEDNESDAY;
  } else if (w == 4) {
    rtn = RTC_WEEK_THURSDAY;
  } else if (w == 5) {
    rtn = RTC_WEEK_FRIDAY;
  } else {
    rtn = RTC_WEEK_SATURDAY;
  }
  return rtn;
}
//------------------------------------------------------------------------------
void printDayweek(Print* pr, int y, int m, int d)
{
  int w;

  w = getDayweek(y, m, d);
  if (w == RTC_WEEK_SUNDAY) {
    pr->print(F(" (Sunday)"));
  } else if (w == RTC_WEEK_MONDAY) {
    pr->print(F(" (Monday)"));
  } else if (w == RTC_WEEK_TUESDAY) {
    pr->print(F(" (Tuesday)"));
  } else if (w == RTC_WEEK_WEDNESDAY) {
    pr->print(F(" (Wednesday)"));
  } else if (w == RTC_WEEK_THURSDAY) {
    pr->print(F(" (Thursday)"));
  } else if (w == RTC_WEEK_FRIDAY) {
    pr->print(F(" (Friday)"));
  } else {
    pr->print(F(" (Saturday)"));
  }
}
//------------------------------------------------------------------------------
void printNow(Print* pr) {
  bool rtn;
  int yy, mm, dd, hh, mi, ss, ww;

  rtn = RTC.getDateTime(yy, mm, dd, hh, mi, ss, ww);
  if (true == rtn) {
    pr->print(2000+yy);
    printField(pr, '-', mm);
    printField(pr, '-', dd);
    printDayweek(pr, 2000+yy, mm, dd);
    printField(pr, ' ', hh);
    printField(pr, ':', mi);
    printField(pr, ':', ss);
  }
}
//------------------------------------------------------------------------------
bool setRtc() {
  bool rtn;
  int yy, mm, dd, hh, mi, ss;
  char line[30];
  char* ptr;

  clearSerialInput();
  Serial.println(F("Enter: YYYY-MM-DD hh:mm:ss"));
  getLine(line, sizeof(line));
  Serial.print(F("Input: "));
  Serial.println(line);

  yy = strtol(line, &ptr, 10);
  if (*ptr++ != '-' || yy < 2000 || yy > 2099) return error("year");
  mm = strtol(ptr, &ptr, 10);
  if (*ptr++ != '-' || mm < 1 || mm > 12) return error("month");
  dd = strtol(ptr, &ptr, 10);
  if (dd < 1 || dd > 31) return error("day");
  hh = strtol(ptr, &ptr, 10);
  if (*ptr++ != ':' || hh > 23) return error("hour");
  mi = strtol(ptr, &ptr, 10);
  if (*ptr++ != ':' || mi > 59) return error("minute");
  ss = strtol(ptr, &ptr, 10);
  if (ss > 59) return error("second");

  rtn = RTC.setDateTime(yy, mm, dd, hh, mi, ss, getDayweek(yy, mm, dd));
  Serial.print(F("RTC set to "));
  printNow(&Serial);
  Serial.println();
  return rtn;
}
//------------------------------------------------------------------------------
void setup() {
  int yy, mm, dd, hh, mi, ss, ww;
    
  Serial.begin(9600);
  while (!Serial) {
    yield();
  }

  //Start RTC.
  //Since the RTC has already been started, the return value is false.
  //RTC.begin();

  // following line sets the RTC to the date & time this sketch was compiled
  // RTC.setDateTime(compileYear(), compileMonth(), compileDay(), compileHour(), compileMinute(), compileSecond(), getDayweek(compileYear(),compileMonth(),compileDay()));
  // This line sets the RTC with an explicit date & time, for example to set
  // on Friday November 24, 2023 at 5pm you would call:
  // RTC.setDateTime(24, 3, 1, 17, 0, 0, RTC_WEEK_FRIDAY);
  yy = compileYear();
  mm = compileMonth();
  dd = compileDay();
  hh = compileHour();
  mi = compileMinute();
  ss = compileSecond();
  ww = getDayweek(yy, mm, dd);
    
  if (!RTC.setDateTime(yy, mm, dd, hh, mi, ss, ww)) {
    Serial.println(F("Set date and time failed."));
    RTC.end();
    return;
  }


  while (true) {
    Serial.print(F("DateTime::now "));
    printNow(&Serial);
    Serial.println();
    clearSerialInput();
    Serial.println(F("Type Y to set RTC, any other character to continue"));
    while (!Serial.available()) {
    }
    if (Serial.read() != 'Y') break;
    if (setRtc()) break;
  }
  Serial.println();

  // Set callback
  FsDateTime::setCallback(dateTime);

  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
  }
  // Remove old version to set create time.
  if (sd.exists("RtcTest.txt")) {
    sd.remove("RtcTest.txt");
  }
  if (!file.open("RtcTest.txt", FILE_WRITE)) {
    Serial.println(F("file.open failed"));
    return;
  }
  // Print current date time to file.
  file.print(F("Test file at: "));
  printNow(&file);
  file.println();

  file.close();
  // List files in SD root.
  sd.ls(LS_DATE | LS_SIZE);
  Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {}
⚠️ **GitHub.com Fallback** ⚠️