Go Down

Topic: Grundsatzfragen SD lesen und Werte zuordnen. (Read 3780 times) previous topic - next topic

combie

Quote
Ich begreife am schnellsten wenn ich eine funktionierende Lösung sehe und damit rumspielen kann.
Am schnellsten vielleicht.


Meine Ansicht, aus eigener schmerzhafter Erfahrung, denn ich habe auch mal so argumentiert:

Aber die Tiefe bleibt einem dann verborgen.
Der Grund, warum es so getan wird, wie es getan wird, bleibt im Dunkel.
Darum lernt man das dann auch so schnell.

Da man das Verborgene, den Grund, nicht erfahren hat, ist es dann leider quasi unmöglich, das Verfahren, auf andere Problemstellungen zu transferieren.


Schade:
Habe gerade meine Platte nach einer (halb)fertigen Datenbank für kleine µC durchsucht. Denn hatte mal sowas gebastelt. Scheint leider futsch zu sein.

Im Grunde waren das nur ein paar Methoden, in einer Template Klasse, welche ein FileHandle bekommen haben, und damit beliebige Strukturen lesen und schreiben konnten.

Schade...
Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

ElEspanol

Wenn das eh nur maschinenlesbar ist, warum dann nicht ins Eeprom?

MaHa76

#17
Dec 31, 2017, 01:54 pm Last Edit: Dec 31, 2017, 02:18 pm by MaHa76
Man soll auch Datensätze am PC anlegen oder bearbeiten können- dafür bietet sich die SD- Karte an...

Ja und das Einlesen mache ich derzeit händisch, sehr rustikal, Schritt für Schritt, basierend auf dem Sketch von Jörg. Ich habe aber für jeden Weckeintrag eine eigene Datei. Was mich da aktuell als einziges stört, ist der Umstand, dass ich den Inhalt der Datei nicht löschen kann, um neue Daten anzulegen- bzw. die alten Daten einfach überschreiben kann...

ElEspanol

Dann ist es eben etwas mehr Aufwand, das umzustricken. Die Einlese und Abspeicherfunktion wird etwas komplexer.

Zeig doch mal, wie du deine Daten nun strukturiert hast und den Inhalt eines Datenfiles

MaHa76

Soll ich dafür mal den kompletten Sketch hochladen? Oder reicht es ein paar Zeilen als Ausschnitt zu zeigen?

ElEspanol

Zeilen als Ausschnitt in Code tags, ganzen Sketch als Anhang

MaHa76

Also da der komplette Sketch recht umfangreich ist, hier mal ein Auszug für je einen Weckeintrag.

So sind die Positionen im array besetzt: (mit Ausnahme der Uhrzeit haben alle Werte "1" oder "0" für aktiv/nicht aktiv)

Code: [Select]

// Stunde, Minute, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, Sonntag, Feiertag, Brückentag, aktiviert, Wecker gesetzt


So wird er geschrieben: (WeckerEingabeName sind die Zeichen die von der qwertz-Tastatur eingelesen werden)
Code: [Select]
if ( Wecker1[0] == 0 )
     { Wecker1[11] = 1;
       Wecker1Name = WeckerEingabeName[0] + WeckerEingabeName[1] + WeckerEingabeName[2] + WeckerEingabeName[3] + WeckerEingabeName[4] + WeckerEingabeName[5] + WeckerEingabeName[6] + WeckerEingabeName[7] + WeckerEingabeName[8] + WeckerEingabeName[9] + WeckerEingabeName[10] + WeckerEingabeName[11] + WeckerEingabeName[12] + WeckerEingabeName[13] + WeckerEingabeName[14] + WeckerEingabeName[15] + WeckerEingabeName[16] + WeckerEingabeName[17] + WeckerEingabeName[18] + WeckerEingabeName[19];  
       WeckerEintrag1 = SD.open("Wecker1.txt", FILE_WRITE);
       if (WeckerEintrag1)
          { if (Wecker1[0] < 10)
               { WeckerEintrag1.print("0");
                 WeckerEintrag1.print(Wecker1[0]); }
            else { WeckerEintrag1.print(Wecker1[0]); }
            WeckerEintrag1.print(",");
             if (Wecker1[1] < 10)
               { WeckerEintrag1.print("0");
                 WeckerEintrag1.print(Wecker1[1]); }
            else { WeckerEintrag1.print(Wecker1[1]); }
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[2]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[3]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[4]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[5]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[6]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[7]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[8]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[9]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[10]);
            WeckerEintrag1.print(",");
            WeckerEintrag1.print(Wecker1[11]);  
            WeckerEintrag1.print(",");
            WeckerEintrag1.println(Wecker1Name);
            WeckerEintrag1.close();
            Kartenstatus = "auf SD gespeichert"; }
            else { Kartenstatus = "Speichern auf SD fehlgeschlagen"; }
       tft.clearScreen(Hintergrund1);BildSchirm6(); BildSchirmWahl = 6; Speichern = 0; }


und so wird gelesen:

Code: [Select]
WeckerEintrag1 = SD.open("Wecker1.txt");
  if ( WeckerEintrag1 )
     { while (WeckerEintrag1.available())            
             { Wecker1Temp = WeckerEintrag1.read();   //Zeichenweise einlesen
               if ( Wecker1Temp != '\n')              //Erkennen von Zeilenumbruch
                  { Weck1Temp += Wecker1Temp; }       //ausgelesene Zeichenfolge in String aufaddieren
               else
                  { Weck1Pos1 = Weck1Temp.substring(0,2);
                    Wecker1[0] = Weck1Pos1.toInt();
                    Weck1Pos2 = Weck1Temp.substring(3,5);
                    Wecker1[1] = Weck1Pos2.toInt();
                    Weck1Pos3 = Weck1Temp.substring(6,7);
                    Wecker1[2] = Weck1Pos3.toInt();
                    Weck1Pos4 = Weck1Temp.substring(8,9);
                    Wecker1[3] = Weck1Pos4.toInt();
                    Weck1Pos5 = Weck1Temp.substring(10,11);
                    Wecker1[4] = Weck1Pos5.toInt();
                    Weck1Pos6 = Weck1Temp.substring(12,13);
                    Wecker1[5] = Weck1Pos6.toInt();
                    Weck1Pos7 = Weck1Temp.substring(14,15);
                    Wecker1[6] = Weck1Pos7.toInt();
                    Weck1Pos8 = Weck1Temp.substring(16,17);
                    Wecker1[7] = Weck1Pos8.toInt();
                    Weck1Pos9 = Weck1Temp.substring(18,19);
                    Wecker1[8] = Weck1Pos9.toInt();
                    Weck1Pos10 = Weck1Temp.substring(20,21);
                    Wecker1[9] = Weck1Pos10.toInt();
                    Weck1Pos11 = Weck1Temp.substring(22,23);
                    Wecker1[10] = Weck1Pos11.toInt();
                    Weck1Pos12 = Weck1Temp.substring(24,25);
                    Wecker1[11] = Weck1Pos12.toInt();  
                    Wecker1Name = Weck1Temp.substring(26,45);
                    }
             }
  WeckerEintrag1.close(); }          


Sicher ist das ganze mehr als umständlich- aber das war jetzt mein erster Versuch und wenn das so Schritt für Schritt läuft kann ich für mich zumindest nachvollziehen was passiert und kann dann auch in 10 Monaten noch dran arbeiten :)

Der Sketch besteht aus mehreren Dateien- für mich ist es übersichtlicher wenn es sich auf mehrere Reiter verteilt....
bitte nicht erschrecken- ich hab das alles recht laienhaft geschrieben und bestimmt einen Haufen unnützen Balast an Board- aber die Funktionen die schon aktiv sind laufen. Es sind mir bisher nur wenige Fehler aufgefallen.

ElEspanol

#22
Dec 31, 2017, 03:24 pm Last Edit: Dec 31, 2017, 03:26 pm by ElEspanol
Schick mal noch die "Wecker1.txt"

wo schreibst du die Dateien auf die SD-Karte?

MaHa76

Anbei die Wecker1.txt ...

Beschrieben wird die im Teensy direkt- ich hab da ein Menü wo ich die Daten eingebe und dann im Sketch die Werte in Variablen speichere und dann auf der SD im gleichen Zug sichere.

ElEspanol

#24
Dec 31, 2017, 05:22 pm Last Edit: Dec 31, 2017, 05:22 pm by ElEspanol
Hab ein bisschen rumexperimentiert. Das ist ideal für ein array aus struct. Nur die dynamische Erstellung des Arrays zur Laufzeit geht nicht so einfach. über einen Workaround mit calloc oder malloc sollte es aber gehen. Leider hört es bei mir da aber langsam auf. Wer von den Profis kann da weiterhelfen?

Ich muss nun auch mal weg.

MaHa76

Heute mache ich auch nicht mehr weiter- sonst gibts Ärger ;)

Ich wünsch mal schon allen einen guten Rutsch!

combie

#26
Dec 31, 2017, 05:38 pm Last Edit: Dec 31, 2017, 09:03 pm by combie
Quote
Das ist ideal für ein array aus struct.
Naja...

Quote
Wer von den Profis kann da weiterhelfen?
Bin kein Profi, aber könnte dir vielleicht einen Ansatz liefern...


Habe ja schon meine Platte durchsucht, aber nicht das fertige gefunden.

Aber ein ungetestetes Fragment, welches ich gerade auch nicht testen kann, da die Hardware nicht bereit steht.


Es besteht aus einer Datenstruktur: "Datensatz.h"

Code: [Select]

#pragma once

struct Datensatz : Printable
{
  bool deleted;
  char vorname[40];
  char nachname[40];
  char telefonnummer[40]; // char wegen "+49 xxxxxx"
  Datensatz():deleted(false)
  {
    *vorname = 0;
    *nachname = 0;
    *telefonnummer = 0;
  }
  virtual size_t printTo(Print& p) const
  {
    size_t len = 0;
    if(deleted)
    {
      len += p.println("Leerer Datensatz");
    }else
    {
      len += p.print("Vorname: ")       +  p.println(vorname) +
             p.print("Nachname: ")      +  p.println(nachname)+
             p.print("Telefonnummer: ") +  p.println(telefonnummer);
    }
    return len;
  }

};

Kann man natürlich beliebig anpassen.


Aus einer Schreib und Lese Einheit: "Datenbank.h"
Code: [Select]

#pragma once

template<typename StructType>
class Datenbank
{
  private:
  bool seekto(File file, size_t num)
  {
    unsigned long pos = 1UL * num * sizeof(StructType);
    return file.seek(pos); // seek error
  }
  
  public:
  size_t count(File file) // anzahl Datensätze in der Datei
  {
    return file.size()/sizeof(StructType);
  }

  bool read(File file, size_t num, StructType &data)
  {
    if(!seekto(file,num)) return false; // seek error
    int error = file.read((uint8_t*)&data,sizeof(StructType));
    return -1 != error; // liefert true bei Erfolg
  }

  bool write(File file, size_t num, const StructType &data) // überschreibt einen vorhandenen Datensatz
  {
    if(!seekto(file,num)) return false; // seek error
    file.write((uint8_t*)&data,sizeof(StructType));
    return true;
  }

  bool append(File file, const StructType &data)
  {
    size_t num = count(file) ;
    return write(file,num,data);  
  }
};



Und ein bisschen drumrum:
Code: [Select]

#include <SPI.h>
#include <SD.h>
#include "Datenbank.h"
#include "Datensatz.h"

const int chipSelect = 4;

using DB = Datenbank<Datensatz>;

Datensatz buffer;
DB db;


void setup()
{
  Serial.begin(9600);
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card failed, or not present");
    for(;;); // halt
  }
  Serial.println(buffer);
}

void loop()
{
   File dataFile = SD.open("telefon.db",FILE_WRITE);
   Serial.println(db.count(dataFile));
   db.append(dataFile,buffer);
   db.read(dataFile,0,buffer);
   dataFile.close();
   delay(2000);

}


Wie gesagt, alles ungetestet, also nur als Anregung gedacht
Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Tommy56

Das ist ideal für ein array aus struct.
Intern im Arduino wäre das eine Möglichkeit, um die Daten nach dem Lesen von SD zu speichern. Dabei könnte man auch evtl. gleich vergangene Termine nicht mit ins Array übernehmen. Also eine Zeile lesen - ist der Termin in der Vergangenheit ? - überspringen, sonst ans Array anhängen.
Am Ende mit realloc() das Array um die übersprungenen Sätze verkleinern.
Da das Ganze ja ein einmaliger Vorgang sein dürfte - Array neu einlesen (vorher Speicher frei geben) dürfte hier eine dynamische Speicherverwaltung auch sinnvoll machbar sein.

Da MaHa76 die Daten ausdrücklich auch am PC erfassen will und dafür wohl kein PC-Programm schreiben will, das ihm die Daten mit gleicher Ausrichtung und Feldlänge in diese Form bringt, ist diese Lösung als SD-Speicherformat für die Datenübergabe wohl eher akademischer Natur.

Den Weg mit den Einzeldateien halte ich auch für nicht so ideal.

Der wohl effektivste Weg über beide Welten dürfte eine csv-Datei sein. Evtl. als Excel- oder Calc-Export auf dem PC, dort könnte man auch die Bereinigung (Löschen alter Termine) z.B. am Jahresende vornehmen.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

agmue

Der wohl effektivste Weg über beide Welten dürfte eine csv-Datei sein. Evtl. als Excel- oder Calc-Export auf dem PC, dort könnte man auch die Bereinigung (Löschen alter Termine) z.B. am Jahresende vornehmen.
Da stimme ich Dir zu, siehe #1 am Ende.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

MaHa76

Gibt es wirklich keine Möglichkeit, dass ich Zeilen im Sketch lösche?

Ich möchte die selbe Steuerung auch meinen Kindern als (lokalen) Wecker (mit abgespecktem Sketch) geben und meinen Eltern für deren Lampen in vollumfänglicher Version... da wäre es gut, wenn die Bearbeitung am PC eine Option bleibt, aber nicht zur Pflicht wird...

Go Up