Официальный сайт компании Arduino по адресу arduino.cc
SDFat для GPS логгера
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Пытаюсь реализовать GPS логгер с функцией спидометра. Лог пишется на карту SD в формате GPX. Для работы с картой используется библиотека SDfat, т.к. требуются длинные имена файлов (имя файла - дата и время начала записи трека).
В процессе записи лога требуется в конце каждого цикла записи добавлять завершающие XML-теги (27 символов), чтобы потом файл можно было открыть без ошибки. Каждый последующий цикл записи должен начинаться со смещением на те же 27 символов, но смещения не происходит. Текст, который должен затиратья, дописывается в каждом цикле.
Код записи в GPX брал в этой теме:
http://arduino.ru/forum/proekty/gps-logger-s-rgb-svetodiodom
там используется библиотека SD.h:
dataFile = SD.open(filepath, FILE_WRITE); unsigned long filesize = dataFile.size(); // back up the file pointer to just before the closing tags filesize -= 27; dataFile.seek(filesize); dataFile.print(F("<trkpt lat=\""));
в моём варианте для SDfat.h код выглядит:
// открытие файла для записи file.open(filename, O_APPEND | O_WRITE); // вычисление размера фала uint32_t filesize = file.fileSize(); // вычисление точки начала записи filesize -= 27; file.seekSet(filesize); // вывод данных в файл file.print(F("<trkpt lat=\""));
собственно вопрос - что я делаю не так?
что я делаю не так?
Ну, для начала, Вы не проверяете, что Вам вернула seekSet. Как и не проверяете успешно ли открылся файл.
Поставьте печать результата её выполнения, Вы хоть будете видеть, считает ли она сама, что всё в порядке, или же она честно говорит Вам, что установить не удалось только Вы это игнорируете.
Итак, печатайте результат seekSet, а потом уж думайте.
Если она вернёт 0, то надо понять почему. Причин может быть три
Если уж совсем будет непонятно, то нужно лезть в библиотеку и вставлять возврат разных кодов на каждую причину.
Возможно из за того что вы не учитываете размер блока для SDfat и пытаетесь выполнить seek не кратный размеру блока.
Почему то пример на гитхабе выполняет seek на кратные 512-байт, может только для low latency, а может и нет ;-)
Ну, вот, Алексей :(
Я тут скромненько пишу: "Файл имеет кластерную организацию и с цепочкой кластеров что-то не так" чтобы ТС сам решил проблему, а Вы прямо на тарелочке :(
Я уж стек исходников раскрутил, да постеснялся запостить, только ссылку дал на какой то не проверенный код, пардоньте, уж торлить не хотелось.
П.С.
ардуина-иде не плоха для быстрого старта, но редактор это как ёжик в тумане, пользоваться слегка совсем неудобно.
эклипсом пользуюсь оч.давно, собираю им же, в метод тык - и прототипы и реализация перед тобой, полный релакс.
Спасибо за ответы.
Файл открывается успешно. В Setup я формирую имя файла по дате и времени из GPS, открываю файл и записываю в него заголовок XML, в конец добавляю закрывающие теги, которые должны затираться в каждом цикле записи.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
В loop файл снова открывается и в него идёт запись данных и файл закрывается. При отключении питания не будет потери данных.
Посижу, поковыряю с возвращаемым значением seekSet.
С кластерной организацией файла дела не имел, пока не понимаю о чём речь.
С кластерной организацией файла дела не имел, пока не понимаю о чём речь.
А Вы откройте файл библиотеки и посмотрите как написана seekSet - поймёте.
Если. Поймете.
Если. Поймете.
да уж, с наскока не разобрался откуда берутся всякие там m_curCluster и т.д....
seekSet возвращает false
размер файла высчитывается корректно.
попробовал функцию seekEnd. как я понял из её описания, результатом выполнения является установка позиции в конец файла + смещение offset.
0
Set the files position to end-of-file + offset. See seekSet(). Can't be used for directory files since file size is not defined.
результат не изменился. смещение на заданное кол-во символов не происходит.
может быть попробовать формировать блоки, кратные 512 и записывать их? т.е. размер файла будет всегда кратен 512 и тогда seekSet заработает.
Алексей, Евгений
по моему, мужики, вы не правы, кластеры тут не при чем. С кластерами или без них Seek() должен отрабатывать верно.
Просто seek меняет только позицию чтения, а позиция записи от seek() не зависит. Позиция записи зависит от режима. В APPEND и WRITE принт всегда пишет в конец файла, в TRUNCATE - в начало. Чтобы писать в произвольное место файла. надо открывать файл не в аппенде, а в режиме Read-Write
по моему, мужики, вы не правы, ... позиция записи от seek() не зависит.
Может быть. Сейчас посмотрю в библиотеку и отпишусь.
Вы правы. Вот кусок из функции write
Т.е. если режим append и указатель не на конце файла, то она сама выполняет seekEnd
Если. Поймете.
да поймет, чего там сверхзаумного
выражусь немного более точно - в файле, открытым в режиме APPEND - текущая позиция записи автоматически отрабатывает в конец файла. вне зависмости от параметра seek()
Таки да, Вы правы, я там выше даже кусок кода библиотеки привёл.
хз, хз... я с ардуиной всего неделю-полторы ковыряюсь. с С++ дружили лет 15-20 назад, по этому начинаю разбираться почти с нуля.
в примере LowLatencyLogger из библиотеки SDfat есть функция recoverTmpFile и использование в ней seekSet, но ни чего волшебного, что мне бы помогло, я не вижу, разве, что только режим открытия файла O_RDWR
разве, что только режим открытия файла O_RDWR
это не "только", это ого-го-го сколько :)
Заработала! Спасибо огромное за помощь!
оставил код в таком виде:
p.s.: теперь можно переходить к следующему этапу - корректная настройка вывода данных на OLED дисплей, но об этом в другой теме, если опять сам не осилю. пока тестовый режим работает, но хочется большего, а вот с ним проблема...
p.p.s.: на всякий случай оставлю в этой теме ссылку на памятку
Алексей, Евгений
по моему, мужики, вы не правы, кластеры тут не при чем. С кластерами или без них Seek() должен отрабатывать верно.
Просто seek меняет только позицию чтения, а позиция записи от seek() не зависит. Позиция записи зависит от режима. В APPEND и WRITE принт всегда пишет в конец файла, в TRUNCATE - в начало. Чтобы писать в произвольное место файла. надо открывать файл не в аппенде, а в режиме Read-Write
Начал с libraries/SD/src/utility/SdFat.h совсем не обратил внимание на сигнатуру функции open, сразу стал раскручивать seekSet, дошел до чтения блока и не встретил проверки на разрешение чтения (мож. пропустил чего), решил что скластерами не сходится.
Второй раз ошибся - дал ссылку а сам не проверил, там как раз всё очевидно, используется иная библиотека SdFat, там то и сигнатура для open та что у ТС, и там же в чтении блока, русским по белому
// error if not open for read
if (!isOpen() || !(m_flags & F_READ)) {
Всем доброго времени суток.
Возникла ещё одна проблема при работе с SD картой. При пропадании питания на карте памяти периодически слетает FAT. В файловой системе появляется куча мучора в виде битых файлов и папок. Файлы с логами создаются корректно, но информация в них записывается не всегда. Надо как-то корректно закрывать файл и отключать карту при пропадании питания, возможно с дополнительным аккумулятором.
Как с минимальными затратами по памяти решить эту проблему?
p.s.: Мой скетч сейчас кушает 85%, в него планирую впихнуть обработчик двух кнопок и вывод информации на вторую страницу OLED дисплея. В перспективе нужно будет добавить обработку второго потока NMEA-0183. Есть подозрение, что Nano на всё это не хватит.
собственно, в продолжение предыдущего поста возник вопрос, будет ли работать такая схема?
C1 - ионистор
VD1 - диод шотке (пока не разобрался с номиналом)
S1 - двухполярный выключатель
V1 - внешний источник питания
Во время работы устройства на пине A0 контролируется наличие напряжения, при его пропадании файл на карте SD закрывается и устройство останавливается или на какое-то время переводится в режим ожидания до появления питания на A0.
по моему схема работать не будет. Или я не понял, что вы хотите сделать.
Диод наоборот. И токоограничитель заряда ионистора - такой же диод с резистором параллельно.
мне надо сделать так, чтобы при пропадании входного напряжения на какой-то короткий срок микроконтроллер оставался в рабочем состоянии и корректно закрыл файл на SD карте.
если файл корректно не закрывать, то возможна потеря записанных данных. так же периодически на карте памяти слетает таблица FAT.
я думал сделать так, чтобы при наличии входного напряжения контроллер запитывается как обычно, а при пропадании от ионистора. чтобы не было напряжения на пине А0 установлен диод.
на аналоговом пине А0 контролируется уровень напряжения, в моём случае контролируется его наличие.
Диод наоборот. И токоограничитель заряда ионистора.
по диоду согласен, исправил
подскажите пожалуйста, какой токоограничитель можно использовать. может быть для простоты обычный кондёр поставить? что-то я совсем не силён в электронике :)
Я написал выше.
Развернете диод суперкап заряжать некому будет.
Измеряете напряжение на нагрузке, при просадке принимаете решение о сохранении данных.
тогда, наверное, для контроля напряжения надо будет поставить ещё один диод в прямую линию от источника питания и измерять показание перед ним, чтобы не мерять напряжение от ионистора.
собственно, если я ни чего не напутал, получается так:
какого сопротивления будет достаточно для R1?
t=R*C
t - постоянная времени в секундах
R - сопротивление в омах
C - емкость в фарадах
1*220=220 секунд для того чтоб напряжение на суперкапе подросло на 63,2% от подоваемого напряжения (падение на диоде не учтено).
почитал статью про RC-цепь, но не понял, каким образом будет происходить защита от перезаряда. максимум, будет увеличено время заряда.
время работы устройства может быть как несколько секунд так и несколько часов. может быть стоит использовать какой-то контроллер заряда, который отключит ионистор от источника питания при достижении заданного напряжения (типа ЗУ)?
У вас источник 5В
плюсминус падение на диоде, суперкап на 5,5В о каком перезаряде идет речь?эээ... согласен. туплю. осталось проверить реальное напряжение, выдаваемое автомобильным ЗУ для телефона.
Спасибо за помощь!