以下のコードは、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ライブラリのドキュメント]1は、このリンクからダウンロードすることができます。
編集する 使い方としてはSDファイルは.csvファイルで、モーターテストを実行するための速度と時間のパラメータを保存しています。各テストは数分から数時間続きます。
いくつかの可能性がありますね。
更新してください。 Arduinoをブロックしない状態でファイルを読み込む必要がある場合、ループに組み込む必要がありますが、ループ内ですべてのファイルを読み込まないようにします。のような擬似コードで何か。
bool readingSd = false; // 最初と最後のファイルを読む間にtrueを返す。 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
}
}