wie wird auf SD gespeichert

Hallo,

ich verwende einen Arduino Mega 2560 mit Ether-Shield, beides V3.

Auf der SD-Karte sind Soll-Werte gespeichert, die der arduino im Minuten-Rhytmus mit aktuellen Messwerten vergleicht. Funktioniert alles bestens.

Die Sollwerte können sich zu beliebigem Zeitpunkt ändern, nicht alle, normaler Weise nur einer, auch eher selten. Bisher ändere ich die Daten auf der SD-Karte. Dies ist ziemlich umständlich. Deshalb möchte ich das Prozedere ändern.

Geändert werden sollen die Sollwerte, wegen des besseren Zugriffs über eine Web-Maske in einer SQL-Datenbank und der Arduino soll selber nachsehen, ob etwas geändert wurde und seine Datei auf der SD ändern.

Mein erster Ansatz war, arduino liest turnusmäßig, z. B. alle 3 Stunden, die SQL-Tabelle aus und schreibt eine neue Datei auf die SD, bzw. überschreibt die vorhandene.

Nun habe ich in Erinnerung, dass für die SD kein echtes Dateisystem existiert und nun stellt sich mir die Frage was spielt sich auf der Sd ab, wenn ich in einer existierenden Datei auf der SD-Karte einen Wert, also ein oder mehrere Zeichen ändern möchte. Geht das überhaupt, eine Datei zu überschreiben? Kann ich einzelne Zeichen in einer Datei ändern?

Da ist mein spartanisches Wissen am Ende. Kann mich jemand aufklären und mir helfen? Wie löse ich mein Problem?

Ich bin gespannt.
Gruß Gerd

Kann ich einzelne Zeichen in einer Datei ändern?

Ja. Das ist kein Problem

Am einfachsten geht es wenn man Zahlen auf eine konstante Breite formatiert. Dann wird z.B. 003 mit 010 oder 200 überschrieben. So bleibt der Rest unberührt, da alle Zeichen und alle Werte sind gleich breit sind.

Hier für ein einzige Zahl:

Da wird eine Zahl ausgelesen, inkrementiert und zurückgeschrieben

Das geht aber auch mit mehrere Zahlen pro Zeile. Und man kann auch mehrere Zeilen haben und Funktionen schreiben die bestimmte Zeile auslesen oder schreiben. Einfach indem man die Anzahl der Zeilen zählt.

Dateien kann man auch komplett überschreiben. In dem Beispiel habe ich das so gemacht dass ich wenn die Datei existiert, sie gelöscht wird und dann neu erzeugt.

Verständnisfrage: Nach meiner Kenntniss kann arduino nix auf der SD löschen. Dann wird also mit jedem "Überschreiben" eines Zeichens die Datei größer oder wie?

Wenn du eine Datei zum Schreiben öffnest geht es hinten weiter (beim Lesen am Anfang). Du kannst aber per seek() den Datei-Zeiger an eine bestimmte Position setzen. Siehe auch in dem Beispiel. Ich schreibe eine Zahl. Dann mache ich seek(0) um sie wieder zu lesen.

Oder z.B. wenn du sowas hast: "001,010,100"

Und du willst gezielt den N-ten Wert überschreiben. Bei 3 Zeichen Breite weißt du dass du den Zeiger auf (3 * N) + N setzen musst

Und mit SD.remove("datei.txt"); kannst Du Dateien löschen

OK, verstanden.
Wenn ich eine ganze Zeile ersetze, kann die dann verschieden lang sein? Ich habe ganz unterschiedliche Daten in einer Zeile: Temperaturwerte, Pin-Nummern, Adressen, Bezeichnungen usw., die kommasapariert im an gleicher Stelle stehen, aber unterschiedlich lang sind. Wenn gleicher Typ auch gleich lang sein müsste, wäre das ein ziemlicher Umstellungsaufwand.

DrEddison:
Und mit

SD.remove("datei.txt");

kannst Du Dateien löschen

Das hab ich bisher immer übersehen. Danke.
Werden dabei auch die Speicherzellen freigegeben oder ist trotz remove irgendwann die SD für den arduino voll?

gerd-wolfgang:
OK, verstanden.
Wenn ich eine ganze Zeile ersetze, kann die dann verschieden lang sein?

Wenn es nur eine Zeile ist kannst du natürlich eine kürzere durch eine längere ersetzen. Aber anders herum bleibt hinten Text stehen.

Wenn du mehrere Zeilen hast überschreibt dir eine längere Zeile teilweise die nächste. Richtige Zeilen gibt es ja im SD Speicher nicht. Die Text Editoren machen einfach nach einem CR/LF einen Zeilenumbruch.

Wenn gleicher Typ auch gleich lang sein müsste, wäre das ein ziemlicher Umstellungsaufwand.

Man muss die Daten vor oder während des Schreibens nur durch eine Formatierungsfunktion schicken.

Oder wenn sich die Daten in Grenzen halten, schreibe immer alles neu. Kommt auf die Anwendung an

Und wenn ich die komplette Datei ersetze? Geht das, wenn der Name gleich bleiben soll?

Sowie ich das verstehe kannst du in der Arduino SD Bibliothek nur die Datei löschen und neu erstellen. open() erstellt eine neue Datei wenn keine existiert. Aber man kann da nicht sage dass sie eine Datei überschreibt. Sowas wie CreateNew als Parameter beim Öfnen wie in .NET existiert leider nicht.

Aber das ist auch kein Problem:

  if (SD.exists("test.txt"))
    SD.remove("test.txt");

  dataFile = SD.open("test.txt", FILE_WRITE);

Siehe SD Doku:
https://www.arduino.cc/en/Reference/SD

ich gehe mal in mich.
Danke vorerst.

Bei sdFat findest du die gesuchte Functionalität.
Schau dir mal den oflag Parameter von open an.

  bool open(FatFile* dirFile, uint16_t index, uint8_t oflag);
  /** Open a file or directory by name.
   *
   * \param[in] dirFile An open FatFile instance for the directory containing
   *                    the file to be opened.
   *
   * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
   *
   * \param[in] oflag Values for \a oflag are constructed by a
   *                  bitwise-inclusive OR of flags from the following list
   *
   * O_READ - Open for reading.
   *
   * O_RDONLY - Same as O_READ.
   *
   * O_WRITE - Open for writing.
   *
   * O_WRONLY - Same as O_WRITE.
   *
   * O_RDWR - Open for reading and writing.
   *
   * O_APPEND - If set, the file offset shall be set to the end of the
   * file prior to each write.
   *
   * O_AT_END - Set the initial position at the end of the file.
   *
   * O_CREAT - If the file exists, this flag has no effect except as noted
   * under O_EXCL below. Otherwise, the file shall be created
   *
   * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
   *
   * O_SYNC - Call sync() after each write.  This flag should not be used with
   * write(uint8_t) or any functions do character at a time writes since sync()
   * will be called after each byte.
   *
   * O_TRUNC - If the file exists and is a regular file, and the file is
   * successfully opened and is not read only, its length shall be truncated to 0.
   *
   * WARNING: A given file must not be opened by more than one FatFile object
   * or file corruption may occur.
   *
   * \note Directory files must be opened read only.  Write and truncation is
   * not allowed for directory files.
   *
   * \return The value true is returned for success and
   * the value false is returned for failure.
   */

Ja, SdFat is super, aber auch um einiges komplexer. Wenn er schon so nicht weiß was er machen soll, vielleicht nicht die beste Idee :slight_smile:

Wobei SD nur ein Wrapper für eine ältere SdFat Version ist. Da hätte man ruhig etwas mehr Funktionalität durchreichen können.

Danke.

Ich möchte erstmal noch bei SD bleiben. SdFat überfordert mich (noch?), glaube ich.

Ich habe mir folgendes überlegt.
Mit folgendem php-Code stelle ich mir den Inhalt der SQL-Tabelle zusammen.

while ($row_sens = mysqli_fetch_row($ergebnis_query)) {
 foreach ($row_sens as $spalt) {
 $str .= $spalt . ",";
 }
 // letztes Komma abschneiden
 $str = substr($str, 0, strlen($str)-1);
 // Zeilenumbruch anhängen
 $str .= "\n";
 }
 // letztes \n-Zeichen abschneiden
 $str = substr($str, 0, strlen($str)-1);
 echo "#";
 echo $str;
 echo "#";

Mit den folgenden Zeilen habe ich dann die komplette Tabelle als String im Arduino.

            selbstClient.readStringUntil('#');            // Vorspann wird übersprungen
            strDB = selbstClient.readStringUntil('#');    // hier steht jetzt die gesamte Tabelle drin

Als nächstes lese ich die Daten aus der SD-Datei und vergleiche beide Strings. Sind sie identisch, ist keine Aktion notwendig. Dies wird zu 99% der Fall sein. Wenn es einen Unterschied gibt, lösche ich die bestehende Datei und speichere den String als neue Datei auf die SD-Karte.

So, nun eine Frage: Welches Zeichen ist "Dateiende".
Und eine zweite. Ich lese an diversen Stellen im Script aus dieser SD-Datei. Mal wird das Zeilenende durch \n erkannt mal durch \r. Es geht dabei immer um die selbe Datei und die selben Zeilenenden. Gibt es einen Grund für die unterschiedliche erkennung?
Gruß Gerd

So, nun eine Frage: Welches Zeichen ist "Dateiende".

Keins.

Am Dateiende liefert read() -1 (int) zurück.