Pages: [1]   Go Down
Author Topic: Die SD-Karte mal wieder...  (Read 318 times)
0 Members and 1 Guest are viewing this topic.
Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallochen.
Sitze mal wieder ein bisschen am Monstertruck und......kämpfe.

Ich möchte in einem bestimmten Verzeichnis der SD-Karte sämtliche enthaltenen Dateien der Reihe nach öffnen, die erste Zeile einlesen und als Klartext ausgeben.
Wie ich das einlesen mache, hab ich schon mal erarbeitet- der Teil klappt.
Es klappt auch, die Dateinamen im Verzeichnis einzulesen aber ich kriegs nicht gebacken, die jeweilige Datei gleichzeitig zu öffnen.

Code:
Serial.println(entry.name());//bis hierher klappts hier wird der Dateiname richtig ausgegeben aber
     File routenDatei=SD.open(entry.name());//klappt nicht
     Serial.print("geoeffnet: ");
     Serial.println(routenDatei); // das wird zwar ausgegeben, enthält aber nur ne "0);

Was hab ich da wieder vermurkst?
Basis ist die Standard-SD-Lib, und das abgewandelte Beispiel 'listfiles'.
Logged

------------
Grüssle, Sly

Offline Offline
Faraday Member
**
Karma: 128
Posts: 4128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Kann es sein dass open() den kompletten Pfad möchte und nicht nur den Dateinamen?

http://arduino.cc/en/Reference/SDopen
Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nein, das ist das Problem nicht denn:

Code:
Serial.println(entry.name());

gibt vollkommen richtig sowas aus:
ROUTE2.GPS
das ist der korrekte Dateiname- und genau den will ich benutzen, um diese Datei auch zu öffnen (um eben jene erste Zeile zu lesen).

Logged

------------
Grüssle, Sly

Offline Offline
Faraday Member
**
Karma: 128
Posts: 4128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich habe die normale SD Klasse noch mit Verzeichnissen genutzt, aber so wie sich das liest reicht das eventuell nicht wenn die Datei in einem Verzeichnis steht.

Um Dateien der Reihe nach zu öffnen gibt es wie in dem Beispiel steht auch openNextFile()
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 170
Posts: 3205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
Serial.println(entry.name());

gibt vollkommen richtig sowas aus:
ROUTE2.GPS
das ist der korrekte Dateiname- und genau den will ich benutzen, um diese Datei auch zu öffnen (um eben jene erste Zeile zu lesen).

Du müsstest aber trotzdem die Verzeichnisstruktur und ggf. vorhandene Unterverzeichnisse beachten.

Ist es denn ein Dateisystem mit Unterverzeichnissen?
Oder liegen alle Dateien im Rootverzeichnis und es gibt gar keine Unterverzeichnisse?
Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ja-und nein.
Es gibt ein eigenes Unterverzeichnis für die Routen-Dateien, klar.
Das wird aber bereits vorher eingestellt- denn die Dateinamen werden ja völlig korrekt gelesen und angezeigt.

für den Moment habe ich das Problem mehr oder weniger umschifft, indem ichs einfach so mache:

Code:
void printDirectory(File dir, int numTabs) // ********** Routendateien zählen ********
{
     while(true)
   { 
     File entry =  dir.openNextFile();
     if (! entry)
     {
       dir.rewindDirectory();
       break;
     }
     for (uint8_t i=0; i<numTabs; i++)
     {
       Serial.print('\t');
     }
     entry.readBytesUntil('#',name,15); //Ersten String lesen, der den Namen enthält
         Serial.print("Routenname: "); //String ausgeben
         Serial.println(name);
        entry.close();
   }
}

Funktioniert einwandfrei- es wird da sehr schön ein Teil der ersten Textzeile in der jeweiligen Datei ausgegeben.
Wie man sieht: auch hier kein Unterverzeichnis (da das schon in der setup() ausgewählt wird).
Ob ich das _so_ lassen kann, weiss ich noch nicht, da hier (in dem Beispiel) nur die jeweilige Datei erstmal auf dem display ausgegeben werden soll (drum auch die Verrenkung mit der Inhaltszeile, da die Namen weniger Zeichen hergeben), und man hier dann auswählt, welche Route(ndatei) nachher genommen werden soll.
Logged

------------
Grüssle, Sly

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So- das Problem hat mich eingeholt.
Hatte ich bereits befürchtet...vermutlich blick ich mal wieder irgendwas mit Variablen nicht.

Es geht darum: ich kann durch die Dateien (alle im selben Ordner) nach belieben brausen- das funktioniert.

Code:
void printRoutenInfo(File dir) // ********** Routeninfo lesen und ausgeben ********
{
     if(routeSelect==1)
   { 
    File routenDatei =  dir.openNextFile();
     if (! routenDatei) //wenn am Ende angekommen
     {
       dir.rewindDirectory();//zurück zum Anfang
      }
     
     routenDatei.readBytesUntil('#',name,15); //Ersten String lesen, der den Namen enthält
         lcd.setCursor(0,1);
         lcd.print(name);//Routenname ausgeben
         routenDatei.close();
         delay(500);
   }
}

Das Ganze wird in ner zeitgesteuertem Schleife über den Joystick gemacht: wird der Stick eine gewisse Zeitlang nicht bewegt, dann wird abgebrochen, wird er bewegt, wird die obige Routine erneut aufgerufen und somit die nächste Datei geöffnet.
Das klappt einwandfrei bis dahin.
Nun aber brauche ich eine Möglichkeit, den Namen der aktuellen Datei in einer Variablen zu speichern.
Also: nicht den Routennamen (der IN der Datei steht), sondern nur den Dateinamen, da ich die ausgewähte Datei ja später weiter verarbeiten muss.
Wenn ich nun folgendes mache:
Code:
lcd.print('routenDatei');
Wird, anstelle des Dateinamens: 25691 ausgegeben.

Code:
lcd.print(routenDatei);
das ergibt einfach nur ne 0...

Jemand eine Idee?
Logged

------------
Grüssle, Sly

Germany S-H
Offline Offline
Faraday Member
**
Karma: 170
Posts: 3205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn ich nun folgendes mache:
Code:
lcd.print('routenDatei');
Wird, anstelle des Dateinamens: 25691 ausgegeben.

Wenn Du einen String ausgeben möchtest:
String-Konstanten stehen immer noch zwischen DOPPELTEN HOCHKOMMAS.
Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Weiss ich doch, jurs...aber ich will nicht:

Code:
lcd.print("routenDatei");
, dann nämlich stünde routenDatei aufm Display, ich brauche den INHALT der (wasauchimmerfüreiner) Variabe routenDatei.
Das Problem scheint daher zu rühren, dass ich in diesem Moment die Datei File routenDatei() bereits wieder geschlossen habe- das muss sein, aber ich muss eben diesen Namen irgendwie speichern...
Logged

------------
Grüssle, Sly

Offline Offline
Faraday Member
**
Karma: 128
Posts: 4128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
lcd.print('routenDatei');
Das ist natürlich Schwachsinn hoch zehn. Ein char steht in einfachen Anführungszeichen. Und String in doppelten. Das ist nichts anderes als 'r'.

Code:
lcd.print(routenDatei);
routenDatei ist ein File Objekt. Ich weiß nicht wieso die Print Klasse das schluckt, aber sie kann wie zu erwarten nicht damit umgehen.


Den Dateinamen bekommst du hiermit:
Code:
lcd.print(routenDatei.name());

Steht auf der Arduino Referenz Seite nicht dabei. Da ist die Doku dann wieder mal unvollständig.

Siehe File.cpp:
Code:
// returns a pointer to the file name
char *File::name(void) {
  return _name;
}
Steht auch in dem listfiles Beispiel so drin.


EDIT:
Wenn du den Namen nachher noch brauchst musst du ihn halt mit strcpy() in ein Array der Größe 13 kopieren

EDIT2:
Mir ist jetzt klar wieso das kompiliert:
Code:
lcd.print(routenDatei);

Das ist ein sehr schönes Konstrukt um Objekte als bool zu evaluieren:
Code:
File::operator bool() {
  if (_file)
    return  _file->isOpen();
  return false;
}
Und dann wird 0 gedruckt, weil false zurückkommt, da die Datei geschlossen wurde smiley

So wird das auch bei Ethernet gemacht. Weshalb man da so Dinge wie if(client) machen kann um zu testen ob eine Verbindung aktiv ist.
« Last Edit: September 04, 2014, 03:49:47 pm by Serenifly » Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

DANKE.
Genau das wars...
Auch den Tipp mit dem Speichern kann ich evtl. noch sehr gut brauchen...
Logged

------------
Grüssle, Sly

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Soweit läuft es...

Nun aber ne neue Nuss:

Ich habe ein Verzeichnis, dessen Name feststeht.
Und ich habe eine Datei, die verschieden heissen kann.
Der Name der Datei ist in ner Variable dateiName gespeichert.

Nun müsste ich sowas haben wie:

Code:
File myFile = SD.open("verzeichnis"+dateiName);// Datei liegt im verzeichnis:/Routen
So funktionierts natürlich nicht.

Praktisch müssen "verzeichnis" und dateiName aneinander gehängt werden.

Wie geht man das an?

Logged

------------
Grüssle, Sly

Offline Offline
Faraday Member
**
Karma: 128
Posts: 4128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Entweder du verwendest die vermurkste String Klasse und castest das auf String

Oder du verwendest strcat():
http://www.cplusplus.com/reference/cstring/strcat/

Code:
char path[25] = "Routen/";
char filename[] = "filename.txt";
strcat(path, filename);
Dabei darauf achten dass das Array groß genug ist!

Sicherer ist deshalb:
Code:
char path[25] = "Routen/";
char filename[] = "filename.txt";
strlcat(path, filename, sizeof(path));
strlcat() garantiert anders als strncat() dass der String korrekt terminiert ist:
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#ga63e609bfa0d354dcd7e35b297c2e6fdd

Allgemein zu String Manipulationen in C:
http://openbook.galileocomputing.de/c_von_a_bis_z/011_c_arrays_013.htm#mj607c824f6d89b1e3f8edb08abdc187d4
« Last Edit: September 07, 2014, 05:54:56 am by Serenifly » Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Soweit funktioniert alles vom feinsten.
Aber natürlich-gibt es _noch_ ein Problem.

Ablauf ist der:
Ich kann per Joystick durch die Dateien (die sich im Verzeichnis /routen befinden) scrollen.
Das geht nur vorwärts, indem ich
Code:
routenDatei =  dir.openNextFile(); //nächste Datei öffnen
benutze.
Das klappt auch ganz problemlos nur ist es ja denkbar, dass ich dabei die Datei, die ich wollte, überblättere, somit muss das Ganze als Schleife laufen.
Daher hab ich das Ende des Verzeichnisses so abgefangen:
Code:
if (! routenDatei) //wenn am Ende angekommen
     {
       dir.rewindDirectory();//zurück zum Anfang
       routenDatei=dir.openNextFile(); // und direkt die erste Datei öffnen
      }
Das aber funktioniert-nicht.  smiley-kitty
Zwar wird hier eine Datei geöffnet, aber irgendwie Mist gelesen.
Lasse ich die zweite Zeile weg, (so hatte ich es bisher), dann wird zwar das Verzeichnis, aber keine Datei gelesen-und auch da kommt natürlich Murks raus.
Hier mal der entsprechende Code im Ganzen:
Code:
void printRoutenInfo(File dir) // ********** Routeninfo lesen und ausgeben ********
{
     if(routeSelect==1) // der Stick wurde bewegt
   { 
     routenDatei =  dir.openNextFile(); //nächste Datei öffnen
     if (! routenDatei) //wenn am Ende angekommen
     {
       dir.rewindDirectory();//zurück zum Anfang
      }
     
     routenDatei.readBytesUntil('#',name,15); //Ersten String lesen, der den Namen enthält
         lcd.setCursor(0,1);
         lcd.print(name);//Routenname ausgeben
         routenDatei.close();
         delay(200);
   }
    strcpy(dateiName, routenDatei.name());// ausgewählte Datei speichern
   
 }

Ich muss diesen Wechsel (vom Ende des Verzeichnisses zum Anfang) irgendwie so abfangen, dass entweder die letzte, oder aber wieder die erste Datei sofort geöffnet wird. Jemand eine Idee dazu?
Logged

------------
Grüssle, Sly

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 821
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sodele.
Das Problem ist gelöst.
Wo lag der Fehler? Wie meistens: nen halben Meter vorm Bildschirm.
Nein, ihr könnt ihn in den Programmschnipseln da nicht finden, denn der ist nicht dort (allenfalls ein winziger Hinweis auf den möglichen Fehler).
Also was war es?
Die Routendatei selbst!

Das lesen der Routen funktioniert nämlich so:
zuerst wird der "Header" gelesen, mittels
 
Code:
routenDatei.readBytesUntil('#',name,15); //Ersten String lesen, der den Namen enthält
Im Klartext bedeutet das, dass dieser Header nix anderes als ein String ist, an dem ich den Namen der Route erkenne.
Später werden dann die Wegpunkte einzeln eingelesen, schön nummeriert, und zwar so:
Code:
wegPunkt = routenDatei.parseInt(); //WegPunkt-Nr. zuerst (Zeilenanfang)
          long lat = routenDatei.parseInt();// als zweites kommt lat
          long lon = routenDatei.parseInt();// dann lon
          sollBreite=lat;
          sollLaenge=lon;
          if(wegPunkt==wegPunktAktuell)
Das Ganze jeweils so lange, bis aus der Datei nichts mehr kommt.
Wie man sieht, gibts jeweils drei Zahlen: Wegpunktnummer, Länge und Breite.
ABER es wird NUR einfach nach Zahlen "gesucht".

Wenn _jetzt_ ein besonders cleverer Programmieranfänger in den Dateiheader als Routenname beispielsweise schreibt:
"ParkplatzRunde1" dann---genau. Wird die 1 schon  als Zahl genommen, alles verschiebt sich um eine Stelle und es kommt unglaublicher Murks raus. smiley-roll
Keine Ahnung, woher ich die plötzliche Eingebung hatte, mir die Routendateien noch mal genauer anzusehen aber sie kam, ich tat es und da ging das Licht auf.  smiley-eek

Langer Rede kurzer Sinn: der Routenparser läuft nun fehlerfrei (bis auf eventuelle Bugs, die ich noch nicht bemerkt habe).


Logged

------------
Grüssle, Sly

Pages: [1]   Go Up
Jump to: