Einlesen einer CSV Datei in eine Wago Steuerung

Kurzschluß

Level-2
Beiträge
59
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich habe folgendes Problem. Ich möchte mit einer Wago Steuerung Typ 750-8212 und e!Cockpit ( aktuelle Version ) eine CSV Datei von der MMC Karte einlesen und verarbeiten. Schreiben auf die MMC Karte erfolgt mit der WAGO Bibliothek "WAGOAPPFILEDIR". Das Programm soll die einzelnen Zeichen der Datei durchgehen und diese dann in ein Array TYP Word schreiben. Ich komme mit der Wago Bibliothek nicht ganz zurecht.

Könnte mir jemand einen Tipp geben wie ich vorgehen soll.

DANKE



 
Hallo Kurzschluss
Warum eine csv Datei?
Hier besteht das große Problem, dass wenn sie mit einem externen Programm (z.B. Excel) bearbeitet wird es mehrere Einstellungen zur Trennung gibt. Des weiteren können Kommentare eingefügt werden, die das Auswerten verkomplizieren.
Dies ist dir eventuell alles nicht bekannt in deiner PFC.

Prinzipiell musst du deine Datei Zeilenweise einlesen, das Trennzeichen suchen und dann mit den Stringfunktionen (Left, Mid, Right) deine Daten auslesen, wandeln und auf Gültigkeit prüfen.

Wenn du nur einen Datenspeicher suchst wäre ein anderes Format wahrscheinlich besser geignet.

Holger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Dies ist dir eventuell alles nicht bekannt in deiner PFC.
...
Wenn du nur einen Datenspeicher suchst wäre ein anderes Format wahrscheinlich besser geeignet.
Vergleichst Du hier Äpfel mit Birnen?
Denkst Du bei "ein anderes Format" an ein allgemein übliches Format? Ich vermute eher, an ein den individuellen Anforderungen angepasstes Format.
Da legt man ja selber fest, wie es aussieht und weiss, wie es einzulesen ist.
Möglichkeiten, die einem die Deutung erschweren, kann man dann sicherlich vermeiden.

CSV-Dateien hingegen drängen sich auf, wenn sie von anderen Anwendungen gelesen und/oder geschrieben werden sollen. Zum Glück ist dort kein bestimmtes Zeichen als Trennzeichen in Stein gemeisselt. CS steht zwar für comma separated, ist aber variabel gehalten, damit es an die zu übertragenden Daten angepasst werden kann. Es muss lediglich sichergestellt sein, dass das Trennzeichen nicht auch innerhalb der Daten verwendet wird. Semikolon oder TAB sind meist besser geeignet als das Komma, das in unserem Sprachraum in Zahlen als DezimalKomma (DezimalPunkt bei uns ungebräuchlich) vorkommt.
Zudem muss man auch beachten, GänseBeinchen (") und HochKomma (') nur paarweise (einmal für Beginn und einmal für Ende eines Textes) zu verwenden und einzelne dieser Zeichen innerhalb eines Textes deshalb zu verdoppeln. Das Zeichen " als Masseinheit für Zoll/inch wird allzu leicht als Störenfried übersehen.
Aber diese Einschränkungen sollten eigentlich bekannt sein und weitere fallen mir nicht ein.
Allerdings, beim Einlesen in Excel gibt es weitere FallStricke. Z.B. '=' ,'+'und '/' an erster Stelle, ':' zwischen Ziffern und runde Klammern um Ziffern herum, werden von Excel gerne missverstanden.
Habe mir deshalb angewöhnt, zum Einlesen in Excel etwas in VBA selbstgestricktes zu verwenden.
 
Zuletzt bearbeitet:
Guten Morgen,

schreiben geht. Das Einlesen macht Probleme. die csv hat immer Datum, Uhrzeit. Die sollen in ein array.

Grüße!
 
Könntest du mir bitte einen Ausschnitt deiner CSV-Datei zeigen? Ich habe meine in ein Array mit Struktur umgewandelt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen,
hier der Ausschnitt:

02.05.2024 00:00​
0​
02.05.2024 00:15​
2​
02.05.2024 00:30​
4​
02.05.2024 00:45​
6​
02.05.2024 01:00​
8​
02.05.2024 01:15​
9​
02.05.2024 01:30​
33​
02.05.2024 01:45​
66​
02.05.2024 02:00​
88​
02.05.2024 02:15​
0​

Das Problem liegt hauptsächlich in den Bibos von eCockpit. Beispiele für Twincat passen an einigen Stellen nicht. Ich brauch nur mal einen Ansatz fürs Einlesen der Datei in Buffer und wenn möcglich die Sortierung in ein Array. Das array aus Struct hab ich schon.


Danke und Grüße!
 
Unter der Annahme, dass die CSV nicht zu groß ist (also in eine halbwegs managebare String-Variable passt) und nicht weiter anwächst, nachdem Du sie gelesen hast, brauchst Du nur drei Dinge.
1. WagoAppFileDir.FbReadWholeFile_cpt
Den Eingang udiRxBufferSize belegst Du mit einem ADR(sReadBuffer) String in ausreichender Größe, z.B. STRING(2048).​
Der Eingang udiRxNBytes ist dann nur diese Größe, also SIZEOF(sReadBuffer).​
2. WagoAppString.StrExtractToken in einer While-Schleife.
Hiermit extrahierst Du erst eine ganze Zeile der CSV indem Du als bSeparator WagoTypes.eChar.LineFeed verwendest.​
Dann nimmst Du die die gleiche Funktion um Zeitstempel und den Prozesswert zu trennen, also als bSeparator WagoTypes.eChar.Semicolon.​
3. Umwandeln des Zeitstempels und in ein Array deines Datentyps aus DT und INT ablegen.
Umwandlung z.B. mit WagoAppString.FuStringToDT(bFormat:=3, sInput:= '02.05.2024 01:15')​
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Zu e!COCKPIT-Zeiten gab es mal eine WagoAppCSV vom Support als Beta-Version. Keine Ahnung, ob es die bereits offiziell gibt. In CODESYS 3 ist sie jedenfalls nicht enthalten. Jedenfalls konnte die CSV-Dateien lesen und gleich auch in Wertepaare stückeln.
 
Hallo,

nun hab ichs versucht.
1. funktioniert nicht gut
2. Sackgasse, da die WagoAppString.StrExtractToken nur einen String von 255 verarbeiten kann. Das ist selbst bei meiner kleien csv zu klein.
3. falls es doch klappt - gibt es in der Visu einen Dateiauswahldialogum die .csv auf die SD-Karte zu schreiben?

hier mal mein ProbierProgrammiercode:
Code:
PROGRAM PLC_PRG
VAR
    
oRead    : WagoAppFileDir.FbReadWholeFile_cpt;

x_stFileName             : STRING := '/media/sd/forecast.csv';

 
  oReadCfg                    : WagoAppFileDir.FbReadWholeFile_cpt;
  sReadErrorInfo            : STRING;
  xRead                        : BOOL;
  xReadError                : BOOL;
 
  oCfg                        : STRING(2000);
  s_line                    : STRING;
  s_date                    : STRING;
  s_time                    : STRING;
  s_value                    : STRING;
 
  dt_date                    : DATE;
  dt_time                    : TIME_OF_DAY; // Zeit von     
  r_arbeit                    : REAL; // Arbeit in kwh
 
 // oToken_sperator             :  WagoAppString.StrExtractToken;
  UDI_startCSV                    : UDINT := 1;
  UDI_nextCSV                    : UDINT;
  UDI_startZ                    : UDINT := 1;
  UDI_nextZ                        : UDINT;        // ENde Zeile
   UDI_nextZv                        : UDINT;        // ENde Zeile
  udi_Zeile_Ende                : UDINT;
  udi_Datum_Ende                : UDINT;   
  udi_Zeit_Ende                    : UDINT;
  sZeileEnde                    : STRING := '$R$N';
 
      z                        : INT;

    i_anzahl_zeilen_in        : INT := 18;
    m_lade_visu_von_csv        : BOOL;

END_VAR


// Program

oReadCfg(
 xTrigger:= xRead,
 sName:= x_stFileName,
 pRxBuffer:= ADR(oCfg),
 udiRxBuffersize:= SIZEOF(oCfg) );
 
 oReadCfg.oStatus.ShowResult(sDescription => sReadErrorInfo);
           UDI_startCSV := 1;   
        
  IF m_lade_visu_von_csv  THEN


        FOR z := 1 TO i_anzahl_zeilen_in  DO
                    
                // Datei in Buffer
                    WagoAppString.StrExtractToken(sBuffer:= oCfg, udiSize := SIZEOF(oCfg),bSeparator := eChar.LineFeed, udiBegin := UDI_startCSV, udiNext =>UDI_nextCSV ) ;            // CSV Zeile einlesen bis Umbruch
                
                
                        s_line := MID(oCfg, UDINT_TO_INT( UDI_nextCSV - UDI_startCSV ), UDINT_TO_INT(UDI_startCSV  ));                                                // Text aus Zeile in String zum weiterzuverarbeiten
                // Zeile ermittelt       
                                    WagoAppString.StrExtractToken(sBuffer:= s_line, udiSize := SIZEOF(s_line),bSeparator := eChar.Comma, udiBegin := UDI_startZ, udiNext =>UDI_nextZ ) ;            // Datum suchen bis ertses Komma in Zeile
                                        udi_Datum_Ende     := UDI_nextZ;
                                    
                                        s_date  := MID(s_line, UDINT_TO_INT( UDI_nextZ -2 ), UDINT_TO_INT(UDI_startZ ));                                                                                       
                                        s_date    := CONCAT('D#',s_date);                                                    // STRING anpassen
                                        dt_date    := STRING_TO_DATE(s_date);            // STRING ZU DATE
                                        
                                        GVL.ar_zeit_soll_visu[z].d_DATE_0         := dt_date;            /// Wert ins ARRAY VISU
                                    
                                     WagoAppString.StrExtractToken(sBuffer:= s_line, udiSize := SIZEOF(s_line),bSeparator := eChar.Comma, udiBegin := udi_Datum_Ende +0, udiNext =>UDI_nextZ ) ;            // Uhrzeit suchen zwischen 1. und 2. Komma
                                        udi_Zeit_Ende     := UDI_nextZ;
                                    
                                         s_time     := MID(s_line, UDINT_TO_INT(UDI_nextZ - udi_Datum_Ende -1  ), UDINT_TO_INT(udi_Datum_Ende));            // -1 wegen Komma
                                        s_time    := CONCAT('TOD#',s_time);                                            // STRING anpassen   
                                        dt_time    := STRING_TO_TOD(s_time);        // STRING ZU TIME_OF_DAY
                                        
                                        GVL.ar_zeit_soll_visu[z].dt_time_0         := dt_time;            /// Wert ins ARRAY VISU
                                
                                     WagoAppString.StrExtractToken(sBuffer:= s_line, udiSize := SIZEOF(s_line),bSeparator := STRING_TO_BYTE(sZeileEnde), udiBegin := udi_Zeit_Ende +0, udiNext =>UDI_nextZv ) ;            // STRING_TO_BYTE(sZzeielEnde) Wert suchen zwischen Zeit Ende und Zeilenende
                                                                            
                                         s_value := MID(s_line, UDINT_TO_INT(UDI_nextZv - udi_Zeit_Ende ), UDINT_TO_INT(udi_Zeit_Ende));        //  Länge des Wertes spielt keine Rolle - bis ENDE Zeile
                                        r_arbeit:= FPU.StrToReal(s_value);        // STRING ZU Real
                                         GVL.ar_zeit_soll_visu[z].r_arbeit         := r_arbeit;            /// Wert ins ARRAY VISU
                        
                                         UDI_startCSV := UDI_nextCSV  ;   
                                
                                
            END_FOR        // CSV Zeile
    END_IF
Code:
// die forecast.csv - ohne Kopf

2024-05-11,04:00,0.1
2024-05-11,05:00,0.2
2024-05-11,06:00,0.3
2024-05-11,07:00,0.4
2024-05-11,08:00,8
2024-05-11,09:00,9
2024-05-11,10:00,10
2024-05-11,11:00,11
2024-05-11,12:00,12
2024-05-11,13:00,13
2024-05-11,14:00,14
2024-05-11,15:00,15
2024-05-11,16:00,16
2024-05-11,17:00,17
2024-05-11,18:00,18
2024-05-11,19:00,19
2024-05-11,20:00,20
2024-05-11,21:00,21

Danke schon mal fürs Kopfzerbrechen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der extrahierte Teil-String darf nicht länger sein als 255 Zeichen, oder genauer gesagt länger als MaxString. Letzter ist ein Alias für STRING(MAX_STRING_LENGTH) und MAX_STRING_LENGTH ist ein Parameter der Bibliothek, der mit 255 initialisiert ist, aber auf einen beliebigen UDINT Wert gesetzt werden kann. Das brauchst Du aber nicht, da die einzelne Zeile bei Dir immer kürzer ist, als 255 Zeichen. Der String in dem gesucht wird wird als Pointer und Größe übergeben und kann daher beliebig lang sein.

Ich überlege noch, ob ich mich in deinen Code eindenke oder selbst eine Lösung erarbeite. Beides aber nicht mehr heute ...

Nein, es gibt keinen Datei-Auswahl-Dialog, aber den kannst Du recht schnell selbst basteln. Hier gab es mal ein gutes Bsp. dafür. Im wesentlichen werden mit WagoAppFileDir Funktionen alle Dateinamen eines Verzeichnisses ausgelesen und Visu gebracht. Wenn man es alles Array der Dateinamen macht kann man es gut in eine Tabelle auf der Visu anzeigen und dort auch eine Auswahl treffen.
 
Zurück
Oben