SD-Karte auslesen

Hallo,

vor kurzer Zeit habe ich mit dem Arduino-programmieren angefangen und stehe nun vor dem ersten großen Problem:

Ich möchte aus einer .TXT Datei auf einer SD-Karte , Zeile für Zeile einlesen und bearbeiten.

Die Datei hat folgenden Aufbau:
N24 G1 X0104.5 Y0059.3
N25 G1 X0114.5 Y0061.4
N26 G1 X0120.5 Y0068.5
N27 G1 X0129.5 Y0070.6
...
...
...
...

Ich habe es bereits geschafft eine einzelne Zeile über den Seriellen Monitor einzugeben und wie folgt aufzuschlüsseln:

Zeilennummer = N:24
Befehl = G:1
Koordinate X:0104.5
Koordinate Y:0059.3

Hierzu der Code:

String readString; //main captured String
String zeile; //data String
String befehl;
String x;
String y;

int ind1;
int ind2;
int ind3;
int ind4;

 
void setup() {
  Serial.begin(19200);
  while(!Serial);
  readString=""; //clears variable for new input
}

void loop() {

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '\n') {
      //do stuff
     
      Serial.println();
      Serial.print("captured String is : ");
      Serial.println(readString); //prints string to serial port out
     
      ind1 = readString.indexOf('N');
      ind2 = readString.indexOf('G', ind1+1 );
      ind3 = readString.indexOf('X', ind2+1 );
      ind4 = readString.indexOf('Y', ind3+1 );

      
      zeile = readString.substring(ind1+1, ind2);
      befehl = readString.substring(ind2+1, ind3);
      x = readString.substring(ind3+1, ind4);
      y = readString.substring(ind4+1);

      Serial.print("Zeilennummer = N:");
      Serial.println(zeile);
      Serial.print("Befehl = G:");
      Serial.println(befehl);
      Serial.print("Koordinate X:");
      Serial.println(x);
      Serial.print("Koordinate Y:");
      Serial.println(y);
      Serial.println();
      Serial.println();
     
      readString=""; //clears variable for new input
      zeile="";
      befehl="";
      x="";
      y="";
    } 
    else {     
      readString += c; //makes the string readString
    }
  }
}

Nun möchte ich Zeile für Zeile meiner .TXT Datei abarbeiten, jedoch habe ich vergeblich versucht hier die SD-Karte mit einzubinden und den Ablauf zu automatisieren, um nicht jede Zeile einzeln eingeben zu müssen.
Das reine auslesen der Datei habe ich bereits geschafft, aber nicht in Verbindung mit der oben gezeigten Aufschlüsselung der einzelnen Parameter.

Ich hoffe auf Hilfe.
Beste Grüße
Daniel

Hallo,

zu der SD lib gibt es Beispiele in der IDE. Nimm eines davon um die Hardware zu testen. In der Hilfe gibt es einen Doku zu der Lib.

Heinz

Ob man von Serial oder SD einliest ist eigentlich egal. Die Serial und File Klassen implementieren beide das Stream Interface und haben somit zum Einlesen die gleichen Methoden. Man kann sich sich sogar eine Funktion schreiben die wahlweise von Serial oder SD liest. Einfach in dem man entweder eine Referenz auf ein Serial oder ein File Objekt übergibt.

Das geht übrigens mit C Strings (Null-terminierte char Arrays) bequemer. Mit strtok() und/oder Zeiger-Arithmetik ist das Splitten und Konvertieren von Teil-Strings sehr einfach.

Eine Weiterverwendung des wunderbaren und mich noch heute faszinierenden Code von Serenifly von vor 5 Jahren ist hier möglicherweise die Lösung.

Peer

Und weils evtl. notwendig ist: Ich habe heute 18:44 Uhr MEZ nur ein Reply - Sollten also Hinweise derart schon drin stehen, sehe ich Sie nicht.

Danke für eure schnellen Antworten :slight_smile:

Rentner:
zu der SD lib gibt es Beispiele in der IDE. Nimm eines davon um die Hardware zu testen. In der Hilfe gibt es einen Doku zu der Lib.

Meine SD-Karte habe ich seperat bereits erfolgreich ausgelesen.

Serenifly:
Ob man von Serial oder SD einliest ist eigentlich egal. …

Das habe ich mir eigentlich auch gedacht, aber es will nicht funktionieren.

Hier ist mein Code, bei dem ich versucht habe von der SD-Karte zu lesen.
Aber hier wird nichts ausgegeben.

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

String readString; //main captured String
String zeile; //data String
String befehl;
String x;
String y;

File myFile;

int ind1;
int ind2;
int ind3;
int ind4;

int chipSelect = 4;

void setup() {
  Serial.begin(19200);
  while (!Serial);
  readString = ""; //clears variable for new input

  SD.begin(chipSelect);

  myFile = SD.open("gcode.txt");

  if (myFile) {

    Serial.println("SD-Karte wurde erfolgreich verbunden");
  }

  else {
    Serial.println("SD-Karte konnte nicht verbunden werden");
    while (1);
  }
  myFile.close();
}

void loop() {
  myFile = SD.open("gcode.txt");
  
  if (myFile)  {
    char c = myFile.read();  //gets one byte from serial buffer
    if (c == '\n') {
      //do stuff

      Serial.println();
      Serial.print("captured String is : ");
      Serial.println(readString); //prints string to serial port out

      ind1 = readString.indexOf('N');
      ind2 = readString.indexOf('G', ind1 + 1 );
      ind3 = readString.indexOf('X', ind2 + 1 );
      ind4 = readString.indexOf('Y', ind3 + 1 );


      zeile = readString.substring(ind1 + 1, ind2);
      befehl = readString.substring(ind2 + 1, ind3);
      x = readString.substring(ind3 + 1, ind4);
      y = readString.substring(ind4 + 1);

      Serial.print("Zeilennummer = N:");
      Serial.println(zeile);
      Serial.print("Befehl = G:");
      Serial.println(befehl);
      Serial.print("Koordinate X:");
      Serial.println(x);
      Serial.print("Koordinate Y:");
      Serial.println(y);
      Serial.println();
      Serial.println();

      readString = ""; //clears variable for new input
      zeile = "";
      befehl = "";
      x = "";
      y = "";
    }
    else {
      readString += c; //makes the string readString
    }
  }
}

Woran kann es hier liegen?

Daniel

@my_xy_projekt

Das ist was anderes. Das verwendest die SdFat Klasse. SdFat ist super, aber nichts wenn er schon mit der normalen SD Lib nicht zurechtkommt.
Die Funktion in dem Thread ist auch für ein etwas anderes Problem. Da kann man eine Zeilennummer übergeben und sie liefert genau diese Zeile. Das braucht man hier nicht unbedingt.

Erst mal eine einzelne Zeile einlesen geht auch mit den normalen Arduino Mitteln:

Und statt Serial einfach ein File Objekt übergeben. Sollte theoretisch immer true liefern bis man an Ende der Datei ist. Bei Serial bricht die Funktion durch die langsame Geschwindigkeit der Schnittstelle nach jedem Zeichen ab. Bei SD bleibt man dagegen in der while-Schleife bis man eine komplette Zeile hat.

Ist aber etwas her dass ich das getestet habe! Deshalb keine Garantie, dass da nichts schiefgehen kann

Ansonsten geht das aber auch mit den Arduino Funktionen wie readStringUntil(), readBytesUntil(), etc.

@danimangl
EDIT: Ich hatte es erst falsch gesehen, daher die Änderung

Du machst in loop() ständig die Datei auf und liest immer nur ein Zeichen. Das kann nicht gehen. Wenn du read() machst um den String Zeichen für Zeichen zusammenzusetzen brauchst du eine Schleife irgendeiner Art.

Oder du verwendest fertige Funktionen wie readString(), readStringUntil(), readBytesUntil(), etc. aus der Stream Klasse. Die lesen eine komplette Zeile auf einmal

Hallo,

du ließt immer nur ein Zeichen ein und erwartest ein Zeilenende ‘\n’ vermutlich hast Du aber in der Datei ein anderes Endzeichen z.B CR

if (myFile) {
char c = myFile.read(); //gets one byte from serial buffer
if (c == ‘\n’) {
//do stuff

Lass dir mal die Zeichen in c als hex ausgeben es geht um CR oder LF ascii dec 12 10 oder 13.

Heinz

Serenifly:
Die Funktion in dem Thread ist auch für ein etwas anderes Problem. Da kann man eine Zeilennummer übergeben und sie liefert genau diese Zeile. Das braucht man hier nicht unbedingt.

Die Betonung liegt auf dem letzten Satz. Habe mich auch ohne 100% Kenntnis SD mit dem von Dir zur Verfügung gestellten Code auf SDfat gestürzt. Ergebnis: funktioniert. Sicher nicht perfekt.
Bin Dir aber absolut Dankbar für diesen Codeschnipsel, weil ich die Aufgabenstellung damit lösen konnte.

Serenifly:
Ansonsten geht das aber auch mit den Arduino Funktionen wie readStringUntil(), readBytesUntil(), etc.

:wink:
Danke für den Hinweis.

Rentner:
du ließt immer nur ein Zeichen ein und erwartest ein Zeilenende '\n' vermutlich hast Du aber in der Datei ein anderes Endzeichen z.B CR

Zeilen sind mit CR + LF abgeschlossen

Das kann man so machen. Aber man muss das in einer Schleife tun nachdem man die Datei geöffnet hat. Was er dagegen macht ist die Datei öffnen und ein Zeichen lesen. Dann fängt loop() wieder an und öffnet die Datei erneut

Aber wie schaffe ich es dann, Zeile für Zeile nacheinander einzulesen, auszuwerten und zur nächsten Zeile zu springen?

Kann mir eventuell jemand einen groben Ablauf darstellen?

Tut mir leid, aber ich komme gerade nicht von der Stelle.

Eine Datei hat intern einen Zeiger auf das nächste Zeichen. Jedesmal wenn gelesen wird wird der weiter gesetzt. Zeilen sind mit einem LF abgeschlossen. Wenn keine Zeichen mehr da sind ist die Datei zu Ende. Deshalb musst du auch mit dem öffnen aufpassen. Einmal öffnen, die Datei bearbeiten und erst dann schließen. Und nicht ständig neu öffnen

Siehe auch:
https://www.arduino.cc/en/Reference/FileAvailable
https://www.arduino.cc/en/Reference/FileRead

Das gleiche wie bei Serial. Entweder man fragt available() ab und man schaut ob read() -1 ist

Okay danke, ich werde es mir in den nächsten Tagen noch einmal ansehen.

Besten Dank für die Hilfe :slight_smile:

Grüße Daniel

Das ist übrigens ein Grund weshalb sowas in Funktionen auslagert. Also eine Funktion schreiben (oder eine fertige verwenden) die eine Zeile einliest. Und melden dass entweder eine Zeile gelesen wurde oder nicht. Dann weiß nach dem Aufruf das man sie auswerten muss oder man ist fertig.

Serenifly:
Zeilen sind mit CR + LF abgeschlossen

Das kann man so machen. Aber man muss das in einer Schleife tun nachdem man die Datei geöffnet hat. Was er dagegen macht ist die Datei öffnen und ein Zeichen lesen. Dann fängt loop() wieder an und öffnet die Datei erneut

Stimmt das hatte ich so nicht gesehen

Heinz

Hi,
vielleicht helfen Dir Codeteile aus meinem "Müllkalender"weiter?

Da lese ich auch Daten von einer SD und werte sie aus!

Grüße
Jörg

Danke an alle die geholfen haben :slight_smile:
Nun funktioniert es.

@Joerg_L:
Ein sehr schönes und übersichtliches Programm...hat mir enorm weitergeholfen!

Grüße Daniel