следующий код отобразит файлы на SD-карте в Arduino и позволит пользователю открыть файл по своему выбору. Вот код с описанием того, что он делает.
В состоянии Init я вызываю библиотеки, необходимые для выполнения кода
// Example use of lfnOpenNext and open by index.
#include<SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
// SD card chip select pin.
const uint8_t SD_CS_PIN = 10;
SdFat sd;
SdFile dirFile;
SdFile file;
// Number of files found.
uint16_t numberOfFiles = 0;
Это область реальной проблемы, вызов SdFile parIndex[50];
Занимает большое количество динамической памяти. Для количества файлов на SD-карте это довольно маленькое число, так что мне нужно что-то получше.
// Position of file's directory entry.
uint16_t dirIndex[50];
SdFile parIndex[50];
//------------------------------------------------------------------------------
На этапе Setup мы убеждаемся, что SD-карта подключена, и, если она подключена, вызываем функцию для передачи файлов на SD-карту.
void setup()
{
Serial.begin(38400);
while (!Serial) {}
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50)))
{
sd.initErrorHalt();
}
if (dirFile.open("/", O_READ))
{
printDirectory(dirFile, 0);
}
}
Функция printDirectory (Эта часть наиболее открыта для редактирования, если есть способ улучшить производительность здесь, пожалуйста, дайте мне знать).
void printDirectory (SdFile CFile, int numTabs)
{
SdFile file;
while (file.openNext(&CFile, O_READ))
{
if (file.isHidden()||false)
{
//file hidden, skip
}
else
{
for (uint8_t i = 0; i < numTabs; i++)
{
//create tabs for spacing
Serial.print('\t');
}
if (file.isSubDir())
{
SdFile SubDirFile;
printDirectory(SubDirFile, numTabs+1);
}
else
{
// Save dirIndex of file in directory.
dirIndex[numberOfFiles] = file.dirIndex();
parIndex[numberOfFiles] = CFile;
// Print the file number and name.
Serial.print(numberOfFiles);
Serial.write(' ');
file.printName(&Serial);
Serial.println();
numberOfFiles++;
}
}
file.close();
}
}
Это часть пользовательского интерфейса, она была сделана в основном в качестве доказательства концепции для вышеупомянутого кода. В том виде, в котором он написан, код принимает только значения индексов 0-9, но моя реальная программа может вызывать любое значение индекса.
void loop() {
int c;
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
Serial.print(F("\r\nEnter File Number: "));
while (!Serial.available()) {
SysCall::yield();
}
c = Serial.read();
uint8_t i = c - '0';
if (!isdigit(c) || i >= numberOfFiles) {
Serial.println(F("Invald number"));
return;
}
Убедившись, что входное значение существует, программа вызывает массивы, содержащие объект SdFile родительского каталога и индекс нужного файла.
Serial.println(i);
if (!file.open(&parIndex[i], dirIndex[i], O_READ)) {
sd.errorHalt(F("open"));
}
Serial.println();
char last = 0;
// Copy up to 500 characters to Serial.
for (int k = 0; k < 500 && (c = file.read()) > 0; k++) {
Serial.write(last = (char)c);
}
// Add new line if missing from last line.
if (last != '\n') {
Serial.println();
}
file.close();
Serial.flush();
delay(100);
}
Основная проблема заключается в том, что SdFile parIndex[50];
использует 22% моей динамической памяти, в то время как остальная часть программы использует 12%. Как я могу переписать свой код, чтобы не держать объекты SDFile в динамической памяти?
Для тех, кто не знаком, документацию по библиотеке SdFat можно скачать по этой ссылке.
Редактировать: С точки зрения использования: SD-файлы - это файлы .csv, в которых хранятся параметры скорости и времени для проведения теста двигателя. Каждый тест длится от нескольких минут до нескольких часов.
У вас есть несколько возможностей:
Обновление: Если вам нужно читать файлы, оставляя Arduino незаблокированным, вы должны включить это в цикл, но не читайте все файлы в цикле. Что-то в псевдокоде вроде:
bool readingSd = false; // Истина между чтением первого и последнего файла uint16_t lastTimeRead = 0; // Последний прочитанный файл
void loop()
{
// Check if file read needed (initial or one hour past, I don't take
// overflow into account
if (lastTimeRead == 0 || (lastTimeRead + 1000 * 60 < millis())
{
checkReadFile();
}
// Perform your normal code... this will run between processing/reading
// one file/dir.
...
}
void ProcessSingleFile()
{
readingSd = true; // Within reading first/last file
"read/process ONE file or dir (without containing files)";
if ("last file read")
{
readingSd = false;
lastTimeRead = millis(); // Move to top to prevent reading time
// between first/last to take into account
}
}