<Solved> Arduino schreibt falsche Werte auf SD

Guten Tag zusammen

Ich bin neu im Forum und freue mich, hier zu sein.
Ich habe bereits einige Projekte auf dem Arduino realisiert, aber jetzt habe ich ein Problem mit meiner SD, die von einem Arduino Nano (alter Bootloader) bearbeitet wird.

Mein Programm macht folgendes: Zuerst rufe ich die Funktion set() auf. Diese liest eine Textdatei in ein String-Array (muss ein String-Array sein, da ich auch Zahlen durch Buchstaben ersetzen möchte) mit 8 Zeilen und 5 Spalten ein. Natürlich hat die SD genau diese 8 Zeilen und 5 Spalten.

Dann rufe ich die Funktion delet_row() auf, die die gewünschte Zeile "löscht", indem sie die Zeile beim Schreiben überspringt. Um die richtige Anzahl von Zeilen am Ende zu erhalten, füge ich am Ende eine neue Zeile ein, die mit Nullen gefüllt und wie der Rest durch ";" getrennt ist.

Mein Problem jetzt. Wenn ich das Programm zum ersten Mal starte, funktioniert alles einwandfrei. Beim zweiten Mal fügt es jedoch an der drittletzten Zeile eine zusätzliche Null ein und nimmt an der vorletzten Zeile eine Null weg. Beim dritten Versuch wird es nur noch schlimmer... :slightly_frowning_face:

Ich versuche schon lange, den Fehler zu finden, scheitere aber jedes Mal.
Ich würde mich freuen, wenn ihr mir helfen würden, und ich bin für jede Nachricht dankbar. Herzlichen Dank!

Mein Programm:

#include <SPI.h>
#include <SD.h>

String toRead= "REWR.TXT"; //Name des Files, das ich bearbeiten will.
char delim = ';';  //Damit ist im File die Spalte getrennt
const int x = 5;  //Anzahl Spalten
const int y = 8;  //Anzahl Zeilen
String param[y][x];  //String-Array, indem das File geladen wird bei set()



void setup()
{
  
  Serial.begin(9600);

  set();  //Funktion, die das File in den String-Array lädt
  delete_row(0);  //Löscht Zeile, bzw. liest gewünschte Zeile nicht wenn die Daten vom String auf die SD kommen
}

void loop()
{ 
  delay(1000);
}


void set(){
  delay(100);
  SD.begin(4);
  File dataFile;
  dataFile = SD.open(toRead);
  int i=0;  //Zähler, damit Anzahl Spalten stimmt und eine neue Zeile angefangen werden kann
  int j=0;  //Zähler, damit Anzahl Zeilen (v.a. letzte Zeile) stimmt und am Schluss keine neue Zeile angefangen wird.
  String stringOne = "";  // hier wird beim Einlesen der Datei die einzelnen Zeilen- und Spalteneinträge zwischengespeichert
  while (dataFile.available()) {
    char letter = dataFile.read();  // liest einzelne char's
    if (letter != '\r' || letter != delim ){
      stringOne.concat(String(letter));  // verbindet char's zu string, wenn kein Trennzeichen oder Umbruch
    }
    if (letter == delim || letter == '\r'){  // wenn Trennzeichen oder Umbruch, dann...
      if (i == x){  
        i = 0;
        j++;
      }
      stringOne.replace(String(delim),""); // nimmt dem String das Trennzeichen weg
      stringOne.replace("\n","");  // nimmt dem String den Umbruch weg
      param[j][i] = stringOne;
      i++;
      stringOne="";
    }
  }
  param[j][i]=stringOne;  // liesst fertigen String in String-Array ein
  dataFile.close();  // schliesst die geöffnete Datei
  stringOne = "";
}


void delete_row(int del_row){

  delay(100);
  SD.begin(4);
  File dataFile;
  SD.remove(toRead);  // löscht die Datei mit dem Namen REWR.TXT
  
  delay(100);

  SD.begin(4);
  dataFile = SD.open(toRead, FILE_WRITE);  //öffnet eine neue Datei zum schreiben mit dem gleichen Namen REWR.TXT
  if(dataFile){   // Wenn die Datei geöffnet/erstellt werden kann, dann...
    int i=0;
    int j=0;
    for (i = 0; i < (y+1); i++) { // Zähler für Anzahl Zeilen
      delay(1000);
      if (i == del_row){  // wenn die Zeile, die zu löschen ist, i ist, dann überspringt es diese Zeile
        Serial.println(i);  // Kontrolle auf dem Serial Monitor
        continue;
      }
      for (j = 0; j < x; j++) {  // Zähler für Anzahl Spalten
        if (i == y){ 
          if (j == (x-1)){  //Wenn letzte Zeile und letzte Spalte
            dataFile.print("0");  //Schreib auf SD null (0)
            Serial.print("0");
          }
          else{  // Wenn letzte Zeile aber nicht letzte Spalte
            dataFile.print("0"); // Schreib auf SD null (0) und Trennzeichen (;) 
            dataFile.print(String(delim));
            Serial.print("0");
            Serial.print(String(delim));
          }
        }
        else{
          if (j == (x-1)){  // Wenn letzte Spalte, aber nicht letzte Zeile
            dataFile.print(String(param[i][j]));
            dataFile.print("\n");
            Serial.print(String(param[i][j]));
            Serial.print("\n");
          }
          else{ // Wenn nicht letzte Spalte und nicht letzte Zeile
            dataFile.print(String(param[i][j]));
            dataFile.print(String(delim));
            Serial.print(String(param[i][j]));
            Serial.print(String(delim));
          }
        }
      }
     }
   }
  dataFile.close();
  delay(100);
}

Meine Datei "REWR.TXT, die ich bearbeiten möchte:

1;2;3;4;5
11;21;31;41;51
12;22;32;42;52
13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;57

Ergebnis nach einer Ausführung: (alles funktioniert gut) wie gewünscht erhalte ich auf letzte Zeile nur Nullen und die erste Zeile ist weg.

11;21;31;41;51
12;22;32;42;52
13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;57
0;0;0;0;0

Ergebnis nach zwei Ausführungen: (fügt eine Null hinzu) Wieder die erste Zeile ist weg im vergleich zur ersten Ausführung, aber die Null ist falsch positioniert.

12;22;32;42;52
13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;570
0;0;0;0;
0;0;0;0;0

Ergebnis nach drei Ausführungen: (eine neue Null) Eine Null weniger in der zweitletzten Spalte und wird bei ursprünglich 57 hinzugefügt

13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;5700
0;0;0;0;0
0;0;0;;
0;0;0;0;0

Ergebnis nach vier Ausführungen: (irgendetwas :o )

14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;57000
0;0;0;00;0
0;;0;0;0
0;0;;;
0;0;0;0;0

(deleted)

Vielen Dank für deine Nachricht.

Habe soeben den Code mit Kommentaren versetzt und zusätzlich einige Infos ergänzt.

ardumaker_ch:
Habe soeben den Code mit Kommentaren versetzt und zusätzlich einige Infos ergänzt.

Deine Überschrift stimmt nicht. :wink: Der Arduino schreibt eh keine, aber der Code schreibt schon richtige Werte auf die SD.

Wass fällt Dir auf?

void set()
{
  SD.begin (4);
  File dataFile;
  dataFile = SD.open (toRead);
}


void delete_row (int del_row)
{
  SD.begin (4);
  File dataFile;
  SD.remove (toRead); // löscht die Datei mit dem Namen REWR.TXT
  SD.begin (4);
  dataFile = SD.open (toRead, FILE_WRITE); //öffnet eine neue Datei zum schreiben mit dem gleichen Namen REWR.TXT
  dataFile.close();
}

Guten Abend my_xy_projekt

Danke für deinen Hinweis.

"SD.begin (4);" sollte eigentlich nur im setup und "File dataFile;" bei mir als globale Variable deklariert werden.

Habe den Code auch gerade laufen lassen, jedoch ohne Erfolg. Genau die gleiche Ausgabe wie zuvor... :frowning:

Welchen Arduino benutzt Du denn? Auf den kleineren kann String nicht richtig funktionieren, dann muß das ganze Programm erst einmal umgeschrieben werden.

Ich benutze einen Arduino Nano. Den Code habe ich aber auch auf einem Arduino Uno laufen lassen, mit dem gleichen Fehler.

Da ist ja der gleiche Prozessor drin, mit der gleichen Menge RAM.

Gruß Tommy

Ist so :sweat_smile:

Ein Uno / Nano sollte es jedoch zu Stande bringen, einen Text auf eine SD Karte zu schreiben.
Wenn ich sonst etwas auf eine SD schreiben will mit dem Uno / Nano, hat das auch immer funktioniert.

Aber danke für die Info Tommy56 :wink:

ardumaker_ch:
"SD.begin (4);" sollte eigentlich nur im setup und "File dataFile;" bei mir als globale Variable deklariert werden.

Habe den Code auch gerade laufen lassen, jedoch ohne Erfolg. Genau die gleiche Ausgabe wie zuvor... :frowning:

Das der Code nicht funktioniert, ist klar - es ist Deiner!
Nur runter gekürzt auf das minimale.
incl. aller SD.begin.

Ich seh auch grade, das sich da noch was geändert hat in der Zeit, als ich das rauskopiert, bearbeitet und dann meinen Post verfasst habe - Ist das da oben in #0 jetzt der Code der endgültig ist oder machst Du das dahin was Du vorgibst?
Denn derzeit ist noch immer mehrfach SD.begin drin. Stand jetzt 3x.

Ist eine etwas schroffe Antwort...

Was meinst du mit „ Nur runter gekürzt auf das minimale.
incl. aller SD.begin.“

Den usprünglich Code, den für das Arduino habe, ich hier im Forum nicht geändert. Habe deinen Vorschlag mal bei mir probiert.

ardumaker_ch:
Ein Uno / Nano sollte es jedoch zu Stande bringen, einen Text auf eine SD Karte zu schreiben.

Richtig erkannt, an denen liegt es nicht. Also steckt das Problem in Deinem Code, oder in dem, der diesen Code geschrieben hat.

Auf den kleinen Arduinos muß man auf etlichen Komfort verzichten, zu allererst auf diesen "String" Datentyp.

@TO: Sind das nur (ganze) Zahlen, die Du lesen/schreiben willst? In welchem Wertebereich?

Gruß Tommy

Ich möchte Buchstaben und Zahlen schreiben. Wenn Buchstaben gehen, sollten dann auch float-typen funktionieren, wenn ich die als String lese und schreibe.

Ich habe auch schon probiert, alle zahlen mit Wörtern zu ersetzen. Der genau gleiche Fehler.

Erster durchgang gut, dann nimmt es einen Buchstaben weg und fügt ihn anderswo ein.

Ich glaube, Du solltest erst mal verständlich erklären, was Du überhaupt willst.

Gruß Tommy

ardumaker_ch:
Ist eine etwas schroffe Antwort...

Ja, weil ich nicht das Ergebnis bekomme, was Du ausgibst und:

Was meinst du mit „ Nur runter gekürzt auf das minimale.
incl. aller SD.begin.“

Ich nicht verstehe, warum Du 3x SD.begin(4) verwendest.

Ich habe Deinen Code mit Deinem in #0 vorgegebenem File 1x durchlaufen lassen. Ergebnis:

21;31;41;5112;22
32;42;5213;23;33
43;5314;24;34;44
5415;25;35;45;5516
26;36;46;5617;27
37;47;57
;;
;;;;
0;0;0;0;0

Das weicht von dem ab, was Du angibst.

Mit dem, was Du in #0 nach dem zweiten Durchlauf angibst:

Ergebnis nach zwei Ausführungen: (fügt eine Null hinzu) Wieder die erste Zeile ist weg im vergleich zur ersten Ausführung, aber die Null ist falsch positioniert.
Code: [Select]

12;22;32;42;52
13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;570
0;0;0;0;
0;0;0;0;0

wäre die Logik, das Dir einfach eine Zeilenende-Markierung fehlt.
Kenn ich aus einer C#-Anwendung - da durfte die letzte Zeile des config-Files nicht mit Return abgeschlossen werden - das nur nebenbei.

Danach:

Ergebnis nach drei Ausführungen: (eine neue Null) Eine Null weniger in der zweitletzten Spalte und wird bei ursprünglich 57 hinzugefügt
Code: [Select]

13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;5700
0;0;0;0;0
0;0;0;;
0;0;0;0;0

Die Logik sagt, Du hast ein Zeilenende nicht erkannt und zählst parallel.

Dazu passt aber Dein Code nicht. - Denn der gibt hier etwas ganz anderes aus. Siehe vorher.

Ich würde Dir gerne helfen - kann es aber nicht, weil Dein Code mit Deiner Ausgabe hier nicht nachzustellen ist.
Und 3x SD.begin(4) ist - sagen wir mal: kontraproduktiv.

[edit] Attachments angefügt, nachdem auch nach xtem Verusch das gleiche Ergebnis

Topic_704653-15.zip (1.69 KB)

REWR Original.TXT (115 Bytes)

REWR nach Code.TXT (113 Bytes)

Tommy56:
Ich glaube, Du solltest erst mal verständlich erklären, was Du überhaupt willst.

Gruß Tommy

Was ich genau wollte habe ich eigentlich im ersten post geschrieben. War aber wahrscheinlich etwas unverständlich. -->

ardumaker_ch:
Ergebnis nach einer Ausführung: (alles funktioniert gut) wie gewünscht erhalte ich auf letzte Zeile nur Nullen und die erste Zeile ist weg.

11;21;31;41;51

12;22;32;42;52
13;23;33;43;53
14;24;34;44;54
15;25;35;45;55
16;26;36;46;56
17;27;37;47;57
0;0;0;0;0

my_xy_projekt:
Ja, weil ich nicht das Ergebnis bekomme, was Du ausgibst und:

Ich nicht verstehe, warum Du 3x SD.begin(4) verwendest.

Ich habe Deinen Code mit Deinem in #0 vorgegebenem File 1x durchlaufen lassen. Ergebnis:

21;31;41;5112;22

32;42;5213;23;33
43;5314;24;34;44
5415;25;35;45;5516
26;36;46;5617;27
37;47;57
;;
;;;;
0;0;0;0;0




Das weicht von dem ab, was Du angibst.

Ich habe den Code so bei mir laufen gelassen und das Ergebnis bekommen, was ich gepostet habe. Bei mir weicht es nicht ab... obwohl ich denselben Code verwende wie Du.

my_xy_projekt:
Ich würde Dir gerne helfen - kann es aber nicht, weil Dein Code mit Deiner Ausgabe hier nicht nachzustellen ist.
Und 3x SD.begin(4) ist - sagen wir mal: kontraproduktiv.

Warum ist denn das eigentlich "kontraproduktiv"?

Für eure Bemühungen möchte ich mich bedanken.
Ich habe den Fehler jedoch jetzt nach Ausgabe im Seriellen Monitor in HEX Form gefunden.
Das Problem war, dass ich eine if-Bedingung vergessen habe, die prüft, ob ich in der zweitletzten Zeile bin und dort zusätzlich zum "\n" ein "\r" einfügen muss.

So lautet der code nun:

#include <SPI.h>
#include <SD.h>

String toRead= "REWR.TXT"; //Name des Files, das ich bearbeiten will.
char delim = ';';  //Damit ist im File die Spalte getrennt
const int x = 5;  //Anzahl Spalten
const int y = 8;  //Anzahl Zeilen
String param[y][x];  //String-Array, indem das File geladen wird bei set()



void setup()
{
 
  Serial.begin(9600);

  set();  //Funktion, die das File in den String-Array lädt
  delete_row(0);  //Löscht Zeile, bzw. liest gewünschte Zeile nicht wenn die Daten vom String auf die SD kommen
}

void loop()
{
  delay(1000);
}


void set(){
  delay(100);
  SD.begin(4);
  File dataFile;
  dataFile = SD.open(toRead);
  int i=0;  //Zähler, damit Anzahl Spalten stimmt und eine neue Zeile angefangen werden kann
  int j=0;  //Zähler, damit Anzahl Zeilen (v.a. letzte Zeile) stimmt und am Schluss keine neue Zeile angefangen wird.
  String stringOne = "";  // hier wird beim Einlesen der Datei die einzelnen Zeilen- und Spalteneinträge zwischengespeichert
  while (dataFile.available()) {
    char letter = dataFile.read();  // liest einzelne char's
    if (letter != '\r' || letter != delim ){
      stringOne.concat(String(letter));  // verbindet char's zu string, wenn kein Trennzeichen oder Umbruch
    }
    if (letter == delim || letter == '\r'){  // wenn Trennzeichen oder Umbruch, dann...
      if (i == x){ 
        i = 0;
        j++;
      }
      stringOne.replace(String(delim),""); // nimmt dem String das Trennzeichen weg
      stringOne.replace("\n","");  // nimmt dem String den Umbruch weg
      param[j][i] = stringOne;
      i++;
      stringOne="";
    }
  }
  param[j][i]=stringOne;  // liesst fertigen String in String-Array ein
  dataFile.close();  // schliesst die geöffnete Datei
  stringOne = "";
}


void delete_row(int del_row){

  delay(100);
  SD.begin(4);
  File dataFile;
  SD.remove(toRead);  // löscht die Datei mit dem Namen REWR.TXT
 
  delay(100);

  SD.begin(4);
  dataFile = SD.open(toRead, FILE_WRITE);  //öffnet eine neue Datei zum schreiben mit dem gleichen Namen REWR.TXT
  if(dataFile){   // Wenn die Datei geöffnet/erstellt werden kann, dann...
    int i=0;
    int j=0;
    for (i = 0; i < (y+1); i++) { // Zähler für Anzahl Zeilen
      delay(1000);
      if (i == del_row){  // wenn die Zeile, die zu löschen ist, i ist, dann überspringt es diese Zeile
        Serial.println(i);  // Kontrolle auf dem Serial Monitor
        continue;
      }
      for (j = 0; j < x; j++) {  // Zähler für Anzahl Spalten
        if (i == y){
          if (j == (x-1)){  //Wenn letzte Zeile und letzte Spalte
            dataFile.print("0");  //Schreib auf SD null (0)
            Serial.print("0");
          }
          else{  // Wenn letzte Zeile aber nicht letzte Spalte
            dataFile.print("0"); // Schreib auf SD null (0) und Trennzeichen (;)
            dataFile.print(String(delim));
            Serial.print("0");
            Serial.print(String(delim));
          }
        }
        else{
          if (j == (x-1)){  // Wenn letzte Spalte, aber nicht letzte Zeile
            if (i == (y-1)){
              dataFile.print(String(param[i][j]));
              dataFile.print("\r");
              dataFile.print("\n");
              Serial.print(String(param[i][j]));
              Serial.print("\r");
              Serial.print("\n");
            }
            else{
              dataFile.print(String(param[i][j]));
              dataFile.print("\n");
              Serial.print(String(param[i][j]));
              Serial.print("\n");
            }
          }
          else{ // Wenn nicht letzte Spalte und nicht letzte Zeile
            dataFile.print(String(param[i][j]));
            dataFile.print(String(delim));
            Serial.print(String(param[i][j]));
            Serial.print(String(delim));
          }
        }
      }
     }
   }
  dataFile.close();
  delay(100);
}

Wünsche allen gute Nacht und nochmals danke für eure Hilfe :wink:

Moin,

ardumaker_ch:
Ich habe den Fehler jedoch jetzt nach Ausgabe im Seriellen Monitor in HEX Form gefunden.
Das Problem war, dass ich eine if-Bedingung vergessen habe, die prüft, ob ich in der zweitletzten Zeile bin und dort zusätzlich zum "\n" ein "\r" einfügen muss.

Na sag ich doch :wink:

So lautet der code nun:

Hab ich mal ausprobiert.
Ich hab nur eine zusätzliche Zeile im Setup um zu sehen, das da tatsächlich was passiert und gebe "Start" aus.
Nach dem ersten Durchlauf Ausgabe auf dem seriellen Monitor:

11:02:21.282 -> Start
11:02:23.309 -> 0
11:02:24.305 -> 21;31;41;5112;22
11:02:25.302 -> 32;42;5213;23;33
11:02:26.299 -> 43;5314;24;34;44
11:02:27.329 -> 5415;25;35;45;5516
11:02:28.326 -> 26;36;46;5617;27
11:02:29.323 -> 37;47;57
11:02:29.323 -> ;;
11:02:30.319 -> ;;;;
11:02:31.316 -> 0;0;0;0;0

Und so ist auch der Inhalt auf der Karte.
Die Textdatei entspricht der von gestern Abend - siehe oben.
Beim Start hat sie 115 bytes - nach dem Durchlauf 114

Schau Dir mal die Texttdateien an.

REWR_Nach_Durchlauf.TXT (114 Bytes)