# Beckhoff -> Array of LREAL in CSV exportieren



## h_matthias (15 Oktober 2017)

Ich wünsche einen schönen Sonntag morgen!

Ich habe hier gerade ein Problem, bei dem ich etwas hänge. Vermutlich ist es nur eine Kleinigkeit, ich sehe aber gerade den Wald vor lauter Bäumen nicht. Ich habe mir das Beispiel von der Beckhoff- Homepage geholt, dieses erzeugt aber immer nur eine leere Datei.

Kann da mal jemand drüber schauen und mir sagen wo es hängt?

Vielen Dank.


```
PROGRAM csv


(* Writing of CSV file in text mode. None of the field value is containing any non-printing control characters like line feed, carriage return, quotation marks, semicolon... *)
VAR
    bWrite            : BOOL := FALSE;(* Rising edge starts program execution *)
    sNetId            : T_AmsNetId := '';    (* TwinCAT system network address *)
    sFileName    : T_MaxString := 'c:\TextModeGen.csv';(* CSV destination file path and name *)
    sCSVLine        : T_MaxString := '';(* Single CSV text line (row, record), we are using string as record buffer (your are able to see created fields) *)
    sCSVField        : T_MaxString := '';(* Single CSV field value (column, record field) *)
    sTest            : T_MaxString :='Test';
    bBusy            : BOOL;
    bError            : BOOL;
    nErrId            : UDINT;
    nRow             : UDINT     := 0;(* Row number (record) *)
    nColumn        : UDINT     := 0;(* Column number (record field) *)
    hFile            : UINT        := 0;(* File handle of the source file *)
    step            : DWORD     := 0;
    fbFileOpen    : FB_FileOpen;(* Opens file *)
    fbFileClose    : FB_FileClose;(* Closes file *)
    fbFilePuts        : FB_FilePuts;(* Writes one record (line) *)
    fbWriter        : FB_CSVMemBufferWriter;(* Helper function block used to create CSV data bytes (single record line) *)




    database        : ARRAY[0..10,0..10000] OF STRING(4) :=
    ['0_0', '0_1', '0_2', '0_3', '0_4', '0_5',
    '1_0', '1_1', '1_2', '1_3', '1_4', '1_5',
    '2_0', '2_1', '2_2', '2_3', '2_4', '2_5',
    '3_0', '3_1', '3_2', '3_3', '3_4', '3_5',
    '4_0', '4_1', '4_2', '4_3', '4_4', '4_5',
	'5_0', '5_1', '5_2', '5_3', '5_4', '5_5'];
	str_Power: STRING;
END_VAR
```


und dann noch das Programm:

GVL.Power ist ein ARRAY of LREAL[1..10000]


```
CASE step OF
    0:    (* Wait for rising edge at bWrite variable *)
        IF bWrite THEN
            bWrite         := FALSE;
            bBusy         := TRUE;
            bError        := FALSE;
            nErrId        := 0;
            hFile        := 0;
            nRow         := 0;
            nColumn    := 0;
            step         := 1;
        END_IF




    1:    (* Open source file *)
        fbFileOpen(  bExecute := FALSE  );
        fbFileOpen(     sNetId := sNetId, sPathName := sFileName, nMode := FOPEN_MODEWRITE OR FOPEN_MODETEXT,(* Open file in TEXT mode! *)
                        ePath := PATH_GENERIC, bExecute := TRUE );
        step := 2;




    2:(* Wait until open not busy *)
        fbFileOpen( bExecute := FALSE, bError => bError, nErrID => nErrID, hFile => hFile );
        IF NOT fbFileOpen.bBusy THEN
            IF NOT fbFileOpen.bError THEN
                step := 3;
            ELSE(* Error: file not found? *)
                step := 100;
            END_IF
        END_IF




    3:(* Convert one PLC record to CSV format *)
        sCSVLine := '';
        fbWriter.eCmd := eEnumCmd_First;(* Write first field value *)
        IF nRow <= 10 THEN




            FOR nColumn := 1 TO 10000 BY 1 DO


		str_Power:=LREAL_TO_STRING(gvl.Power[nColumn]);
                sCSVField := STRING_TO_CSVFIELD( str_Power, FALSE );(* TODO: Get field value from your application *)




                (* Add new field to the record buffer *)
                fbWriter(     pBuffer := ADR( sCSVLine ), cbBuffer := SIZEOF( sCSVLine ) - 1, putValue := sCSVField, pValue := 0, cbValue := 0,
                            bCRLF := ( nColumn = 10000 ) );(* bCRLF == TRUE => Write CRLF after the last field value *)
                IF fbWriter.bOk THEN
                    fbWriter.eCmd := eEnumCmd_Next;(* Write next field value *)
                ELSE(* Error *)
                    step := 100;
                    RETURN;
                END_IF




            END_FOR(* FOR nColumn := 0... *)




            (* FB_FilePuts adds allready CR (carriage return) to the written line.
            We have to replace the $R$L characters with $L character to avoid double CR. *)
            IF RIGHT( sCSVLine, 2 ) = '$R$L' THEN
                sCSVLine := REPLACE( sCSVLine, '$L', 2, LEN( sCSVLine ) - 1 );
            END_IF




            nRow := nRow + 1;(* Increment number of created records (rows) *)
            step := 4;(* Write record to the file *)




        ELSE(* All rows written => Close file *)
            step := 10;
        END_IF




    4:    (* Write single text line *)
        fbFilePuts( bExecute := FALSE );
        fbFilePuts( sNetId := sNetId, hFile := hFile, sLine := sCSVLine, bExecute := TRUE );
        step := 5;




    5:(* Wait until write not busy *)
        fbFilePuts( bExecute := FALSE, bError => bError, nErrID => nErrID );
        IF NOT fbFilePuts.bBusy THEN
            IF NOT fbFilePuts.bError THEN
                step := 3;(* Write next record *)
            ELSE(* Error *)
                step := 100;
            END_IF
        END_IF




    10:    (* Close source file *)
        fbFileClose( bExecute := FALSE );
        fbFileClose( sNetId := sNetId, hFile := hFile, bExecute := TRUE );
        step := 11;




    11:(* Wait until close not busy *)
        fbFileClose( bExecute := FALSE, bError => bError, nErrID => nErrID );
        IF ( NOT fbFileClose.bBusy ) THEN
            hFile := 0;
            step := 100;
        END_IF




    100: (* Error or ready step => cleanup *)
        IF ( hFile <> 0 ) THEN
            step := 10; (* Close the source file *)
        ELSE
            bBusy := FALSE;
            step := 101;    (* Ready *)
        END_IF




END_CASE
```


----------



## h_matthias (15 Oktober 2017)

Nochmal ein Nachtrag:

Wenn ich die Prozedur starte, läuft sie auch anständig durch und bleibt bei step=101 stehen. Aber die Datei ist halt eben leer. :-(


----------



## redria (15 Oktober 2017)

Hallo h_matthias,

ich habe Deinen Programmcode soeben einmal selbst in TwinCAT3 getestet.
Wenn ich den Code richtig gelesen habe, möchtest Du 10 Zeilen der CSV-Datei mit dem GVL.Power-Array zeilenweise beschreiben. D.h. du möchtest anschließend eine CSV-Datei mit 10 Zeilen haben, wobei in jeder Zeile das GVL.Power-Array steht. Ist das so richtig?

Du versuchst nun aber, das gesamte GVL.Power-Array mithilfe des FB_CSVMemBufferWriter Bausteins in eine CSV-Zeile zu formatieren. 
Dein verwendeter Buffer _sCSVLine_, welchen Du an _fbWriter _übergibst, ist hierzu jedoch mit 255 Bytes zu klein. Deshalb geht Dein Programm von Step 3 nach Step 100 und anschließend in Step 101, sobald der Buffer voll ist.

Man könnte nun den Buffer _sCSVLine_ durch ein sehr großes ARRAY OF BYTE ersetzen (z.B. 1..1000000).
Dazu kommt dann aber, dass FilePuts nicht geeignet ist, um solch lange Zeilen zu schreiben. Mit FilePuts sind maximal 255 Zeichen (T_MaxString) möglich.
Deshalb ist es außerdem notwendig, FB_FilePuts durch FB_FileWrite zu ersetzen.
Ich bin gerade dabei, Deinen Code dementsprechend anzupassen und ergänze diesen Post hier, sobald ich fertig bin.

Eventuell könntest Du ein wenig mehr über Deine Anwendung schreiben. Ggf. gibt es auch geschicktere Möglichkeiten, Deine Anforderungen zu erfüllen.

MfG Redria


----------



## h_matthias (15 Oktober 2017)

Guten Morgen Redria

Danke erstmal für Deine schnelle Antwort.

Ich hatte das vergessen Du erwähnen: Ich verwende auch TC3.
Das genannte Array wird von der Steuerung mit Stromwerten gefüllt. Jetzt muss ich dieses Array exportieren können, um das außerhalb der Maschine auswerten zu können. Daher hatte ich mir csv ausgesucht.

Es ist also das Ziel:
CSV-Zeile 1: GVL.Power[1]
CSV-Zeile 2: GVL.Power[2]
CSV-Zeile 3: GVL.Power[3]
CSV-Zeile 4: GVL.Power[4]
.
.
.
CSV-Zeile 10000: GVL.Power[10000]

sowas zu erzeugen.

Ich schau's mir selbst auch eben nochmal an.


----------



## redria (15 Oktober 2017)

Hallo h_matthias,

anbei das bearbeitete Programm zum Schreiben der CSV-Datei:


```
PROGRAM MAIN
VAR
    bWrite                : BOOL := FALSE;(* Rising edge starts program execution *)
    sNetId                : T_AmsNetId := '';    (* TwinCAT system network address *)
    sFileName            : T_MaxString := 'c:\TextModeGen.csv';(* CSV destination file path and name *)
    sCSVLine            : ARRAY [1..1000000] OF BYTE;(* Single CSV text line (row, record), we are using string as record buffer (your are able to see created fields) *)
    sCSVField            : T_MaxString := '';(* Single CSV field value (column, record field) *)
    sTest                : T_MaxString :='Test';
    bBusy                : BOOL;
    bError                : BOOL;
    nErrId                : UDINT;
    nRow                 : UDINT     := 0;(* Row number (record) *)
    nColumn                : UDINT     := 0;(* Column number (record field) *)
    hFile                : UINT        := 0;(* File handle of the source file *)
    step                : DWORD     := 0;
    fbFileOpen            : FB_FileOpen;(* Opens file *)
    fbFileClose            : FB_FileClose;(* Closes file *)
    fbFileWrite            : FB_FileWrite;(* Writes one record (line) *)
    fbWriter            : FB_CSVMemBufferWriter;(* Helper function block used to create CSV data bytes (single record line) *)








    database        : ARRAY[0..10,0..10000] OF STRING(4) :=
    ['0_0', '0_1', '0_2', '0_3', '0_4', '0_5',
    '1_0', '1_1', '1_2', '1_3', '1_4', '1_5',
    '2_0', '2_1', '2_2', '2_3', '2_4', '2_5',
    '3_0', '3_1', '3_2', '3_3', '3_4', '3_5',
    '4_0', '4_1', '4_2', '4_3', '4_4', '4_5',
    '5_0', '5_1', '5_2', '5_3', '5_4', '5_5'];
    str_Power: STRING;
    
    bFirstRun        :    BOOL := TRUE;
    nCounter        :    UDINT    := 0;
END_VAR
```


```
(* Filling the array during first run with dummydata*)
IF bFirstRun THEN
    FOR nCounter := 1 TO 10000 BY 1 DO
        gvl.Power[nCounter] := SIN(UDINT_TO_LREAL(nCounter));
    END_FOR
    
    bFirstRun := FALSE;
ELSE


CASE step OF
    0:    (* Wait for rising edge at bWrite variable *)
        IF bWrite THEN
            bWrite         := FALSE;
            bBusy         := TRUE;
            bError        := FALSE;
            nErrId        := 0;
            hFile        := 0;
            nRow         := 0;
            nColumn    := 0;
            step         := 1;
        END_IF








    1:    (* Open source file *)
        fbFileOpen(  bExecute := FALSE  );
        fbFileOpen(     sNetId := sNetId, sPathName := sFileName, nMode := FOPEN_MODEWRITE OR FOPEN_MODEBINARY,(* Open file in BINARY mode, because FB_CSVMemBufferWriter already adds CRLF! *)
                        ePath := PATH_GENERIC, bExecute := TRUE );
        step := 2;








    2:(* Wait until open not busy *)
        fbFileOpen( bExecute := FALSE, bError => bError, nErrID => nErrID, hFile => hFile );
        IF NOT fbFileOpen.bBusy THEN
            IF NOT fbFileOpen.bError THEN
                step := 3;
            ELSE(* Error: file not found? *)
                step := 100;
            END_IF
        END_IF








    3:(* Convert one PLC record to CSV format *)
        fbWriter.eCmd := eEnumCmd_First;(* Write first field value *)
       
    FOR nRow := 1 TO 10000 BY 1 DO




        str_Power:=LREAL_TO_STRING(gvl.Power[nRow]);
                sCSVField := STRING_TO_CSVFIELD( str_Power, FALSE );(* TODO: Get field value from your application *)


                (* Add new field to the record buffer *)
                fbWriter(     pBuffer := ADR( sCSVLine ), cbBuffer := SIZEOF( sCSVLine ), putValue := sCSVField, pValue := 0, cbValue := 0,
                            bCRLF := TRUE);(* bCRLF == TRUE => Write CRLF after the last field value *)
                IF fbWriter.bOk THEN
                    fbWriter.eCmd := eEnumCmd_Next;(* Write next field value *)
                ELSE(* Error *)
                    step := 100;
                    RETURN;
                END_IF








            END_FOR(* FOR nColumn := 0... *)


            step := 4;(* Write record to the file *)














    4:    (* Write single text line *)
    
        fbFileWrite( bExecute := FALSE );
        fbFileWrite( sNetId := sNetId, hFile := hFile, bExecute := TRUE, pWriteBuff := ADR(sCSVLine), cbWriteLen := fbWriter.cbSize);
        step := 5;








    5:(* Wait until write not busy *)
        fbFileWrite( bExecute := FALSE, bError => bError, nErrID => nErrID );
        IF NOT fbFileWrite.bBusy THEN
            IF NOT fbFileWrite.bError THEN
                step := 10;(* Writing CSV-File done*)
            ELSE(* Error *)
                step := 100;
            END_IF
        END_IF








    10:    (* Close source file *)
        fbFileClose( bExecute := FALSE );
        fbFileClose( sNetId := sNetId, hFile := hFile, bExecute := TRUE );
        step := 11;








    11:(* Wait until close not busy *)
        fbFileClose( bExecute := FALSE, bError => bError, nErrID => nErrID );
        IF ( NOT fbFileClose.bBusy ) THEN
            hFile := 0;
            step := 100;
        END_IF








    100: (* Error or ready step => cleanup *)
        IF ( hFile <> 0 ) THEN
            step := 10; (* Close the source file *)
        ELSE
            bBusy := FALSE;
            step := 101;    (* Ready *)
        END_IF








END_CASE


END_IF
```


----------



## h_matthias (15 Oktober 2017)

Super Genial!
Es funktioniert!

Danke für Deine Hilfe. Ich schau mir aber jetzt mal eben mal an, wie Du das gemacht hast.
Es ist schon komisch, kaum macht man es richtig, schon geht's  

Ich wünsche noch einen schönen Sonntag, hoffentlich mit weniger Zeit vor'm Computer!

Beste Grüße, Matthias


----------



## h_matthias (15 Oktober 2017)

Hallo nochmal

Jetzt muss ich doch noch eine Nachfrage stellen. Bei der Umwandlung in einen String (genauer: bei der Umwandlung durch STRING_TO_CSVFIELD) geht das Komma verloren. Da die Anzahl der Stellen immer unterschiedlich ist, kann ich das also durch mathematische Operationen nicht mehr ausgleichen.

Weiß jemand woran das liegt?

Danke.


----------



## h_matthias (15 Oktober 2017)

ok, hab's rausgefunden!
Einfach bei der Funktion auf TRUE stellen...


----------



## fhartmann (27 August 2018)

Vielen Dank für den nützlichen Beitrag. 
Ich hab den Variablen und Quellcode in mein TCProjekt einkopiert bekomme jedoch folgenden Fehler: Error 3760: P_500_CSV (29): Erroneous initial value --> benutze: TC2.11.0
Weis jemand was ich da flasch mache?


----------



## Guga (28 August 2018)

Ja, ich weiss was falsch läuft.
Bevor ich es dir aber verrate: Screenshots sind manchmal schon sehr limitiert, besonders wenn der Fehler auf Zeile 29 verweist und die Zeile 28 dann z.B. nicht vollständig sichtbar ist.
Zudem... bei der Bildauflösung habe ich Probleme die Details zu erkennen.

Aber zu deinem Problem. Initialwerte werden zwischen TC2 und TC3 marginal anders formatiert.

TC2: 
	test: ARRAY[0..7] OF REAL:= 10,20,30,40,50,60,70,80;
TC3:	
	test: ARRAY[0..7] OF REAL:= [10,20,30,40,50,60,70,80];


Guga


----------



## fhartmann (31 August 2018)

Merci, gewusst wie und es funktioniert. 
Herzlichen dank


Gesendet von iPhone mit Tapatalk


----------



## Vetsrob (7 März 2019)

Hallo zusammen


ICh habe eine Frage zum Beispielcode.

Ich möchte das erste Array in die Spalten der ersten Zeile schreiben, beim nächsten Aufruf  resp. Durchgang sollen die Werte nicht hinter die alten angehängt werden,sondern das neue Array soll in die selben Spalten geschrieben werden wie das alte Array, allerdings soll eine neue Zeile verwendet werden. 

Kann mir jemand weiter helfen wie ich das realisieren kann?

Vielen Dank für die Hilfe.


----------

