Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: Beckhoff TwinCAT PLC - Alle 10 Sekunden Werte von Variablen in eine CSV-Datei

  1. #1
    Registriert seit
    22.03.2013
    Beiträge
    32
    Danke
    6
    Erhielt 0 Danke für 0 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hallo zusammen,

    ich sitze derzeit daran ein für Profis sehr einfach Programm mi ST zu schreiben.
    Leider verzweifel ich derzeit daran alle 10 Sekunden eine Zeile in eine CSV-Datei zu schreiben.
    Was ich geschafft habe, ist das Schreiben eines Arrays in die CSV-Datei mit Hilfe der Anleitung von hier: http://infosys.beckhoff.com/content/1031/tcplclib_tc2_utilities/html/tcplclibutilities_csv_sample.htm?id=15741

    Der entsprechende Programmcode ist dieser hier:

    Die Variablen:
    Code:
    PROGRAM P_TextModeWrite
    (* 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 := '192.168.2.109.1.1';    (* TwinCAT system network address *)
        sFileName    : T_MaxString := '\Hard Disk\test\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 :='DasTest';
        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..MAX_CSV_ROWS, 0..MAX_CSV_COLUMNS ] OF STRING(MAX_CSV_FIELD_LENGTH) := (* Source PLC database *)
        '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';
    
    
    END_VAR
    Der Code:
    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_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 <= MAX_CSV_ROWS THEN
    
    
                FOR nColumn := 0 TO MAX_CSV_COLUMNS BY 1 DO
    
    
                    sCSVField := STRING_TO_CSVFIELD( sTest, 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 = 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... *)
    
    
                (* 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
    Nach meinem Verständnis müsste ich nun bei Step 3 die Schleife ändern und dann irgendwie alle 10 Sekunden eine neue Zeile in die Datei schreiben. Bei beiden vorhaben komme ich derzeit nicht weiter.
    Könnt ihr mir weiterhelfen?
    Vielen Dank!
    LG,
    Dennis
    Zitieren Zitieren Beckhoff TwinCAT PLC - Alle 10 Sekunden Werte von Variablen in eine CSV-Datei  

  2. #2
    Registriert seit
    20.08.2007
    Beiträge
    112
    Danke
    13
    Erhielt 10 Danke für 8 Beiträge

    Beitrag

    Anbei mal ne ganz schnelle schlampige Idee von mir.
    Vielleicht hiflts ja weiter. Ist ungetestet, aber ich denke die Idee ist klar.
    Viel Spaß damit

    Zitat Zitat von mv08 Beitrag anzeigen
    Code:
        3:(* Convert one PLC record to CSV format *)
            sCSVLine := '';
            fbWriter.eCmd := eEnumCmd_First;(* Write first field value *)
            IF nRow <= MAX_CSV_ROWS THEN
    
    
                FOR nColumn := 0 TO MAX_CSV_COLUMNS BY 1 DO
    
    
                    sCSVField := STRING_TO_CSVFIELD( sTest, 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 = 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... *)
    
    
                (* 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
    Hi zuerst würde ich mir mit einem Ton eine weiterschaltbedingung machen, dass ich weitermachen darf:

    Code:
    MyWaitTON(IN:=startNextColumn , PT:=t#10ms , Q=> , ET=> );
    Dann die Statemachine vielleicht so aufdrösseln

    Code:
        3: (*Starte die Zeit an deinem Ton*)
            startNextColumn := TRUE;
            step := 4;
    
        4: (* Convert one PLC record to CSV format *)
            sCSVLine := '';
            fbWriter.eCmd := eEnumCmd_First;(* Write first field value *)
            nColumn := 0;
            IF nRow <= MAX_CSV_ROWS THEN
               step := 5;
            ELSE
                step := 10;
            END_IF
          5: (**)
                   startNextColumn := TRUE;
                   sCSVField := STRING_TO_CSVFIELD( sTest, 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 = 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
             6: IF  nColumn < TO MAX_CSV_COLUMNS BY
                  nColumn := nColumn +1;
                  step := 7;
                 ELSE
                  step 8=;
                 END_IF
               
             7: IF MyWaitTON.Q THEN
                   startNextColumn := FALSE;
                   step := 5;
                 END_IF
    
    
    
    
               8: (* 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
    EDit!!!
    Ups ich habe gerade gesehen, dass du die Zeilen, nicht die Spalten alle 10ms schreiben willst. Aber vielleicht siehst du ja jetzt ungefähr wie es geht.
    Geändert von wonderfulworld (14.06.2013 um 18:18 Uhr)
    Solls was Rechtes sein, oder darfs auch was von Siemens sein?

  3. #3
    Registriert seit
    20.08.2007
    Beiträge
    112
    Danke
    13
    Erhielt 10 Danke für 8 Beiträge

    Standard

    Hier jetzt nochmal ne anständige Lösung (natürlich auch ungetestet, aber die Idee müsste klar sein).

    Der Code:
    Code:
    (*neues ton einfügen. Das TON geht erst nach 10s an, wenn die Eingangsvaribele IN TRUE ist*)
    startNewRowTON(IN:= startNewRow, PT:=t#10s , Q=> , ET=> );
    
    CASE step OF
    ....
    
        3:(* Convert one PLC record to CSV format *)
    (*-------------> Hier wird die Zeit gestartet, bei der du in das ton reinschreiben darfst.*)
            startNewRow := TRUE;
                            ....
        
       4:    (* Write single text line *)
                            ...
    
    
        5:(* Wait until write not busy *)
            fbFilePuts( bExecute := FALSE, bError => bError, nErrID => nErrID );
            IF NOT fbFilePuts.bBusy THEN
                IF NOT fbFilePuts.bError 
    (*erst weiterschalten, wenn die 10ms abgelaufen sind*)
               AND startNewRowTON.Q
                THEN
    (*startNewRow zurücksetzten, weil sonst das Ton nicht mehr bei 0 startet*)
                    startNewRow := FALSE;
                    step := 3;(* Write next record *)
                ELSE(* Error *)
                    step := 100;
                END_IF
            END_IF
                           ...
    END_CASE
    Hoffe das hilft. Bei Fragen einfach fragen.
    Gruß
    wonderfulworld
    Solls was Rechtes sein, oder darfs auch was von Siemens sein?

  4. #4
    mv08 ist offline Benutzer
    Themenstarter
    Registriert seit
    22.03.2013
    Beiträge
    32
    Danke
    6
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Zitat Zitat von wonderfulworld Beitrag anzeigen
    Hoffe das hilft. Bei Fragen einfach fragen.
    Gruß
    wonderfulworld
    Hi,

    vielen Dank!
    Ich werde das nach meinem Urlaub direkt mal testen. Wenn noch Fragen sind, melde ich mich.

    LG,
    Dennis

  5. #5
    mv08 ist offline Benutzer
    Themenstarter
    Registriert seit
    22.03.2013
    Beiträge
    32
    Danke
    6
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Leider scheint der TON bei mir nicht zu greifen. Er rast einfach ohne 10s Pause durch die Schleifen:

    ganz oben:
    Code:
    startNewRowTON(IN:= startNewRow, PT:=t#10s , Q=> , ET=> );
    
    CASE step OF
    	0:	(* Wait for rising edge at bWrite variable *)
    .
    .
    .
    und im Code:
    Code:
    	5:(* Warten, wenn der Writer noch beschäftigt ist *)
    		fbFilePuts( bExecute := FALSE, bError => bError, nErrID => nErrID );
    		IF NOT fbFilePuts.bBusy THEN
    			IF NOT fbFilePuts.bError THEN
    			IF  zaehler < 10 THEN
    			startNewRow := TRUE;
    			(*erst weiterschalten, wenn die 10s abgelaufen sind*)
    	        		startNewRowTON.Q;
    			(*startNewRow zurücksetzten, weil sonst das Ton nicht mehr bei 0 startet*)
                    		startNewRow := FALSE;
    			zaehler := zaehler +1;
    			step := 4;
    			ELSE (*Fertig, jetzt Datei schließen*)
    				step := 10;
    			END_IF
    			ELSE(* Error *)
    				step := 100;
    			END_IF
    		END_IF
    Kannst du einen Fehler erkennen?

    Vielen Dank!
    Dennis

  6. #6
    Registriert seit
    18.10.2012
    Beiträge
    34
    Danke
    1
    Erhielt 1 Danke für 1 Beitrag

    Standard

    Code:
    IF  zaehler < 10 THEN
    	startNewRow := TRUE; 
    	startNewRowTON.Q;
               startNewRow := FALSE;
    ...
    Da ist dein Fehler, dein TON Aufruf ganz oben bekommt nie ein StartNewRow := TRUE da du die Variable in jedem Zyklus zwar auf True, aber direkt danach wieder auf False setzt. Den Sinn deiner Zähler-Variable verstehe ich auch nicht ganz!?
    Hätte jetzt erwartet, dass step := 10 durchgeführt wird sobald startNewRowTON.Q auf True geht oder?

  7. #7
    mv08 ist offline Benutzer
    Themenstarter
    Registriert seit
    22.03.2013
    Beiträge
    32
    Danke
    6
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Den Zähler kannst du ignorieren, der war nur zum Test drinnen, damit ich keine Schleife habe.
    Aber jetzt stehe ich mit dem TON an der Stelle auf dem Schlauch. Wie müsste denn der Quellcode aussehen, damit das TON funktioniert?

    Code:
    5:(* Warten, wenn der Writer noch beschäftigt ist *)
    		fbFilePuts( bExecute := FALSE, bError => bError, nErrID => nErrID );
    		IF NOT fbFilePuts.bBusy THEN
    			IF NOT fbFilePuts.bError THEN
    			IF  zaehler < 10 THEN
    			startNewRow := TRUE;
    			(*erst weiterschalten, wenn die 10s abgelaufen sind*)
    	        		startNewRowTON.Q;
    			(*startNewRow zurücksetzten, weil sonst das Ton nicht mehr bei 0 startet*)
                    		startNewRow := FALSE;
    			zaehler := zaehler +1;
    			step := 4;
    			ELSE (*Fertig, jetzt Datei schließen*)
    				step := 10;
    			END_IF
    			ELSE(* Error *)
    				step := 100;
    			END_IF
    		END_IF

  8. #8
    Registriert seit
    18.10.2012
    Beiträge
    34
    Danke
    1
    Erhielt 1 Danke für 1 Beitrag

    Standard

    so müsste es klappen
    Code:
    tonDelay(IN := xStartDelay, PT := T#10MS);
    xStartDelay := NOT tonDelay.Q;
    IF tonDelay.Q THEN
    	//Anweisungen, welche nach 10 sekunden erfolgen sollen
    END_IF

  9. Folgender Benutzer sagt Danke zu Mensetta für den nützlichen Beitrag:

    mv08 (03.07.2013)

  10. #9
    Registriert seit
    25.11.2010
    Ort
    OWL
    Beiträge
    750
    Danke
    27
    Erhielt 165 Danke für 143 Beiträge

    Standard

    Es muss heissen
    Code:
    IF startNewRowTON.Q
    THEN
       startNewRow:=FALSE;
       zaehler:=zaehler+1;
       step:=4;
    END_IF
    Und das
    Code:
    startNewRow:=TRUE;
    muss in Step 4.

  11. Folgender Benutzer sagt Danke zu StructuredTrash für den nützlichen Beitrag:

    mv08 (03.07.2013)

  12. #10
    mv08 ist offline Benutzer
    Themenstarter
    Registriert seit
    22.03.2013
    Beiträge
    32
    Danke
    6
    Erhielt 0 Danke für 0 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Danke Mensetta. Das hat wunderbar geklappt

Ähnliche Themen

  1. Antworten: 24
    Letzter Beitrag: 14.10.2016, 09:30
  2. CodeSys V3 Werte in CSV Datei Schreiben,Hilfe!
    Von Nitro-Haiza im Forum CODESYS und IEC61131
    Antworten: 0
    Letzter Beitrag: 19.09.2012, 11:17
  3. Globale Variablen von TwinCat PLC mit C# verbinden
    Von Hans_der_Kann`s im Forum CODESYS und IEC61131
    Antworten: 4
    Letzter Beitrag: 26.03.2012, 16:38
  4. Antworten: 15
    Letzter Beitrag: 14.02.2012, 08:26
  5. Antworten: 1
    Letzter Beitrag: 02.03.2009, 13:04

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •