Файл не найден на SD-карте
У меня есть довольно длинный код для копирования файла с SD на ту же карту, но под другим именем. У меня есть одна версия, в которой имена файлов встроены в скетч, но чтобы сделать его более переносимым, я реализовал последовательную систему выбора файлов. Есть 3 фазы: выбор входного файла, выбор выходного файла и копирование. Я включил проверки, чтобы увидеть, существуют ли файлы, подтверждение имен и так далее. Однако в середине моего кода, как раз перед фазой копирования, входной файл исчезает, и arduino не находит его. Он находит его на первой фазе, находит выходной файл, но не может найти входной файл на фазе копирования. SD.exists() и SD.open() оба подтверждают это, но если я извлеку SD-карту и вставлю ее в компьютер, файл будет там.
Мой код:
#include <SoftReset.h>
#include <SPI.h>
#include <SdFat.h>
#define csPin 4
#define roundTo 64
SdFat SD;
File sourceFile;
File outputFile;
int bufSize;
uint32_t lastPos = 0, timeLast, timeNow;
#define BAUD 115200
//сделать timeBetweenChars временем (в миллисекундах), которое проходит между передачей каждого символа по последовательному порту, и сделать его не менее одного
unsigned long timeBetweenChars = max(1000 / (BAUD / 8), 1);
void setup() {
// Открываем последовательную связь и ждем открытия порта:
Serial.begin(BAUD);
while (!Serial) {
}
Serial.print(F("Initializing SD card..."));
/******************************************************************************/
// проверяем, присутствует ли карта и может ли она быть инициализирована:
if (!SD.begin(csPin, SPI_FULL_SPEED)) {
Serial.println(F("Card failed, or not present"));
soft_restart();
}
Serial.println("Card initialized.");
Serial.println(F("Files on card:"));
SD.ls();
//***************************************************************************
//НАЧАЛО ИМЕНИ ВХОДНОГО ФАЙЛА
//***************************************************************************
enterInputFileName:
Serial.println(F("Enter input file name:"));
while (!Serial.available()); // ждем, пока серийный номер станет доступен
char inbuf[64];
/******************************************************************************/
//создаем переменную для хранения количества прочитанных допустимых символов (не символов новой строки или возврата каретки)
byte pos = 0;
//читаем в массив, пока не получим символ новой строки
while (Serial.available() && Serial.peek() != '\n' && Serial.peek() != '\r') {
inbuf[pos] = Serial.read();
pos++;
//ждем, пока следующий символ не поступит в буфер
delay(timeBetweenChars);
}
while (Serial.available() && (Serial.peek() == '\n' || Serial.peek() == '\r')) {
//удаляем следующий символ из буфера
Serial.read();
//ждем, если есть еще один символ для очистки
delay(timeBetweenChars);
}
//конец массива в позиции pos
inbuf[pos] = '\0';
/******************************************************************************/
//создаем новый массив с правильным размером для имени входного файла
char inputFileName[pos];
//копируем данные из inbuf в inputFileName
strcpy(inputFileName, inbuf);
/******************************************************************************/
//подтвердите, что вы ввели правильное имя файла
confirmInputFileName:
Serial.print(F("Select file '"));
Serial.print(inputFileName);
Serial.println(F("'? Y/N"));
while (!Serial.available()); // ждем, пока серийный номер станет доступен
char confirm = Serial.read();
bool tooManyChars = 0;
// ждем следующих символов
delay(timeBetweenChars);
while (Serial.available()) {
//читаем следующий символ
char extra = Serial.read();
//если это не символ новой строки или возврата каретки
if (extra != '\n' && extra != '\r') {
//введено слишком много символов
tooManyChars = 1;
}
//ждем следующего символа
delay(timeBetweenChars);
}
/******************************************************************************/
if (tooManyChars) {
Serial.println(F("Enter 1 char"));
goto confirmInputFileName;
}
//если введен только 1 символ
switch (confirm) {
case 'Y': break;
case 'y': break;
case 'N': goto enterInputFileName; break;
case 'n': goto enterInputFileName; break;
//введен неверный символ
default: Serial.println(F("Enter Y/N")); goto confirmInputFileName; break;
}
/******************************************************************************/
Serial.print(F("Using file '"));
Serial.print(inputFileName);
Serial.println("' as input file");
if (SD.exists(inputFileName)) {
Serial.println(F("File exists"));
}
else {
Serial.println(F("Error, file does not exist. Please choose another file"));
goto enterInputFileName;
}
//***************************************************************************
//КОНЕЦ ИМЕНИ ВХОДНОГО ФАЙЛА
//************************************************ ******************************
//************************************************ ******************************
//НАЧАЛО ИМЕНИ ВЫХОДНОГО ФАЙЛА
//************************************************ ******************************
enterOutputFileName:
//очистить входной буфер
for (byte w = 0; w < (sizeof(inbuf) / sizeof(inbuf[0])); w++) {
inbuf[w] = '\0';
}
Serial.println(F("Enter output file name:"));
//ждем, пока поступят некоторые символы
while (!Serial.available());
/******************************************************************************/
//создаем переменную для хранения количества прочитанных допустимых символов (не символов новой строки или возврата каретки)
pos = 0;
//найдено здесь Serial.print(SD.exists(inputFileName));
//читаем в массив, пока не получим символ новой строки
while (Serial.available() && Serial.peek() != '\n' && Serial.peek() != '\r') {
//файл найден в первом цикле, но не после него
// найдено здесь Serial.println(SD.exists(inputFileName));
inbuf[pos] = Serial.read();
//здесь не найдено Serial.println(SD.exists(inputFileName));
pos++;
//ждем, пока следующий символ не поступит в буфер
delay(timeBetweenChars);
}
//входной файл здесь не найден
while (Serial.available() && (Serial.peek() == '\n' || Serial.peek() == '\r')) {
//удаляем следующий символ из буфера
Serial.read();
//ждем, если есть еще один символ для очистки
delay(timeBetweenChars);
}
//конец массива в позиции pos
inbuf[pos] = '\0';
/******************************************************************************/
//создаем новый массив с правильным размером для имени выходного файла
char outputFileName[pos];
//копируем данные из inbuf в outputFileName
strcpy(outputFileName, inbuf);
/******************************************************************************/
//подтвердите, что вы ввели правильное имя файла
confirmOutputFileName:
Serial.print(F("Select file '"));
Serial.print(outputFileName);
Serial.println(F("'? Y/N"));
while (!Serial.available()); // ждем, пока серийный номер станет доступен
confirm = Serial.read();
tooManyChars = 0;
// ждем следующих символов
delay(timeBetweenChars);
while (Serial.available()) {
//читаем следующий символ
char extra = Serial.read();
//если это не символ новой строки или возврата каретки
if (extra != '\n' && extra != '\r') {
//введено слишком много символов
tooManyChars = 1;
}
//ждем следующего символа
delay(timeBetweenChars);
}
/******************************************************************************/
if (tooManyChars) {
Serial.println(F("Enter 1 char"));
goto confirmOutputFileName;
}
//если введен только 1 символ
switch (confirm) {
case 'Y': break;
case 'y': break;
case 'N': goto enterOutputFileName; break;
case 'n': goto enterOutputFileName; break;
//введен неверный символ
default: Serial.println(F("Enter Y/N")); goto confirmOutputFileName; break;
}
/******************************************************************************/
Serial.print(F("Using file '"));
Serial.print(outputFileName);
Serial.println("' as output file");
if (SD.exists(outputFileName)) {
Serial.println(F("File already exists. Overwrite? Y/N"));
confirmOverwrite:
while (!Serial.available()); // ждем, пока серийный номер станет доступен
confirm = Serial.read();
tooManyChars = 0;
// ждем следующих символов
delay(timeBetweenChars);
while (Serial.available()) {
//читаем следующий символ
char extra = Serial.read();
//если это не символ новой строки или возврата каретки
if (extra != '\n' && extra != '\r') {
//введено слишком много символов
tooManyChars = 1;
}
//ждем следующего символа
delay(timeBetweenChars);
}
/******************************************************************************/
if (tooManyChars) {
Serial.println(F("Enter 1 char"));
goto confirmOverwrite;
}
//если введен только 1 символ
bool overwrite = 0;
switch (confirm) {
case 'Y': overwrite = 1; break;
case 'y': overwrite = 1; break;
case 'N': goto enterOutputFileName; break;
case 'n': goto enterOutputFileName; break;
//введен неверный символ
default: Serial.println(F("Enter Y/N")); goto confirmOverwrite; break;
}
if (overwrite) {
Serial.println(F("Removing output file"));
SD.remove(outputFileName);
}
}
Serial.println(F("Creating output file"));
outputFile = SD.open(outputFileName, FILE_WRITE);
outputFile.close();
//***************************************************************************
//КОНЕЦ ИМЕНИ ВЫХОДНОГО ФАЙЛА
//***************************************************************************
//***************************************************************************
//НАЧАЛО КОПИРОВАНИЯ
//***************************************************************************
//прочитать исходный код и записать в выходной файл
sourceFile = SD.open(inputFileName);
timeLast = micros();
//строка отладки
Serial.print(F("Exists(I,O): ")); Serial.print(SD.exists(inputFileName)); Serial.println(SD.exists(outputFileName));
if (sourceFile) {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.println(F("Copying"));
while (sourceFile.available()) {
//сделать размер буфера равным 50% от свободной оперативной памяти или количеству оставшихся байтов, если меньше
int ram = round((freeRam() * 0.5) / roundTo) * roundTo;
bufSize = min(ram, sourceFile.available());
//округлить до ближайшего значения roundTo
bufSize = round(bufSize / roundTo) * roundTo;
byte data[bufSize];
sourceFile.readBytes(data, bufSize);
lastPos = sourceFile.position();
sourceFile.close();
outputFile = SD.open(outputFileName, O_APPEND | O_WRITE);
outputFile.write(data, bufSize);
outputFile.close();
sourceFile = SD.open(inputFileName);
sourceFile.seek(lastPos);
//Serial.print(F("\tExists(I,O): ")); Serial.print(SD.exists(inputFileName)); Serial.print(SD.exists(outputFileName));
printStats();
}
sourceFile.close();
outputFile.close();
Serial.println(F("Finished"));
unsigned int sec = millis() / 1000;
unsigned int mins = sec / 60;
sec -= mins * 60;
Serial.print(F("Time taken: "));
Serial.print(mins);
Serial.print(':');
Serial.print(sec);
Serial.print(F("Speed: "));
Serial.print((sourceFile.size() / 1000) / (millis() / 1000));
Serial.print(F(" KB/s"));
}
// если файл не открыт, вывести ошибку:
else {
Serial.println("error opening files");
Serial.print(F("Exists(I,O): ")); Serial.print(SD.exists(inputFileName)); Serial.println(SD.exists(outputFileName));
SD.initErrorHalt();
}
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void printStats() {
timeNow = micros();
uint32_t timeTaken = timeNow - timeLast;
float sent = sourceFile.position() / 1000.0;
float fileSize = sourceFile.size() / 1000.0;
float left = fileSize - sent;
float speed;
speed = 1000000UL / timeTaken * bufSize;
speed /= 1000;
unsigned int sec = millis() / 1000;
unsigned int mins = sec / 60;
sec -= mins * 60;
int estSec = (left / speed);
int estMin = estSec / 60;
estSec -= estMin * 60;
Serial.print(F("\tSent (KB): ")); Serial.print(sent);
Serial.print(F("\tLeft (KB): ")); Serial.print(left);
Serial.print(F("\tSize (KB): ")); Serial.print(fileSize);
Serial.print(F("\tTime: ")); Serial.print(mins); Serial.print(':'); Serial.print(sec);
Serial.print(F("\tSpeed (KB/sec): ")); Serial.print(speed);
Serial.print(F("\tFree: ")); Serial.print(freeRam() - bufSize);
Serial.print(F("\tBuf: ")); Serial.print(bufSize);
Serial.print(F("\tEST: ")); Serial.print(estMin); Serial.print(':'); Serial.print(estSec);
//Serial.print(F("\tExists(I,O): ")); Serial.print(SD.exists(inputFileName)); Serial.print(SD.exists(outputFileName));
Serial.print('\n');
timeLast = micros();
}
Мой последовательный вывод (я выбрал Nova.mp3 в качестве входного файла и output.mp3 в качестве выходного файла):
Initializing SD card...Card initialized.
Files on card:
output.mp3
Nova.mp3
Eclipse.wav
Enter input file name:
Select file 'Nova.mp3'? Y/N
Using file 'Nova.mp3' as input file
File exists
Enter output file name:
Select file 'output.mp3'? Y/N
Using file 'output.mp3' as output file
File already exists. Overwrite? Y/N
Removing output file
Creating output file
Exists(I,O): 01
error opening files
Exists(I,O): 01
No error found.
Я знаю, что у меня не заканчивается память, и нет ошибок компилятора, но я понятия не имею, что не так. Возможно, я вставил какой-то ненужный код? Кроме того, если бы можно было открывать несколько файлов одновременно, ускорил бы я скорость чтения/записи?
@, 👍1
1 ответ
Лучший ответ:
Проблема в том, что у вас есть массивы символов для c-строки, завершающейся нулем, на один символ короче, чем нужно. Я вижу, что вы назначаете завершающий ноль inbuf[pos], а затем выделяете pos символов для имени файла и копируете pos количество символов. Это исключает завершающий ноль, а c-строка имени файла не завершается 0 и продолжается в памяти со случайным содержимым.
- Создание файла на SD-карте
- SD-карта не инициализируется
- Печать содержимого файла SD - карты на ЖК-дисплее
- RTC и SD работают отдельно, а не вместе
- Записать массив на SD
- Nextion Display не получает обновленных данных
- Использование Arduino wireless SD Shield для сохранения данных на SD-карту и отправки на ПК по беспроводной сети
- Инициализация SD-карты не удалась