CSV Dateien schreiben

Der TwinCAT 3 Database Server unterstützt das CSV-Dateiformat. Es gibt unterschiedliche Ansätze mit jeweils Vor- und Nachteilen, um Inhalte in die Datei zu schreiben oder zu lesen. Zwei dieser Ansätze werden hier genauer erläutert.

Wählen Sie die ASCII-Datenbank aus. Dort kann unter dem Dateipfad das Dateiformat .csv angegeben werden. Das ASCII-DB 3.0 Format-Flag gibt das Format der ASCII/CSV-Datei an. Fall das Format angehakt ist, wird das SAX-Verfahren genutzt. Mit dieser Einstellung ist der Schreibzugriff auf die Datei insbesondere mit dem FB_PLCDBCmdEvt-Baustein auch bei großen Dateien sehr performant. Ist das Format nicht angehakt, wird das DOM-Verfahren genutzt, welches sich besonders für das Lesen einer Datei eignet. Die Daten liegen dabei strukturiert im Arbeitsspeicher. Deshalb ist dieses Verfahren eher bei kleinere Dateien <1MB zu empfehlen. Durch die strukturierte Ablage bietet dieses Verfahren jedoch einige Vorteile. Die CSV-Datei kann mithilfe einer abgelegten Tabellenstruktur als SQL Datenbank genutzt werden. Nutzen Sie hierfür den SQL Query Editor. Über den ‚Create‘-Button kann diese Datei direkt erzeugt werden.

CSV Dateien schreiben 1:

Laden Sie ihre Konfiguration auf Ihr TwinCAT Database Server Target System.

ASCII-Format Kompatibilität

Funktionsbaustein

Tabellen Struktur

ASCII-Format 3.0

Standard ASCII

FB_PLCDBWriteEvt.Write

standard

CSV Dateien schreiben 2:

CSV Dateien schreiben 3:

FB_PLCDBWriteEvt.WriteStruct*

beliebig

CSV Dateien schreiben 4:

CSV Dateien schreiben 5:

FB_PLCDBReadEvt.Read

standard

CSV Dateien schreiben 6:

CSV Dateien schreiben 7:

FB_:PLCDBReadEvt.ReadStruct*

beliebig

CSV Dateien schreiben 8:

CSV Dateien schreiben 9:

FB_PLCDBCmdEvt.Execute*

beliebig

CSV Dateien schreiben 10:

CSV Dateien schreiben 11:

FB_SQLCommandEvt

beliebig

CSV Dateien schreiben 12:

CSV Dateien schreiben 13:

*Markierte werden im folgenden Beispiel verwendet

Performant in die CSV-Datei schreiben

Die performanteste Art in eine CSV-Datei zu schreiben, ist die Nutzung des FB_PLCDBCmdEvt Bausteines. Dafür muss die Verknüpfung zu CSV-Datei im ASCII-DB 3.0 Format eingestellt werden. Der DBValueType spielt dabei keine Rolle. Eine Tabellenstruktur muss vorher nicht definiert werden.

Beispiel:

Gegeben sei folgende Struktur:

TYPE ST_CSVDataStruct :
STRUCT
    ID: LINT;
    Timestamp: DT;
    Name: STRING(80);
    Velocity: LREAL;
    Temperature: LREAL;
END_STRUCT
END_TYPE

Der Baustein wird folgendermaßen initialisiert:

VAR
    InputData: ST_CSVDataStruct;
    fbPLCDBCmd: FB_PLCDBCmd (sNetID:= '', tTimeout := T#30S);

    sCmd : T_MaxString := '{ID};{Timestamp};{Name};{Velocity};{Temperature}';

    para : ARRAY [0..4] OF ST_ExpParameter :=[
            (eParaType:= E_ExpParameterType.Int64, nParaSize := 8, sParaName := 'ID'),
            (eParaType:= E_ExpParameterType.DateTime, nParaSize := 4, sParaName := 'Timestamp'),
            (eParaType:= E_ExpParameterType.STRING_, nParaSize := 81, sParaName := 'Name'),
            (eParaType:= E_ExpParameterType.Double64, nParaSize := 8, sParaName := 'Velocity'),
            (eParaType:= E_ExpParameterType.Double64, nParaSize := 8, sParaName := 'Temperature')];
END_VAR

Die einzelnen Parameter werden in geschweiften Klammern im Kommando angegeben. Diese werden in über die Initialisierung beschrieben mit den Informationen zum Typ, der Bytelänge und dem Namen. Anhand des Namens wird der Parameter im Kommando wiedererkannt und entsprechend beim Schreiben in die Datei durch den Wert aus der PLC ersetzt.

Der Aufruf im PLC-Quellcode des Bausteins besteht aus einem Aufruf:

IF fbPLCDBCmd.Execute(
    hDBID:= 3,
    pExpression:= ADR(sCmd),
    cbExpression:= SIZEOF(sCmd),
    pData:= ADR(InputData),
    cbData:= SIZEOF(InputData) ,
    pParameter:= ADR(para),
    cbParameter:=SIZEOF(para))
THEN
    ;//Place for errorhandling or reactions;
END_IF
// Result: 16160;19-10-2018 12:27:38;Water Turbine;35.2238040741592;62.6461585412374

Die hDBID ist abhängig von ihrer Konfiguration und kann der Datenbankverknüpfung entnommen werden. Als pData (bzw. cbData) kann nicht nur die Adresse zur einzelnen Struktur, sondern auch zu einem Array ihrer Struktur angegeben werden. Dies kann nochmals zu Performanceverbesserungen führen.

Strukturiertes Schreiben und Lesen einer CSV-Datei

Nicht alle Funktionsbausteine sind mit dem ASCII-Format 3.0 möglich. Für einige Funktionen des TwinCAT Database Servers ist eine vorher konfigurierte Tabellenstruktur nötig. Diese lässt sich jedoch nicht im ASCII-Format 3.0 hinterlegen. In diesem Beispiel wird eine fest definierte Struktur verwendet, um die Daten mit den PLCDBWriteEvt- und PLCDBReadEvt-Bausteinen in beliebiger Struktur zu schreiben und zu lesen.

Folgende Struktur ist gegeben:

CSV Dateien schreiben 14:

Auch als Export für die PLC unter dem ‚Select‘-Tab möglich:

TYPE ST_CSVDataStruct :
STRUCT
    ID: LINT;
    Timestamp: DT;
    Name: STRING(80);
    Velocity: LREAL;
    Temperature: LREAL;
END_STRUCT
END_TYPE

Für beliebige Tabellenstrukturen werden die Write-/ReadStruct Methoden der jeweiligen PLC-Funktionsbausteine verwendet:

VAR
    fbPLCDBWrite: FB_PLCDBWrite(sNetID:= '', tTimeout := T#30S);
    fbPLCDBRead : FB_PLCDBRead(sNetID:= '', tTimeout := T#30S);
    ColumnNames : ARRAY [0..4] OF STRING(50) := ['ID','Timestamp','Name','Velocity','Temperature'];
    Data: ST_CSVDataStruct;
    ReadData: ARRAY[0..4] OF ST_CSVDataStruct;
END_VAR
IF fbPLCDBWrite.WriteStruct(
    hDBID:= hDBID,
    sTableName:= 'CSV_Sample',
    pRecord:= ADR(Data),
    cbRecord:= SIZEOF(Data),
    pColumnNames:= ADR(ColumnNames),
    cbColumnNames:= SIZEOF(ColumnNames) )
THEN
    ;//Place for errorhandling or reactions
END_IF

IF fbPLCDBRead.ReadStruct(
    hDBID:= hDBID,
    sTableName:= 'CSV_Sample',
    pColumnNames:= ADR(ColumnNames),
    cbColumnNames:= SIZEOF(ColumnNames) ,
    sOrderByColumn:= 'ID',
    eOrderType := E_OrderType.ASC,
    nStartIndex:= 0,
    nRecordCount:= 5,
    pData:= ADR(ReadData),
    cbData:=SIZEOF(ReadData))
THEN
    ;//Place for errorhandling or reactions
END_IF

Die Methode WriteStruct(…) schreibt die Struktur Data in die Datenbank. Anhand der ColumnNames werden die Strukturen der PLC und der CSV-Datei abgeglichen.

Die Methode ReadStruct(…) liest eine bestimmte Anzahl (nRecordCount) von Datensätzen aus der CSV-Datei. Diese können auch nach einer ausgewählten Spalte geordnet werden. Das Ziel-Array ReadData sollte dabei mindestens so groß sein, wie die Anzahl der abgeholten Daten, um alle Daten empfangen zu können.

Anhang

Eine Beispielkonfiguration beider Beispiele, sowie der vollständige Code eines einfachen Beispielprogramms können Sie hier herunterladen:TF6420_BestPractise_CSV.zip. Um den Vorgang zu veranschaulichen, generiert das Programm Werte und schickt diese wiederholt in die CSV. Die oben verwendeten Einstellungen wurden dabei in einen eigenen Funktionsbaustein ausgelagert, welcher auf verschiedene Weise mit den beiden CSV-Formaten kommuniziert.