Problem bei Schreiben in CSV-Datei

Exilim

Level-1
Beiträge
44
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo liebe Community


ich stehe vor einem Problem und hoffe ihr könnt mir weiterhelfen.
Ich möchte mit meiner CX5130 - SPS Daten einer Messklemme auslesen und in eine CSV-Datei schreiben (Soweit nicht kompliziert :)).
Die Klemme liefert alle 100µs (EL3356-0010) neue Werte, wobei ich im 5ms Takt die Werte in die CSV-Datei schreiben möchte.


Folglich mein Code für die Datenspeicherung:

Code:
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! - Write
                        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 *)
    cbRecord := 0;
    fbWriter.eCmd := eEnumCmd_First;                                                // Write first field value
    IF nRow <= GVL_Measurement.MAX_CSV_ROWS THEN
         FOR nColumn := 0 TO GVL_Measurement.MAX_CSV_COLUMNS BY 1 DO
                
         cbField := 0;
         CASE nColumn OF
         0:
             cbField := ARG_TO_CSVFIELD(F_ULINT(database[nRow].uliTimestamp), TRUE, ADR(aBuffer), SIZEOF(aBuffer));
         1:
            cbField := ARG_TO_CSVFIELD(F_DINT(database[nRow].diValue), TRUE, ADR(aBuffer), SIZEOF(aBuffer));
         ELSE
         ;
         END_CASE
                
         IF cbField > 0 THEN
         (* Add new field to the record buffer *)
              fbWriter(pBuffer := ADR(record),
                           cbBuffer := SIZEOF(record), 
                           putValue :='',  
                           pValue := ADR(aBuffer), 
                           cbValue := cbField,
                           bCRLF := (nColumn = GVL_Measurement.MAX_CSV_COLUMNS));(* bCRLF == TRUE => Write CRLF after the last field value *)
                             
             IF fbWriter.bOk THEN
                 fbWriter.eCmd     := eEnumCmd_Next;(* Write next field value *)
                 cbRecord         := cbRecord + fbWriter.cbWrite;(* Calculate the new record size *)
             ELSE(* Error *)
                 step := 100;
                 RETURN;
             END_IF
       END_IF
   END_FOR

   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:
    fbFileWrite(sNetId:= sNetId, 
                    hFile:= hFile, 
                    pWriteBuff:= ADR(record), 
                    cbWriteLen:= cbRecord, 
                    bExecute:= TRUE);    
           
    step := 5;
        
    5:    
     fbFileWrite(bExecute := FALSE,
                      bError        => bError,
                      nErrId        => nErrId);
                    
      IF NOT fbFileWrite.bBusy THEN
            IF NOT fbFileWrite.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     := 0;                                                                // Ready 
        END_IF
END_CASE


Die Daten (uliTimestamp-> ULINT und diValue -> DINT) werden in ein Array gespeichert welches dem Baustein "FB_WriteDataIntoCSVFile" übergeben wird (database : ARRAY[0..GVL_Measurement.MAX_CSV_ROWS] OF ST_Csv_Record;)
soweit funktioniert die Datenumwandlung.... Jedoch steht in meiner CSV-Datei (zwar in der richtigen Zeile/Spalte) nur Unsinn in From von irgendwelchen Buchstaben oder Sonderzeichen...



Was mache ich flasch? oder was kann ich ändern damit es funktioniert?


Vielen Dank im voraus!


Viele Grüße
 
Zuletzt bearbeitet:
Ok, das Problem liegt wahrscheinlich am Binary-Mode... Jedoch möchte ich meinen Daten die String-Konvertierung ersparen um die Performance anzukurbeln.

LG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es liegt wohl eher nicht am Binary-Mode, sondern daran, daß Zeichen (mit unkontrolliertem, quasi zufälligem Inhalt) in die Datei geschrieben werden, die gar nicht zu den Strings gehören.

Kann sich die Länge Deiner Strings ändern? Dann müsstest Du die Strings immer auf volle Länge mit Leerzeichen auffüllen oder einzeln und lückenlos in den Buffer für fbFileWrite umkopieren, weil fbFileWrite schreibt keine Strings sondern den gesamten vom Buffer belegten Speicher (Array of Byte) - inklusive der unkontrollierten Bytes hinter dem Ende der Strings.

Harald
 
Mal eine generelle Frage dazu, ist der Baustein so überhaupt eingebunden? Weil wenn ja müsste er eigentlich meckern, weil bei step 2,3 & 11 die : fehlen. Oder einfach nur Code dazwischen gelöscht?

Edit: Wenn du magst kann ich dir mal schreiben, wie ich das anhand eines umgeschrieben Beispielprogrammes bei mir löse, allerdings im Textmode. Das wird dann aber eher eine längere PN als Foreneintrag
 
Zuletzt bearbeitet:
Hallo,
vielen Dank für eure Antworten. Ich habe mich mal dran orientiert .... stoße aber jetzt auf folgendes Problem:

Ich schreibe einen Zeitstempel (Spalte 1), und zwei Messwerte (Spalte 2 und 3) in eine CSV-Datei. Laut meinem Beispiel sollen 250 Zeilen (GVL_Measurement.nRow := 250) beschrieben werden.
Komischerweise werden nur jeder zweite Wert in die Datei geschrieben und am Ende auch nur insgesamt 125 Zeilen beschrieben.... Könnt ihr mir auf die schnelle sagen was ich falsch mache?

Code:
FUNCTION_BLOCK FB_WriteDataIntoCSVFile
VAR_INPUT
    bWrite            : BOOL;                                                                // Rising edge starts program execution
    sPath            : STRING(255);
    sFileName        : STRING(255);
    sFileExt        : STRING(255);
    dwMode            : DWORD;
    udiAnzByte        : UDINT;
    database        : ARRAY[0..GVL_Measurement.MAX_CSV_ROWS] OF ST_Csv_Record;
END_VAR
VAR_OUTPUT
    bBusy            : BOOL;                                                                // is functionblock busy? 
    bError            : BOOL;                                                                // signals an error 
    nErrId            : UDINT;                                                            // if the functionblock has an error, show the error-id 
END_VAR
VAR
    fbRtrigExecute    : R_TRIG;
    sNetId            : T_AmsNetId := '';                                // TwinCAT system network address
    sFile            : STRING(255);
    nRow             : UDINT        := 0;                                                    // Row number
    nColumn            : UDINT     := 0;                                                    // Column number
    hFile            : UINT        := 0;                                                    // File handle of the source file
    step            : DWORD     := 0;                                                    // switch - case - Anweisung
    
    fbFileOpen        : FB_FileOpen;                                                        // Opens file
    fbFileClose        : FB_FileClose;                                                        // Closes file
    fbFilePuts        : FB_FilePuts;
    fbWriter        : FB_CSVMemBufferWriter;                                            // Helper function block used to create CSV data bytes (single record line)(Tc2_Utilities)
    
    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) *)
END_VAR


fbRtrigExecute(CLK := bWrite, Q=> );


CASE step OF
    0:    (* Wait for rising edge at bWrite variable *)
        IF fbRtrigExecute.Q THEN
            bBusy         := TRUE;
            bError        := FALSE;
            nErrId        := 0;
            hFile        := 0;
            nRow        := 0;
            nColumn        := 0;
            sFile        := sPath;
            sFile        := CONCAT (sFile, sFileName);
            sFile        := CONCAT (sFile, '.');
            sFile         := CONCAT (sFile, sFileExt);
            step         := 1;
        END_IF


    1:    (* Open source file *)
        fbFileOpen(sNetId         := sNetId, 
                   sPathName     := sFile, 
                   nMode         := dwMode,
                   ePath         := PATH_GENERIC, 
                   bExecute     := TRUE,
                   hFile        => hFile);
        
        IF NOT fbFileOpen.bBusy THEN
            IF fbFileOpen.bError THEN
                nErrId     := fbFileOpen.nErrId;
                   bError    := TRUE;
                step     := 10;
            ELSE
                step     := 2;
            END_IF
            fbFileOpen(bExecute := FALSE);
        END_IF


    2:(* Convert one PLC record to CSV format *)
        sCSVLine := '';
        (* Write first field value *)
        fbWriter.eCmd := eEnumCmd_First;                                        
        IF nRow <= GVL_Measurement.MAX_CSV_ROWS THEN
            (* Convert every PLC data field to the CSV data field format *)
            database[nRow].sTimestamp     := ULINT_TO_STRING(database[nRow].uliTimestamp);
            database[nRow].sValue1      := DINT_TO_STRING(database[nRow].diValue1);
            database[nRow].sValue2         := DINT_TO_STRING(database[nRow].diValue2);
            
            FOR nColumn := 0 TO GVL_Measurement.MAX_CSV_COLUMNS BY 1 DO
                CASE nColumn OF
                    0:
                        sCSVField := STRING_TO_CSVFIELD(database[nRow].sTimestamp, TRUE);
                    1:
                        sCSVField := STRING_TO_CSVFIELD(database[nRow].sValue1, TRUE);
                    2: 
                        sCSVField := STRING_TO_CSVFIELD(database[nRow].sValue2, TRUE);
                    ELSE
                        ;
                END_CASE
                
                    (* Add new field to the record buffer *)
                fbWriter(pBuffer := ADR(sCSVLine),
                         cbBuffer := SIZEOF(sCSVLine)-1, 
                         putValue :=sCSVField,  
                         pValue := 0, 
                         cbValue := 0,
                         bCRLF := (nColumn = GVL_Measurement.MAX_CSV_COLUMNS));(* 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... *)


            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 := 3;                                                                    // Write record to the File


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


    3:
        fbFilePuts(
            sNetId:= sNetId, 
            hFile:= hFile, 
            sLine:= sCSVLine, 
            bExecute:= TRUE);
            
        step := 4;
        
    4:    (* Wait until write not busy *)
        fbFilePuts( bExecute := FALSE, bError => bError, nErrID => nErrID );
        IF NOT fbFilePuts.bBusy THEN
            IF NOT fbFilePuts.bError THEN
                step := 2;(* 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     := 0;                                                                // Ready 
        END_IF


END_CASE
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,um kein neues Thema zu eröffnen, frage ich mal hier nach. Ich habe meine Art die .csv Datei zu beschreiben umgeworfen. Das Array Database wird auch die befüllt, siehe Bild. Jedoch schreibt er mir nur den ersten Wert in die csv. Datei. das wird wohl daran liegen das er, wie in bild 2 zu sehen ist nur den einen nrow Inhalt hat weiter gibt. Was muss ich ändern das er da alle Werte des Database[nrow] nimmt und nicht nur den Inhalt des ersten [nrow]?

Die Database wird wie folgt aufgebaut
Code:
[/FONT][/COLOR]database[nrow].Widerstand := Widerstand;          database[nrow].Kraft:=GL_VAR.KMZ_String;
	 database[nrow].Weg:=GL_VAR.hoehe_dif;
         nrow:=nrow+1;[COLOR=#000000][FONT=monospace]


database_inhalt.jpgdatabase_code.jpg

 
Zuletzt bearbeitet:
Zurück
Oben