Изменение файловых атрибутов даты-времени при создании/корректировке файлов на SD-карте

Scare
Offline
Зарегистрирован: 30.08.2012

В процессе работы с записью данных на SD-карту (Arduino Mega 2560 + Ethernet Shield) понадобилось устанавливать файловые атрибуты, связанные с датой-временем, которые в обычном случае жестко устанавливаются в 01.01.2000 01:00.
Беглое ознакомление с библиотеками показало, что в libraries\SD\utility\SdFat.h наличествуют функции класса SdFile: timestamp и sync , позволяющие работать с файловыми атрибутами

Данные функции использовались в решении, описанном тут: http://forums.adafruit.com/viewtopic.php?f=31&t=20355

Не могли бы участники форума опубликовать пример установки атрибутов даты-времени для файлов, обрабатываемых скетчем, использующем стандартную библиотеку SD?

Предположительно, это могло бы выглядеть как-то так.

 

#include <SD.h>
#include <Time.h>

...

SD.begin()
...
File file = SD.open("filename.txt", FILE_WRITE );
...
file.print("12345");
...
boolean T_C = file.timestamp( T_CREATE, year(), month(), day(), hour(),  minute(), second() );
...

file.sync();
...
SD.close();

Данная схема, кстати, неверна, т.к. функции-методы timestamp , sync принадлежат классу, отличному от  SD.

Буду благодарен за работающий пример установки атрибутов даты-времени при создании, и/или корректировке файла.

Artur1985
Offline
Зарегистрирован: 19.02.2013

Добрый вечер.

Не специалист в данном вопросе, платы Ethernet Shield у меня нет.
Поэтому рабочий пример не дам, возможно кто-то еще 
откинется.

Возможно ответ тут, взял из кеша гугола.
http://webcache.googleusercontent.com/search?q=cache:IsnxaGOOBwIJ:forums.adafruit.com/viewtopic.php%3Ff%3D31%26t%3D20355+SdFat+set+the+date&cd=1&hl=ru&ct=clnk&gl=ru

Там Fat16, как я понял это маленькая библиотека, огрызок от SdFat.
 

// set creation date time
  if (!file.timestamp(T_CREATE,now.year(),now.month(),now.day(),now.hour(),
  now.minute(),now.second() )) {
    error("create time");
  }
  // set write/modification date time
  if (!file.timestamp(T_WRITE,now.year(),now.month(),now.day(),now.hour(),
  now.minute(),now.second() )) {
    error("write time");
  }
  // set access date
  if (!file.timestamp(T_ACCESS,now.year(),now.month(),now.day(),now.hour(),
  now.minute(),now.second() )) {
    error("access time");
  }

Тут посдсмотрел, как работает, без лишнего кода.
http://arduino.cc/forum/index.php?topic=116510.0

Возможно решение будет примерно таким, но....
Внимание, прежде чем запускать, нужно убедиться, что у вас именно 10 пин, осуществляет работу с SD.

Я плохо знаю сам Arduino, поэтому не подскажу какой именно у вас порт, в примере 10, но не факт, что у вас такой же.

Применое решение.

#include <SdFat.h>

// SdFat, sdfatlib20120719.zip http://code.google.com/p/sdfatlib/downloads/list

// Объявление объектов
SdFat sd;
SdFile file;

// оставил оригинальный комментарий
// не знаю какая должна быть ножка
// for the data logging shield, we use digital pin 10 for the SD cs line

// const int chipSelect = 10; // комментировал специально, вдруг не прочтете и кинете в ардуино :), сужу по себе :)

void setup() 
{

}

void loop(void) {
  if (!sd.begin(chipSelect)) sd.initErrorHalt();

  // open the file for write at end like the Native SD library
  if (!file.open("test.txt", O_WRITE | O_CREAT | O_AT_END)) {
    sd.errorHalt("opening test.txt for write failed");
  }

  // set creation date time
  if (!file.timestamp(T_CREATE,2013,2,19,22,00,00)) {
    error("create time");
  }

  file.close();
}

void error(char *str)
{
  // Что-то делаем при ошибке
}

Дополнение
Да надо скачать библиотеку
sdfatlib20120719.zip http://code.google.com/p/sdfatlib/downloads/list.

Только, что увидел, есть официальный пример.
sdfatlib20121219\SdFat\examples\Timestamp
 

/*
 * This sketch tests the dateTimeCallback() function
 * and the timestamp() function.
 */
#include <SdFat.h>

SdFat sd;

SdFile file;

// Default SD chip select is SS pin
const uint8_t chipSelect = SS;

// create Serial stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
//------------------------------------------------------------------------------
/*
 * date/time values for debug
 * normally supplied by a real-time clock or GPS
 */
// date 1-Oct-09
uint16_t year = 2009;
uint8_t month = 10;
uint8_t day = 1;

// time 20:30:40
uint8_t hour = 20;
uint8_t minute = 30;
uint8_t second = 40;
//------------------------------------------------------------------------------
/*
 * User provided date time callback function.
 * See SdFile::dateTimeCallback() for usage.
 */
void dateTime(uint16_t* date, uint16_t* time) {
  // User gets date and time from GPS or real-time
  // clock in real callback function

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(year, month, day);

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(hour, minute, second);
}
//------------------------------------------------------------------------------
/*
 * Function to print all timestamps.
 */
void printTimestamps(SdFile& f) {
  dir_t d;
  if (!f.dirEntry(&d)) error("f.dirEntry failed");

  cout << pstr("Creation: ");
  f.printFatDate(d.creationDate);
  cout << ' ';
  f.printFatTime(d.creationTime);
  cout << endl;

  cout << pstr("Modify: ");
  f.printFatDate(d.lastWriteDate);
  cout <<' ';
  f.printFatTime(d.lastWriteTime);
  cout << endl;

  cout << pstr("Access: ");
  f.printFatDate(d.lastAccessDate);
  cout << endl;
}
//------------------------------------------------------------------------------
void setup(void) {
  Serial.begin(9600);
  while (!Serial) {}  // wait for Leonardo

  cout << pstr("Type any character to start\n");
  while (!Serial.available());
  delay(400);  // catch Due reset problem
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

  // remove files if they exist
  sd.remove("CALLBACK.TXT");
  sd.remove("DEFAULT.TXT");
  sd.remove("STAMP.TXT");

  // create a new file with default timestamps
  if (!file.open("DEFAULT.TXT", O_CREAT | O_WRITE)) {
    error("open DEFAULT.TXT failed");
  }
  cout << pstr("\nOpen with default times\n");
  printTimestamps(file);

  // close file
  file.close();
  /*
   * Test the date time callback function.
   *
   * dateTimeCallback() sets the function
   * that is called when a file is created
   * or when a file's directory entry is
   * modified by sync().
   *
   * The callback can be disabled by the call
   * SdFile::dateTimeCallbackCancel()
   */
  // set date time callback function
  SdFile::dateTimeCallback(dateTime);

  // create a new file with callback timestamps
  if (!file.open("CALLBACK.TXT", O_CREAT | O_WRITE)) {
    error("open CALLBACK.TXT failed");
  }
  cout << ("\nOpen with callback times\n");
  printTimestamps(file);

  // change call back date
  day += 1;

  // must add two to see change since FAT second field is 5-bits
  second += 2;

  // modify file by writing a byte
  file.write('t');

  // force dir update
  file.sync();

  cout << pstr("\nTimes after write\n");
  printTimestamps(file);

  // close file
  file.close();
  /*
   * Test timestamp() function
   *
   * Cancel callback so sync will not
   * change access/modify timestamp
   */
  SdFile::dateTimeCallbackCancel();

  // create a new file with default timestamps
  if (!file.open("STAMP.TXT", O_CREAT | O_WRITE)) {
    error("open STAMP.TXT failed");
  }
  // set creation date time
  if (!file.timestamp(T_CREATE, 2009, 11, 10, 1, 2, 3)) {
    error("set create time failed");
  }
  // set write/modification date time
  if (!file.timestamp(T_WRITE, 2009, 11, 11, 4, 5, 6)) {
    error("set write time failed");
  }
  // set access date
  if (!file.timestamp(T_ACCESS, 2009, 11, 12, 7, 8, 9)) {
    error("set access time failed");
  }
  cout << pstr("\nTimes after timestamp() calls\n");
  printTimestamps(file);

  file.close();
  cout << pstr("\nDone\n");
}

void loop(void){}

 

Scare
Offline
Зарегистрирован: 30.08.2012

Artur1985, огромное Вам спасибо! Буду осваивать матчасть.

(пример с Fat16 видел, тупое скрещивание стоковой SD и Fat16 мне не помогло; зато теперь есть обильная пища для ума и рук)

 

Artur1985
Offline
Зарегистрирован: 19.02.2013

Не за что, если используйте какие-то внешние библиотеки, смотрите последние версии.
И примеры, они или на сайте разработчика или внутри папки с библиотекой.

Хочу распросить вас о связке Arduino Mega 2560 + Ethernet Shield, у моего знакомого проблема с Ethernet Shield.
Поэтому себе не покупал.

Какая у вас плата, оригинал или нет?
Вы пробовали работу сети?
И как вы подключали плату, просто вставили и все?

Может ему достался не удачный экземпляр.

Scare
Offline
Зарегистрирован: 30.08.2012

Сорри за задержку с ответом, не заметил Ваш вопрос.

У меня не оригинальная Мега, а отечественный клон Freeduino Mega 2560 http://mk90.ru/store/ru/microcontrollers/50-freeduino-mega-2560.html

Сетевой шилд http://mk90.ru/store/ru/shields/4-ethernet-shield.html оттуда же.

Использую несколько пар Мега+Шилд, в одном случае Мега версии 2.0.0, в остальных 3.0.0 (особеннности национального ардуиностроения: требуется установить оригинальный драйвер, плата поставляется вместе с драйверами семейства Freeduino). Схемотехника незначительно изменена в лучшую сторону по сравнению с оригиналом: применены кварцы и более стабильная частотозадающая цепь.

На Мега+Шилд реализован веб-клиент, он же веб-сервер.

У шилда есть особенность, связанная общим управлением кардридером и сетевой частью и тем, что у меги и у остальных Ардуин в этой части различная распиновка (53 и 10 пины соответственно).  Поэтому, опуская детали, следует явно устанавливать режим работы с сетевым интерфейсом и с кардридером

    digitalWrite(  4, HIGH); // SD disabled
    digitalWrite( 10, LOW ); // LAN enabled

или

    digitalWrite( 10, HIGH ); // LAN disabled 
    digitalWrite(  4, LOW  ); // SD enabled

Если этого не делать, дребезг на неустановленных пинах приводит к спорадическим зависаниям устройства.

ПС

Для работы с картой я использовал стандартную библиотеку SD и удивлялся ее ограниченной функциональности иобилием используемых в официальных примерах недокументированных возможностей. В противоположность ей, SdFat отлично документирована и полнофункциональна. Но протестировать ее работу вместе с сетевой частью я еще не успел, так что  о стабильности работы сетевого и карточного интерфейсов говорить с уверенностью не могу, хотя и предполагаю, что проблемы маловероятны.

 

 

Artur1985
Offline
Зарегистрирован: 19.02.2013

День добрый.

>> Сорри за задержку с ответом, не заметил Ваш вопрос.
Бывает.

Спасибо за подробное разъяснение.
Надо будет, присмотрится к Freeduino.
Цена приятная, сетевая почти в 2 раза дешевле, да и мега.

Конечно, это не ebay, но последняя доставка не дошла, да и ждать месяц.

У меня оригинальные меги у друга тоже и сетевой.
Теперь сетевой достался мне, он не такой упорный:), но увы пока не пашет.

Код который вы указали, пробовал.

Пациент скорее мертв, чем жив.
Пингуется, глазками моргает, но не пашет.

Буду воевать с ней.

>> Но протестировать ее работу вместе с сетевой частью я еще не успел
Одновременно они не работают, но можно переключать как у вас в коде.

Еще раз спасибо.
И удачи!

sadovod
Offline
Зарегистрирован: 09.10.2015

Всем привет!Столкунулся с такой же проблемой,но ничего не понял,что написали выше.Как то строанно,что такой важной функции как установка атрибутов даты и времени для файлов отсутствует в стандартной библиотеке для работы с SD.Ковыряя библиотеку SD обнаружил в файле SdFat.h константы установки даты и времени по умолчанию FAT_DEFAULT_DATE и FAT_DEFAULT_TIME,может быть можно как то прикрутить к этому файлу использование данных с библиотеки часов например из этой ds3231.Прошу помощи у знатоков которые смоглибы использовать в библиотеке данные, полученные из другой библиотеке.

T.Rook
Offline
Зарегистрирован: 05.03.2016

Исходные данные:

 Используем SD и RTC (ну и Wire для RTC)

План реализации:

 Пишем callback-функцию дату-время и подсовываем её SD.

Реализация:

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


RTC_DS3231 RTC;  // define the Real Time Clock object
//------------------------------------------------------------------------------
// call back for file timestamps
void cb_dateTime(uint16_t* date, uint16_t* time) {
  DateTime now = RTC.now();

  // 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());
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
  if (!RTC.begin()) {
    Serial.println("RTC failed");
    while(1);
  };
  // set date time callback function
  SdFile::dateTimeCallback(cb_dateTime);
 //теперь все операции с файлами должны брать время с RTC
}


//------------------------------------------------------------------------------
void loop() {}

Источник: первая ссылка Гугла "arduino sd file date time".

Вроде компилится. Моя Arduin-ка только едет ко мне, так что мне проверить не на чем. Может протестит кто?

sadovod
Offline
Зарегистрирован: 09.10.2015

Проверил ,работает,но у меня другая библиотека для работы с часами 3231,пришлось немного подправить представленный код за который вам огромное спасибо.Вот что у меня получилось при работе с библиотекой DS3231

#include <SD.h>
#include <Wire.h>
#include <DS3231.h>
Time  t;
DS3231  rtc(SDA, SCL);
File myFile;
//------------------------------------------------------------------------------
// call back for file timestamps
void cb_dateTime(uint16_t* date, uint16_t* time) {
 t = rtc.getTime();
  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(t.year, t.mon, t.date);
  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(t.hour, t.min, t.sec);
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Wire.begin();
  rtc.begin();
  t = rtc.getTime();
  pinMode(53, OUTPUT);// change this to 53 on a mega
  if (!SD.begin(53)) {
    Serial.println("initialization failed!");
  }  else {
    Serial.println("initialization done.");
}
  // set date time callback function
  SdFile::dateTimeCallback(cb_dateTime);
 //теперь все операции с файлами должны брать время с RTC
//создаем тестовый файл для проверки 
 myFile = SD.open ("Test1.txt", FILE_WRITE);
  Serial.println("file created !");
 myFile.close();
}


//------------------------------------------------------------------------------
void loop() {}

 

T.Rook
Offline
Зарегистрирован: 05.03.2016

sadovod пишет:

Проверил ,работает

Спасибо за тест! DS3231  тоже едет :)) Так заберу Ваш проверенный код к себе в копилку.

santalov2
Offline
Зарегистрирован: 27.02.2017

у меня заработало но может что не такили библиотек нету 

Test_file_33231_SD:8: error: 'Time' does not name a type
 
 Time  t;
Test_file_33231_SD:9: error: no matching function for call to 'DS3231::DS3231(const uint8_t&, const uint8_t&)'
 DS3231  rtc(SDA, SCL);
C:\Prog\adruino\_Perv\Proekt\Datchiki\Test_file_33231_SD\Test_file_33231_SD.ino:9:21: note: candidates are:
In file included from C:\Prog\adruino\_Perv\Proekt\Datchiki\Test_file_33231_SD\Test_file_33231_SD.ino:5:0:
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:64:3: note: DS3231::DS3231()
   DS3231();
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:64:3: note:   candidate expects 0 arguments, 2 provided
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:60:7: note: constexpr DS3231::DS3231(const DS3231&)
 class DS3231 {
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:60:7: note:   candidate expects 1 argument, 2 provided
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:60:7: note: constexpr DS3231::DS3231(DS3231&&)
C:\Prog\adruino\_Perv\Proekt\libraries\DS3231/DS3231.h:60:7: note:   candidate expects 1 argument, 2 provided
C:\Prog\adruino\_Perv\Proekt\Datchiki\Test_file_33231_SD\Test_file_33231_SD.ino: In function 'void cb_dateTime(uint16_t*, uint16_t*)':
Test_file_33231_SD:14: error: 't' was not declared in this scope
  t = rtc.getTime();
Test_file_33231_SD:14: error: 'class DS3231' has no member named 'getTime'
  t = rtc.getTime();
C:\Prog\adruino\_Perv\Proekt\Datchiki\Test_file_33231_SD\Test_file_33231_SD.ino: In function 'void setup()':
Test_file_33231_SD:24: error: 'class DS3231' has no member named 'begin'
   rtc.begin();
Test_file_33231_SD:25: error: 't' was not declared in this scope
   t = rtc.getTime();
Test_file_33231_SD:25: error: 'class DS3231' has no member named 'getTime'
   t = rtc.getTime();
exit status 1
'Time' does not name a type