SD-Karte auslesen und Array aus Inhalt erstellen

Hallo zusammen,

ich benötige eure hilfe bei meinen Problem(en).

1. Problem
Ich möchte gerne von einer SD Karte die in einem Textfile abgespeicherten Werte in einem Array speichern.
In diesem Textfile ist pro Zeile eine Zeichenkette mit maximal 5 Werten gespeichert:
Soll so aussehen: werte.txt
v.1.a
v.2.a
v.3.a

Der Array hierzu soll dann wie folgt aussehen:
dateiInhalt("v.1.a";"v.2.a";"v.3.a")

2. Problem
Nun möchte ich gerne wissen wieviele Elemente dieser Array hat, damit ich diese mittels eine Schleife wiedergeben kann.

Dieses soll alles im void setup(){} Teil geschehen.

Ich habe danach schon viel danach gegoogelt, aber eine richtig anständige, kurze und unkomplizerte Lösung
hab ich leider nicht gefunden.

Gruß
Thyrie

Je nachdem, wie die Datei auf die SD Karte gekommen ist, findest du zusätzlich zum Neue-Zeile-Zeichen '\n' oder 0x0A auch noch ein '\r' oder 0x0D.

Falls das 0x0D vorkommt, einfach ingnorieren,
bei 0x0A (oder Datei-Ende) den bisherigen Text in dein Array speichern und den Zeilenzähler erhöhen,
alle anderen Zeichen erstmal merken.
Fertig.

Die wirklichen Fragen hast du nicht gestellt:

  • Ist jede Zeile gleich lang ( 5 Buchstaben ) ? Wenn nein, mit was musst du rechnen ?
  • Wieviele Zeilen sind möglich ? Kann es sein, dass dein RAM knapp wird?

( Ein Hinweis: selbst wenn man bedenkt, dass du auch eine SD Library verwendest, sollte wohl beim UNO Platz für 10*10 Zeichen sein. Bau dir am einfachsten so ein Array fest global auf, und fülle es gleich beim Einlesen der Datei. )

"Eine richtig anständige, kurze und unkomplizerte Lösung" für genau diese Aufgabe wirst du nicht leicht finden, und jurs hat wohl auch keine Langeweile.

  • Probleme beim Umsetzen des obigen Hinweis kriegst du sicher geholfen.
  • Wenn das 10*10 Beispiel nicht reicht, bau es trotzdem erstmal, dann sehen wir weiter.

Viel Spass

Als erstes sollte dir klar sein, dass in C ein Array aus Strings ein zwei-dimensionales Array aus char ist.

Diese Aufgabe ist nicht trivial, da in C die Größe von statischen Arrays zur Compile-Zeit feststehen muss. Dadurch bekommt man wie gesagt Probleme da man abschätzen muss wie viel Speicher man maximal braucht. Wie groß das Array sein muss, musst du wissen. Wir können nicht sagen wie viele Zeilen du maximal hast.
Vom Speicher her ist es vielleicht nicht so schlimm. Man hat nur 6 Bytes pro Zeile (5 Zeichen + Terminator). Daher hätten 20 Zeilen auch nur 120 Bytes. Das hält sich noch in Grenzen.

(Man kann dynamischen Speicher mit malloc() verwenden. Damit kann man die Größe erst zur Laufzeit festlegen, aber das wird nochmal komplizierter. Besser erst mal statisch mit einer kleinen Anzahl von Zeilen probieren. Dann kann man es immer noch anpassen wenn das nichts ist.)

Eine Alternative zur normalen SD Lib ist hier SdFat:
https://code.google.com/p/sdfatlib/
Die hat mit fgets() in der SdFile Klasse eine Funktion um gleich eine ganze Zeile auf einmal auszulesen und in einen Puffer zu schreiben.

Hallo,

vielen dank für eure Hinweise, dann werde ich mich mal ran setzen, damit ich das hin bekomme.
Wenn ich so weit bin, werde ich das hier ins Forum stellen, damit evtl auch für andere die das selbe
Problem haben nachlesen können.

michael_x:
Die wirklichen Fragen hast du nicht gestellt:

  • Ist jede Zeile gleich lang ( 5 Buchstaben ) ? Wenn nein, mit was musst du rechnen ?
  • Wieviele Zeilen sind möglich ? Kann es sein, dass dein RAM knapp wird?

Dazu ist zu sagen, dass die Zeichen pro Zeile zwischen einem und fünf Zeichen variieren.
Wieviele Zeilen es sind kann ich nicht sagen, da dieses ja je nach gebrauch auch variiert.
Sollten aber nicht mehr als 50 werden (vorab).

Ich werde mal mit einem mehrdimensionalen Array mit folgender Größe anfangen:
char prgAblauf[50][7];
Denkt ihr dieser ist für einen Arduino Mega zu groß?

Gruß
Thyrie

Auf dem Mega ist das völlig ok. Der hat 8kB RAM. Auf dem UNO eventuell auch, je nachdem was sonst noch läuft. Wenn du maximal 5 Zeichen hast, brauchst du aber nur 6 für die zweite Dimension. Nicht 7.

Ob die Zeilenlänge variiert ist für die Funktionalität egal.

Hiermit kannst du den freien Speicher berechnen:

int getFreeRAM() 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

So, hier das Programm

#include <SD.h>
File myFile;
int prgZeilen = 0;
int durchl =0;
char prgAblauf[50][7];
int i;
int j;

void setup() {
  Serial.begin(9600);
  if (!SD.begin(10)) {
    Serial.println("Initialisierung fehlgeschlagen!");
    return;
  }
  myFile = SD.open("prg.txt");
  if (myFile) {
    while (myFile.available()) {
      char ch = myFile.read();
      byte tmp = ch;
      if (tmp == 13){ // 13 = CR (neue Zeile) '\r'
        prgZeilen = prgZeilen + 1;
        durchl = -1;
      }
      else if(tmp == 46){
        //nichts machen 46 = . (Punkte ignorieren)
      }
      else if(tmp == 32){
        //nichts machen 32 = Leerzeichen (Leerzeichen ignorieren) 
      }
      else{
        prgAblauf[prgZeilen][durchl] = ch; 
        durchl = durchl + 1;
      }
    }
  }
}

void loop() {
  Serial.print("Es sind: ");
  Serial.print(prgZeilen);
  Serial.println(" Programmzeilen auf der Speicherkarte");
  for(i=0;i<=prgZeilen;i++){
    Serial.println(prgAblauf[i]);
    if(prgAblauf[i][0] == 'S') {

    } /// usw.
  }
  while(1){
    //Programm "stoppen"
  }
}

Funktioniert wunderbar, jedoch wenn ich wie von dir beschrieben den
Array in der zweiten Dimension auf 6 stelle, so bekomme ich wirre Werte,
vermutlich wegen der "unsichtbaren" Zeichen welche ja im Textfile
vorhanden sind.

Bezüglich des verfügbaren Speichers muss ich gleich noch
testen, da mein Testaufbau über einen Arduino Nano v.3 läuft.

Die Linefeeds solltest du ja auch nicht da rein schreiben. :slight_smile:

Vielleicht mal so am Ende:

else if ( tmp != '\n' )
{
}

ch in tmp abzuspeichern ist übrigens unnötig. Ein byte ist lediglich ein unsigned char

Was auch nichts schadet ist zu überprüfen ob prgZeilen < 50 ist, da dich C munter über Array Grenzen schreiben lässt

Hallo,

vielen Danke für eure tipps, ich denke so werde ich schon an mein Ziel kommen.

Gruß

Du vergisst, am Ende der Zeile eine Text-Ende-Kennnung '\0' einzutragen.
Das geht hier zwar gut, weil dein Array mit 0 vorbelegt ist, und nur einmal nach Reset beschrieben wird, aber schöner wäre es.
( Ob durch1 etwa zu groß wird, prüfst du auch nicht. )

Das erklärt übrigens deine Beobachtung

jedoch wenn ich wie von dir beschrieben den Array in der zweiten Dimension auf 6 stelle, so bekomme ich wirre Werte,

'\r' findet man übrigens nur in Windows-Dateien, '\n' ist die eigentliche Neue-Zeile Kennung in einer Text-Datei.