Nummerische Daten aus der Speicherkarte auslesen und aufteilen

Hallo Gemeinde
Ich stehe gerade mal wieder komplett auf der Leitung. Ich habe mit dem PC eine Excel Datei erstellt und die auf die SD-Karte geladen. Dann mit dem Arduino mit "Serial.write" wieder ausgelesen.

 myFile = SD.open("Mappe1.csv");
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
    gelesen = 1;
    lcd.setCursor(0, 1);
    lcd.print(F("                    "));
    lcd.setCursor(0, 1);
    lcd.print(F("  Daten uebergeben  "));

Das sieht dann so aus:

3;1;2;1000;200;0,5<\r><\n>
1;1;1;200;30800;77<\r><\n>
2;1;1;700;10800;27<\r><\n>
3;1;2;1000;200;0,5<\r><\n>
1;1;1;200;30800;77<\r><\n>
2;1;1;700;10800;27<\r><\n>
3;1;2;1000;200;0,5<\r><\n>
1;1;1;200;30800;77<\r><\n>
2;1;1;700;10800;27<\r><\n>
3;1;2;1000;200;0,5<\r><\n>
1;1;1;200;30800;77<\r><\n>
2;1;1;700;10800;27<\r><\n>
3;1;1;1000;20000;50<\r><\n>

Aber ich habe jetzt absolut keine Vorstellung wie ich das jetzt Zeilenweise in einzelne Variablen √ľbergebe. :grinning: Idial ist von jeder Zeile z.B. die erste Zahl in ein Array, von jeder Zeile die zweite Zahl in ein Array, das bis zur f√ľnften Zahl, dass ich danach 5 Array¬īs habe. Dann habe ich gewonnen.

Da stehe ich gerade restlos daneben. :roll_eyes:

Franz

Hallo Franz,
ich sehe sechs Zahlen pro Zeile.
Wenn die jeweils zusammen geh√∂ren w√ľrde ich zu einem Array of struct raten.
Das Aufteilen wird vermutlich mit strtok (oder so ähnlich) am einfachsten gehen.


Gruß Walter

Hallo,
Na ja Du kannst mit String Objekt arbeiten readStringUnti () und dann nach ";" trennen oder jeweils in eine C Zeichenkette bilden dazu zeichenweise bis CR lesen und dann mit strtok arbeiten. Anschlie√üen die einzelnen Teilketten mit ati wandeln. ich w√ľrde zweites machen.
https://de.wikibooks.org/wiki/C-Programmierung:_Zeichenkettenfunktionen#strtok

Heinz

Hallo Franz,
wozu willst Du das erst in Array einlesen, Lies die SD Karte dann zeilenweise aus wenn du es brauchst. Du kannst die Datei ja offen lassen und dann immer nur eine Zeile lesen, fahren , lesen , ....
Heinz

strtok.

wurde eh schon genannt.

Aber ehrlich warum tust du dir das eigentlich an? Warum nimmst nicht einen GRBL Sketch und baust das nach? bzw. eigentlich f√ľr 30 EUR aufw√§rts bekommst eine fertiges GRBL Board f√ľr 3 Achsen das normalen G-Code verarbeitet. Quasi "jede" Software kann G-Code generieren, der Universal G-Code Sender schickt dass dann zu deiner Fr√§se.
Oder eben den G-Code auf eine SD-Karte und √ľber ein "Offline" Bedienteil abarbeiten.

Aber eine Fr√§sersteuerung f√ľr eine Selbstbau Fr√§se von 0 an schreiben zu wollen, du das ist schon sehr ambitioniert...

Ja, ich wollte erst auslesen, dann die Fräse sausen lassen. Aber ja, ich schaue mal, wie es mit den beiden Möglichkeiten funktioniert.

Ja, aber die sechste ist nicht sooo interessant, das sind die mm der fahrwege die in Excel schon in Schritte umgerechent wurden.

Im Endefekt wird es eh EstlCam werden, aber dass es mir nicht langweilig wird, m√∂chte ich auch was selber bauen. Zum Schluss wird es eine Unterst√ľtzung zum Bohren werden, also Automatisches anfahren der Bohrl√∂cher mit dem Kreuztisch, und die Fr√§se wird vielleicht auch eine Extra Geschichte. Also im Endefekt ist es auch bischen Besch√§ftigung f√ľr ein m√ľdes Hirn. :grinning:

Hallo
@Franz54 aus der Bastelkiste gekroost. :wink:
Heinz

char zeile[] = {"1;1;3;100;1000;2000"};
int var1;
int var2;
int var3;
int var4;
int var5;
int var6;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  var1 = atoi(strtok(zeile, ";"));
  var2 = atoi(strtok(NULL, ";"));
  var3 = atoi(strtok(NULL, ";"));
  var4 = atoi(strtok(NULL, ";"));
  var5 = atoi(strtok(NULL, ";"));
  var6 = atoi(strtok(NULL, ";"));

  Serial.println(var1);
  Serial.println(var2);
  Serial.println(var3);
  Serial.println(var4);
  Serial.println(var5);
  Serial.println(var6);

}

void loop() {
  // put your main code here, to run repeatedly:


}

Danke dir. Da mache ich mich morgen dr√ľber.

Ich w√ľnsche allen eine gute Nacht, servus
Franz

Hallo Franz
mir kommt da gerade noch eine Idee f√ľr Dich. Du bastelst doch gerade mit einem ESP32 rum. Dann nutze doch das Filesystem von dem Ding und von Fips den Fileserver. Dann kannst Du mittels Webseite des ESP eine CSV Datei von deinen PC auf den ESP uploaden und dann da nutzen. Damit sparst Du dir den Umweg √ľber die SD Karte und bekommst Einblick in sicher ganz was neues f√ľr Dich.
Heinz

Naja, da k√∂nnte ich dann mal dr√ľber nachdenken wenn ich dieses Problem hier erst mal vom Hals habe. Ich bin mit meinem Prblem noch nicht weiter gekommen. Der Kartenleser bringt mir die Daten die ich hier gezeigt habe nicht Zeilenweise sondern den Buchstaben jedes Satzzeichen einzeln. Was man nat√ľrlich nicht sieht. Somit habe ich keine Zeilen, sondern einzelne Zeichen die nur durch die Steuerzeichen Return und neue Zeile, die es nur so aussehen lassen wie fertige S√§tze die ich nur noch an den Strichpunkten trennen muss. Das ist eine Sache die ich noch nicht machen musste, also v√∂lliges Neuland. Also ich stehe v√∂llig am Schlauch. Wer ist denn da fit.

Ich habe hier unten in der PDF mal die die einzelnen Übergaben sichtbar gemacht, mit Trennzeichen und Nummerierung der einzelnen Zeichen. und der zweite Teil ist dann das Array wieder zusammengesetzt. Also ich mache bis jetzt nur ein Array in das ich die Daten aus der Karte eingelesen habe. Wie ich dann aber die eizelnen zahlen zusammensetze weiß ich noch nicht. Die Nummern zwischen den Zeichen z.B. #23# sind nur die Nummern der Zeichen Array.

Und da noch das Programm mit dem ich diese Daten ausgelesen habe, und dargestellt habe. Im Durchlauf "0" bringe ich die Daten aus der Karte in ein Array, im Durchlauf "1" zeige ich die Daten mit der Adresse im Array, im Durchlauf "2" setze ich die Daten aus dem Array wieder zusammen. Das Ergebnis ist in der PDF Datei.

/*
  SD card read/write

  Dieses Beispiel zeigt, wie Sie Daten von einer SD-Kartendatei lesen und schreiben
  SD-Karte wie folgt an SPI-Bus angeschlossen:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
   Achtung beim Mega
 ** MOSI - pin 51
 ** MISO - pin 50
 ** CLK - pin 52
 ** CS - pin 53 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

*/
#include <SPI.h>
#include <SD.h>
File myFile;
char quelle[400];
//char quelle;
int zaehler = 0;
int zaehler2 = 0;
byte durchlauf = 0;
//===========================================================================================
void setup() {
  // Open serial communications and wait for port to open:
  pinMode(SS, OUTPUT);
  Serial.begin(9600);
  while (!Serial) {
    ; // Warten Sie, bis die serielle Schnittstelle eine Verbindung hergestellt hat. Nur f√ľr nativen USB-Port erforderlich
  }
  Serial.print("Initializing SD card...");

  if (!SD.begin(53)) {
    Serial.println("Initialisierung fehlgeschlagen!");
    while (1);
  }
  Serial.println("Initialisierung abgeschlossen .");
}
//==========================================================================================
void loop() {
  if (durchlauf == 0) {
    // öffne die Datei. Beachten Sie, dass jeweils nur eine Datei geöffnet sein kann.
    // Sie m√ľssen diese also schlie√üen, bevor Sie eine andere √∂ffnen.
    myFile = SD.open("Mappe1.csv"); // File Mappe1.csv öffnen
    if (myFile) {
      Serial.println("Mappe1.csv geöffnet:");
      zaehler = 0;
      Serial.println("Durchlauf 0");
      // aus der Datei lesen, bis nichts mehr drin ist :
      while (myFile.available()) {
        //Serial.write(myFile.read());
        quelle[zaehler] = (myFile.read());
        Serial.print(quelle[zaehler]);
        Serial.print(" #");
        Serial.print(zaehler);
        Serial.print("# ");
        zaehler ++;
      }
      // schließe die Datei:
      myFile.close();
      Serial.print("*** ");
      Serial.print(zaehler);
      Serial.println(" ***");
      durchlauf = 1;
    } else {
      // Wenn die Datei nicht geöffnet wurde, drucke einen Fehler :
      Serial.println("Fehler beim √Ėffnen von test.txt ");
    }
    Serial.println("Durchlauf 1");
  }
  if (durchlauf == 1)
  {
    Serial.print(quelle[zaehler2]);
    zaehler2 ++;
    if (zaehler2 == zaehler)
    {
      durchlauf = 2;
    }
  }
  if (durchlauf == 2)
  {
    Serial.println("Durchlauf 2");
    Serial.print(quelle);
    Serial.println("**********");
    Serial.println("** Ende **");
    Serial.println("**********");
    durchlauf = 3;
  }
}

Excel_Datei_aus_SD.pdf (21,5 KB)

Oder eigentlich muss ich ja die Zahlen zusammenfassen die zwischen den Semikolon¬īs stehen. Also wenn da "3;1;2;1000;200;0,5<\r>" im Array steht in 19 Positionen steht, dass ich hernach
"3" - "1" - "2" - "1000" - "200" - "0,5" in 6 Variablen habe.
Kann man das zwischen den Semikolon¬īs gleich zusammenf√ľhren, oder ist es einfacher, erst den Satz komplett zusammenzuf√ľhren, um in dann mit dem Programm von Heinz zu trennen?

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

const byte chipSelectPin = 4;
const String filename = "x2.csv";
char zeilenBuffer[30];
char auswerteBuffer[6][8];
File myFile;


void setup()
{
  pinMode(SS, OUTPUT);
  Serial.begin(9600);
  while (!Serial)
    Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelectPin))
  {
    Serial.println("Initialisierung fehlgeschlagen!");
    while (1);
  }
  Serial.println("Initialisierung abgeschlossen .");
}
//==========================================================================================
void loop()
{
  myFile = SD.open(filename);
  Serial.print(filename);
  if (myFile)
  {
    Serial.println(F(" geöffnet!"));
    while (myFile.available())
    {
      leseZeile();
      ausgabeZeile();
      teileZeile();
      ausgabeWerte();
    }
    // schließe die Datei:
    myFile.close();
    Serial.println(F(" geschlossen!"));
    while (1);
  }
  else
  {
    // Wenn die Datei nicht geöffnet wurde, drucke einen Fehler :
    Serial.print("Fehler beim öffnen von ");
    Serial.println(filename);
  }
}

void leseZeile()
{
  char myChar = '\0';
  static byte bufferPosition = 0;
  if (bufferPosition == 0) memset(zeilenBuffer, '\0', sizeof(zeilenBuffer));
  while (myFile.available() && myChar != '\n')
  {
    myChar = myFile.read();
    if (isPrintable(myChar))
    {
      zeilenBuffer[bufferPosition] = myChar;
      bufferPosition++;
    }
  }
  // Hier ist ZeilenEnde / DateiEnde
  bufferPosition = 0;
}
void ausgabeZeile()
{
  Serial.print(F("eingelsene Zeile ist: "));
  Serial.println(zeilenBuffer);
}
void teileZeile()
{
  // zeilenbuffer in auswerteBuffer umschreiben
  memset(auswerteBuffer, '\0', sizeof(auswerteBuffer) / sizeof(auswerteBuffer[0]));
  strcpy (auswerteBuffer[0], strtok(zeilenBuffer, ";"));
  strcpy (auswerteBuffer[1], strtok(NULL, ";"));
  strcpy (auswerteBuffer[2], strtok(NULL, ";"));
  strcpy (auswerteBuffer[3], strtok(NULL, ";"));
  strcpy (auswerteBuffer[4], strtok(NULL, ";"));
  strcpy (auswerteBuffer[5], strtok(NULL, ";"));
  Serial.println(F("Puffer geteilt!"));
}
void ausgabeWerte()
{
  for (byte b = 0; b < sizeof(auswerteBuffer) / sizeof(auswerteBuffer[0]); b++)
  {
    Serial.print(F("Wert "));
    Serial.print(b);
    Serial.print(F(" ist: "));
    Serial.println(auswerteBuffer[b]);
  }
}

Beachte Zeile 43#
Dateinamen anpassen und Pin.

Einfacher ist es nicht unbedingt, aber es ist wesentlich flexibler, da man so weniger vom genauen Datenformat abh√§ngig ist. Eine Funktion die zeilenweise einliest kann man immer wieder f√ľr alles m√∂gliche verwenden, und man muss nur die Auswertung etwas anpassen.

2 Likes

Mein reden... :wink:
Ich habs schon nach Funktionen aufgeteilt.
Ja, ich mach kein atoi / atof aber das ist Absicht...

Die Zahlen sind, wenn ich es richtig verstehe, Anweisungen f√ľr eine Maschine, die zeilenweise abgearbeitet werden sollen. Also braucht es kein Feld.

Da ich keine SD-Karte zur Hand habe, nutze ich SPIFFS, sollte keinen Unterschied machen. Getestet mit ESP32:

#include "SPIFFS.h"

int var1;
int var2;
int var3;
int var4;
int var5;
float var6;

void setup() {
  Serial.begin(115200);
  
  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  File file = SPIFFS.open("/Mappe1.csv");
  if (!file) {
    Serial.println("Failed to open file for reading");
    while (1);
  }

  Serial.println("\nStart");

  file = SPIFFS.open("/Mappe1.csv");
  while (file.available()) {
    String tmp = file.readStringUntil('\n');
    Serial.println(tmp);
    char zeile[50];
    snprintf( zeile, sizeof(zeile), "%s", tmp.c_str() );
    var1 = atoi(strtok(zeile, ";"));
    var2 = atoi(strtok(NULL, ";"));
    var3 = atoi(strtok(NULL, ";"));
    var4 = atoi(strtok(NULL, ";"));
    var5 = atoi(strtok(NULL, ";"));
    tmp = strtok(NULL, ";");
    tmp.replace(",", ".");
    var6 = atof(tmp.c_str());

    Serial.printf( " Werte var1=%d; var2=%d; var3=%d; var4=%d; var5=%d; var6=%f; \n", var1, var2, var3, var4, var5, var6 );
  }
  file.close();
}

void loop() {}

var6 ist float, wobei ein Komma vorher in einen Punkt gewandelt werden muß. Da merkt man die anglo-amerikanische Herkunft oder Dominanz.

Ich kömme spät, hoffentlich nicht zu spät :roll_eyes:

Was ist schon spät.
Erstmal muss er ja das char in irgendwas aufgelöst bekommen..
.. und daraus wieder irgendwas machen ..
Na denne.

Vielen Dank euch allen. Ich gehe morgen wieder dran. Heute war Spieleabend und ich habe wenigstens da zweimal gewonnen. :star_struck: Dann werde ich ja wohl morgen auch hier was zustande bringen.

Gute Nacht, w√ľnsche gut zu schlafen.
Franz

Hallo,
@Franz54 braucht das noch ein bisschen anders.

Du benötigst mehrere Functionen die erste öffnet nur die Datei zum lesen. Die bleibt dann offen.
eine zweite function ließt dann immer nur eine Zeile ein und macht Zahlen draus. Der Lesezeiger bleibt dann da stehen, beim nächsten Aufruf wird die nexte Zeile automatisch gelesen. Das machst Du so lange bis Du am Ende angekommen bist oder du ende machst. Dann die dritte function zum schliessen.

also 1 öfnen, 2 eine zeile lesen 3 schliessen.
wenn Du immer schliesst und wieder √∂ffnest musst du einen Zeiger mitf√ľhren wo du bist und dann dummy Zeile lesen. Zeiger auf bytePos setzten gibts auch noch aber da mussten alle Zeilen gleich lang sein, oder nach dem lesen die aktuelle position auslesen und dann wieder setzen wird auch noch gehen.
Heinz

Moins,

Er braucht erstmal einen Einstieg!
Schau Dir seinen Versuch an.

Mache ich.

Jedes Einzelne davon mache ich. Im √úbrigen das Letzte nicht weil √ľberfl√ľssig.

Genau deshalb ist das genau auf diese Funktionen reduziert.
Und in Zeile 43 f√ľr immer beendet.
jeder kann damit nachvollziehen was da passiert.

Und ich habe darauf hingewiesen, das ich atoi/atof nicht benutze um zu zeigen, wie die Auslösung Datei - Zeile - Wert geht.

00:05:33.782 -> Initialisierung abgeschlossen .
00:05:33.815 -> x2.csv geöffnet!
00:05:33.848 -> eingelsene Zeile ist: 3;1;2;1000;200;0,5
00:05:33.881 -> Puffer geteilt!
00:05:33.881 -> Wert 0 ist: 3
00:05:33.914 -> Wert 1 ist: 1
00:05:33.914 -> Wert 2 ist: 2
00:05:33.947 -> Wert 3 ist: 1000
00:05:33.947 -> Wert 4 ist: 200
00:05:33.980 -> Wert 5 ist: 0,5
00:05:33.980 -> eingelsene Zeile ist: 1;1;1;200;30800;77
00:05:34.046 -> Puffer geteilt!
00:05:34.046 -> Wert 0 ist: 1
00:05:34.079 -> Wert 1 ist: 1
00:05:34.079 -> Wert 2 ist: 1
00:05:34.113 -> Wert 3 ist: 200
00:05:34.113 -> Wert 4 ist: 30800
00:05:34.146 -> Wert 5 ist: 77
00:05:34.146 -> eingelsene Zeile ist: 2;1;1;700;10800;27
00:05:34.212 -> Puffer geteilt!
00:05:34.212 -> Wert 0 ist: 2
00:05:34.245 -> Wert 1 ist: 1
00:05:34.245 -> Wert 2 ist: 1
00:05:34.278 -> Wert 3 ist: 700
00:05:34.278 -> Wert 4 ist: 10800
00:05:34.311 -> Wert 5 ist: 27
00:05:34.311 -> eingelsene Zeile ist: 3;1;2;1000;200;0,5
00:05:34.378 -> Puffer geteilt!
00:05:34.378 -> Wert 0 ist: 3
00:05:34.411 -> Wert 1 ist: 1
00:05:34.411 -> Wert 2 ist: 2
00:05:34.444 -> Wert 3 ist: 1000
00:05:34.444 -> Wert 4 ist: 200
00:05:34.531 -> Wert 5 ist: 0,5
00:05:34.531 -> eingelsene Zeile ist: 1;1;1;200;30800;77
00:05:34.531 -> Puffer geteilt!
00:05:34.531 -> Wert 0 ist: 1
00:05:34.551 -> Wert 1 ist: 1
00:05:34.578 -> Wert 2 ist: 1
00:05:34.578 -> Wert 3 ist: 200
00:05:34.610 -> Wert 4 ist: 30800
00:05:34.610 -> Wert 5 ist: 77
00:05:34.643 -> eingelsene Zeile ist: 2;1;1;700;10800;27
00:05:34.676 -> Puffer geteilt!
00:05:34.709 -> Wert 0 ist: 2
00:05:34.709 -> Wert 1 ist: 1
00:05:34.743 -> Wert 2 ist: 1
00:05:34.743 -> Wert 3 ist: 700
00:05:34.777 -> Wert 4 ist: 10800
00:05:34.777 -> Wert 5 ist: 27
00:05:34.810 -> eingelsene Zeile ist: 3;1;2;1000;200;0,5
00:05:34.843 -> Puffer geteilt!
00:05:34.876 -> Wert 0 ist: 3
00:05:34.876 -> Wert 1 ist: 1
00:05:34.909 -> Wert 2 ist: 2
00:05:34.909 -> Wert 3 ist: 1000
00:05:34.943 -> Wert 4 ist: 200
00:05:34.943 -> Wert 5 ist: 0,5
00:05:34.976 -> eingelsene Zeile ist: 1;1;1;200;30800;77
00:05:35.009 -> Puffer geteilt!
00:05:35.042 -> Wert 0 ist: 1
00:05:35.042 -> Wert 1 ist: 1
00:05:35.075 -> Wert 2 ist: 1
00:05:35.075 -> Wert 3 ist: 200
00:05:35.108 -> Wert 4 ist: 30800
00:05:35.108 -> Wert 5 ist: 77
00:05:35.141 -> eingelsene Zeile ist: 2;1;1;700;10800;27
00:05:35.175 -> Puffer geteilt!
00:05:35.208 -> Wert 0 ist: 2
00:05:35.208 -> Wert 1 ist: 1
00:05:35.208 -> Wert 2 ist: 1
00:05:35.241 -> Wert 3 ist: 700
00:05:35.241 -> Wert 4 ist: 10800
00:05:35.274 -> Wert 5 ist: 27
00:05:35.307 -> eingelsene Zeile ist: 3;1;2;1000;200;0,5
00:05:35.340 -> Puffer geteilt!
00:05:35.340 -> Wert 0 ist: 3
00:05:35.373 -> Wert 1 ist: 1
00:05:35.373 -> Wert 2 ist: 2
00:05:35.407 -> Wert 3 ist: 1000
00:05:35.407 -> Wert 4 ist: 200
00:05:35.440 -> Wert 5 ist: 0,5
00:05:35.473 -> eingelsene Zeile ist: 1;1;1;200;30800;77
00:05:35.506 -> Puffer geteilt!
00:05:35.506 -> Wert 0 ist: 1
00:05:35.539 -> Wert 1 ist: 1
00:05:35.539 -> Wert 2 ist: 1
00:05:35.572 -> Wert 3 ist: 200
00:05:35.572 -> Wert 4 ist: 30800
00:05:35.606 -> Wert 5 ist: 77
00:05:35.606 -> eingelsene Zeile ist: 2;1;1;700;10800;27
00:05:35.672 -> Puffer geteilt!
00:05:35.672 -> Wert 0 ist: 2
00:05:35.705 -> Wert 1 ist: 1
00:05:35.705 -> Wert 2 ist: 1
00:05:35.738 -> Wert 3 ist: 700
00:05:35.738 -> Wert 4 ist: 10800
00:05:35.771 -> Wert 5 ist: 27
00:05:35.771 -> eingelsene Zeile ist: 3;1;1;1000;20000;50
00:05:35.838 -> Puffer geteilt!
00:05:35.838 -> Wert 0 ist: 3
00:05:35.871 -> Wert 1 ist: 1
00:05:35.871 -> Wert 2 ist: 1
00:05:35.904 -> Wert 3 ist: 1000
00:05:35.904 -> Wert 4 ist: 20000
00:05:35.937 -> Wert 5 ist: 50
00:05:35.937 ->  geschlossen!

Aber ja, ich weiss...

Sorry ich hab mal wieder den falschen Button gedr√ľckt , ich habs gesehen bei Dir ist es so wie angedacht.
mir ist es nur bei dem Beispiel von @agmue direkt ins Auge gesprungen

Gruß Heinz