使用arduino从SD卡存储文件的最后一个值

Storing the last value of a file from SD card using arduino

我正在做一个前后移动的设备,需要存储它的最后一个位置,以便在通电时,可以从 SD 卡上文件的最后一行中抓取最后存储的值,并且可以恢复运行。然后该文件将被销毁并重写。对于这个特定的应用程序,不能使用归位和其他方法,因为它必须从上次所在的位置开始。由于通过编码器进行位置跟踪,因此没有位置记忆 otherwise.The 文件设置为由逗号分隔的单个数据列。

目前,随着位置的变化,我正在成功地写入 SD 卡,并读取要在串行监视器上打印的整个文件。但是,我真的只需要最后一个值。文件的长度总是因系统操作而异。

我已经阅读了很多不同的解决方案,但其中 none 似乎适用于我的应用程序。

我可以使用以下方法读取整个文件:

void read_file() {
  // open the file for reading:
  myFile = SD.open("test8.txt");
  if (myFile) {
    Serial.println("test8.txt:");
    // read from the file until there's nothing else in it:
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      String a = "";
      for (int i = 0; i < 9; ++i)
      {
        int j;
        char temp = myFile.read();
        if (temp != ',' && temp != '\r')
        { //a=temp;
          a += temp;
        }
        else if (temp == ',' || temp == '\r') {
          j = a.toInt();
          // Serial.println(a);
          Serial.println(j);
          break;
        }
      }
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test8.txt");
  }
}

这给了我一个由 0 分隔的值流,如下所示:

20050
0
20071
0
20092
0
20113
0
20133
0

理想情况下,我只需要抓取 20133 并将其存储为一个整数。

我也试过:

void read_file_3() {
  // open the file for reading:
  myFile = SD.open("test8.txt");
  if (myFile) {
    Serial.println("test8.txt:");
    // read from the file until there's nothing else in it:
    Serial.println(myFile.seek(myFile.size()));
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

这只是returns“1”,对我来说没有任何意义。

更新: 我找到了一个可以满足我要求的草图,但是由于使用了字符串 class,所以速度很慢。根据 post #6 这里:https://forum.arduino.cc/index.php?topic=379209.0

这确实会获取最后存储的值,但是随着文件变大需要相当长的时间,并且可能会耗尽内存。

没有字符串 class 怎么能做到这一点?

void read_file() {
  // open the file for reading:
  myFile = SD.open("test8.txt");
  if (myFile) {
    while (myFile.available())
    {
      String  line_str = myFile.readStringUntil(',');  // string lavue reading from the stream - from , to , (coma to comma)
      int line = line_str.toInt();
      if (line != 0) // checking for the last NON-Zero value
      {
        line2 = line; // this really does the trick
      }
//      Serial.print(line2);
//      delay(100);
    }
    Serial.print("Last line = ");
    Serial.print(line2);
    // close the file:
    myFile.close();
    //    SD.remove("test3.txt");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

如有任何帮助,我们将不胜感激!

seek returns 如果它成功到达该位置则为真,如果在那里没有找到任何东西则为假,例如文件不是那么大。它不会给你那个位置的价值。这就是为什么你看到 1,seek 返回真,它能够到达位置 (myFile.size()),这就是你正在打印的内容。

除此之外,您不想转到文件末尾,那将在您的号码之后。如果您的号码是 5 位数字,您想转到文件末尾前 5 个字符的位置。

无论哪种方式,一旦您找到了那个位置,您仍然需要像在第一个代码中那样使用 read 来实际读取数字。 seek 不会这样做,它只会将您带到文件中的那个位置。

编辑:由于您编辑了 post,我将编辑答案以供参考。你在倒退。你第一次做对了。使用与开始时相同的读取方法,只需在开始读取之前查找文件末尾,这样就不必一直读取。你几乎拥有它。您第一次做错的唯一一件事是打印从查找中返回的内容,而不是查找正确的位置然后读取文件。

您使用字符串 class 查找的内容正在从您所在的位置倒退。忘记你曾经见过。它正在做你一开始就已经在做的同样的事情,只是它还在这个过程中浪费了大量的内存和代码space。

使用您的原始代码,只需添加一个跳转到文件末尾的搜索。

这假定它始终是一个 5 位数字。如果不是,那么您可能需要进行一些调整:

void read_file() {
  // open the file for reading:
  myFile = SD.open("test8.txt");
  if (myFile) {
    Serial.println("test8.txt:");

    /// ADDED THIS ONE LINE TO SKIP MOST OF THE FILE************
    myFile.seek(myFile.size() - 5);


    // read from the file until there's nothing else in it:
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      String a = "";
      for (int i = 0; i < 9; ++i)
      {
        int j;
        char temp = myFile.read();
        if (temp != ',' && temp != '\r')
        { //a=temp;
          a += temp;
        }
        else if (temp == ',' || temp == '\r') {
          j = a.toInt();
          // Serial.println(a);
          Serial.println(j);
          break;
        }
      }
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test8.txt");
  }
}

看,我所做的就是采用您的原始函数并添加一行以结束它。