# Codesys KOP Daten aufzeichnen



## winsterde (25 November 2021)

Guten Tag,

ich hab eine Frage über die ich mir heute schon den Kopf zerbrochen habe.
Könnte ich in Codesys mit der Programmiersprache KOP Daten aufzeichnen (in meinem Fall Temperaturwerte), z.B jede Minute einen Wert über einen Zeitraum von 2 Wochen, diese dann in eine z.B. csv Datei einbetten.  Wie könnte ich das am besten mit KOP umsetzen? Oder ist es überhaupt möglich?

Ich hoffe Ihr könnt mir helfen!

Vielen Dank schonmal!


----------



## holgermaik (25 November 2021)

KOP ist eine Programmiersprache und zeichnet keine Daten auf. Jede Funktion lässt sich in jeder Programmiersprache erstellen, in der einen besser in der anderen schlechter.
Grob überschlagen als DINT sind das 80kB die du irgendwo speichern musst. Sinnvollerweise in einem Datenfeld.
Ob deine Steuerung das kann ??


----------



## winsterde (25 November 2021)

Danke für deine Antwort schonmal. Ich hab mich vielleicht etwas blöd ausgedrückt. Das Ziel: In KOP eine Funktion zu erstellen, diese sollte die Messwerte dann automatisch in eine .csv Datei einbetten. Als Speicherplatz sollte eine SD-Karte in der Steuerung dienen. Nur leider weiß ich nicht wie ich diese Funktion in KOP umsetzen kann.


----------



## oliver.tonn (25 November 2021)

winsterde schrieb:


> Danke für deine Antwort schonmal. Ich hab mich vielleicht etwas blöd ausgedrückt. Das Ziel: In KOP eine Funktion zu erstellen, diese sollte die Messwerte dann automatisch in eine .csv Datei einbetten. Als Speicherplatz sollte eine SD-Karte in der Steuerung dienen. Nur leider weiß ich nicht wie ich diese Funktion in KOP umsetzen kann.


Darf ich einmal fragen warum ausgerechnet in KOP? Von allen verfügbaren Sprachen ist KOP für so etwas die schlechteste Wahl.


----------



## PN/DP (25 November 2021)

Schlechter geht immer  z.B. CFC wäre nun wirklich ganz total völlig ungeeignet...

Harald


----------



## oliver.tonn (25 November 2021)

PN/DP schrieb:


> Schlechter geht immer  z.B. CFC wäre nun wirklich ganz total völlig ungeeignet...
> 
> Harald


Ok, das hätte ich auf eine Ebene mit FUP gesetzt und über KOP.


----------



## winsterde (26 November 2021)

Okay, danke werde es mit ST probieren.


----------



## holgermaik (26 November 2021)

Gib dochmal deine Codesys Version und die Steuerung mit an.
csv Export macht nur Sinn wenn die Daten mit z.B. Excel weiterverarbeitet werden sollen.
Ein permanentes schreiben auf die SD zerstört diese.
Geneau Prüfen wie oft auf die SD geschieben werden muss.


----------



## winsterde (26 November 2021)

Die Steuerung ist von Wago 750-880. Arbeite mit Codesys V2.3. Genau dass sollte das Ziel sein, eine Auswertung über Excel. Nun bin ich aber etwas aufgeschmissen, weil noch nicht viel in ST programmiert habe.


----------



## holgermaik (26 November 2021)

Wo klemmt es denn?
an der Zusammenstellung der Daten oder dem Speichern?


----------



## winsterde (26 November 2021)

Soweit bin ich noch nicht.🙃Wie könnte ich diese Befehle am besten in ST umsetzen? Bin leider noch ziemlicher Anfänger in ST.


----------



## holgermaik (26 November 2021)

xAF_Temp := xAF;
xAF_TempR := xAF_Temp / 10.0 ;



oliver.tonn schrieb:


> Von allen verfügbaren Sprachen ist KOP für so etwas die schlechteste Wahl.





winsterde schrieb:


> weil noch nicht viel in ST programmiert habe.


die schlechteste Wahl ist meiner Meinung nach die Sprache die man nicht beherscht.

Wenn du KOP kannst versuche es damit. Evtl. dann einige Funktionen in ST für Berechnungen.


----------



## winsterde (26 November 2021)

Okay Vielen Dank. Eine gute Wahl ist es natürlich nicht. Ich werde es versuchen, ansonsten lese ich mich mal in ST ein.


----------



## Professor (26 November 2021)

Vielleicht hilft dir die EXECUTE Box, dann kannst du genau an den Stellen wo KOP gar nicht passen will ST verwenden.


----------



## winsterde (26 November 2021)

Okay, danke wäre auch eine Möglichkeit. Ich habe das jetzt mal so probiert, funktioniert aber leider nicht. Erkennt Ihr was das Problem sein könnte?


----------



## oliver.tonn (26 November 2021)

Deine IF-Abfrage sieht etwas seltsam aus, da fehlt was. Du musst auch angeben bei oder besser ab welchem Wert von xSF_TempSF der Teil in der IF-Abfrage ausgeführt werden soll.
Außerdem solltest Du Dir mal Beispiele zum Thema schreiben in Dateien ansehen, dass kann so nämlich auch nicht gehen.
Du musst die Bausteine (Datei öffnen/erstellen, Daten schreiben, Datei schließen) einzeln ausführen und deren Rückmeldung auswerten. Erst wenn diese jeweils melden, dass sie fertig sind darfst Du den nächsten Baustein ausführen.
Dafür solltest Du mit CASE eine Schrittkette bauen. In der Schrittkette aber nur die Eingänge der Bausteine setzen, den Aufruf bitte außerhalb.


----------



## winsterde (26 November 2021)

Okay, wenn ich alle Temperaturen möchte benötige ich ja keine IF-Abfrage oder?


----------



## oliver.tonn (26 November 2021)

Äh, wie alle Temperaturen? Die Variable enthält doch nur eine.


----------



## winsterde (26 November 2021)

Die Variable hat die Adresse eines Analogen Zugangs zugewiesen bekommen, an der ein Temperaturfühler angeschlossen ist.


----------



## oliver.tonn (26 November 2021)

OK, aber es geht um nur einen Temperaturwert, der in einem bestimmten Intervall aufgezeichnet werden soll?


----------



## winsterde (26 November 2021)

Ja, genau. Und alle Temperaturen. Dann benötige ich keinen IF-Befehl oder?


----------



## oliver.tonn (26 November 2021)

Nein, aber, wie gesagt, such Dir mal eine Doku zum Thema Schreiben in Dateien, hier im Forum ist das Thema auch schon öfters aufgetaucht, denn da machst Du einen großen Fehler. Die einzelnen Bausteine benötigen nämlich mehr als einen Zyklus.


----------



## winsterde (26 November 2021)

Okay, mach ich. Danke


----------



## Heinileini (26 November 2021)

Was soll denn 'WriteBuffer:=INT_TO_STRING;' machen? Welche INT-Variable soll in einen String gewandelt werden?


----------



## Oberchefe (26 November 2021)

Beispiel um etwas in eine Datei zu speichern:

```
(************************************************************************************************)
(*    Einstellungen abspeichern                                                                *)
(************************************************************************************************)

CASE stat OF

100:
        Filename:='SETTING.TXT';
        Mode:='w';
        stat:=101;
101:
        RGWW:=SysFileOpen(FileName, Mode);
        IF RGWW>0 THEN
            stat:=102;
        END_IF
102:
        BytesDone:=    SysFileWrite(RGWW, ADR(G_HMI), SIZEOF(G_HMI));
        IF BytesDone = SIZEOF(G_HMI) THEN
                stat:=103;
        END_IF
103:
        SysFileClose(RGWW);
        Stat:=    104;
```


----------



## winsterde (26 November 2021)

PROGRAM PLC_PRG
VAR
    xAF_Temp: REAL;
    xAF: INT;
    xAF_TempR: REAL;
    iStat: INT;
    FileName: STRING:= 'D:';
    Mode: STRING;
    SysFileOpenNum: DWORD;
    DwWritten: DWORD;

END_VAR



CASE iStat OF
100:
        xAF_Temp := xAF;
        xAF_TempR := xAF_Temp / 10.0 ;
        iStat:= 101;
101:
        FileName:='Temperatur.csv';
        Mode:='w';
        iStat:=102;
102:
        SysFileOpenNum:=SysFileOpen(FileName, Mode);
        iStat:=102;

103:
        DwWritten:= SysFileWrite(RGWW, ADR(str_Temperatur), SIZEOF(str_Temperatur));


        END_CASE



Vielen Dank für eure Hilfe!
Mir wird "SysFileOpen" und "SysFileWrite" nicht als Befehl deklariert. Zudem benötigt SysFileOpen noch einen 3en Eingang?
Kann es sein das mir ein Paket aus der Bibliothek fehlt?


----------



## Oberchefe (26 November 2021)

Du brauchst die SysLibFile.


----------



## winsterde (26 November 2021)

Die finde ich in der Bibliothek nicht. Hast du einen Tipp wo ich die herbekomme?


----------



## Oberchefe (26 November 2021)

> Die finde ich in der Bibliothek nicht.


Das ist ja auch eine eigene Bibliothek.

"Fenster", "Bibliotheksverwaltung", Rechtsklick an markierter Stelle, "Weitere Bibliothek", dann SysLibFile auswählen


----------



## winsterde (7 Dezember 2021)

Vielen Dank, du hast mir sehr geholfen!
Mein Programm ist soweit fertig. Ich habe dennoch ein kleines Problem und finde keine Lösung.
Ich möchte in die csv Datei, eine Spalte mit Datum und Uhrzeit und eine Spalte mit der Temperatur. Funktioniert so weit auch alles, aber
ich bekomme immer 3 Spalten ausgegeben. Die erst Spalte ist ein abgeschnittenes Datum, die zweite Spalte, das ganze Datum und die dritte Spalte die Temperatur. Im ersten Durchgang des Programms passt alles. Im zweiten-00 habe ich immer 3 Spalten. Ich komme nicht drauf, woran es liegen könnte.
Vielleicht habt Ihr eine Idee?
Code und csv Datei hänge ich an.


----------



## JSEngineering (7 Dezember 2021)

Moin Winsterde,

ganz spontan habe ich auch keine Idee, allerdings mehrere Dinge, die mir auffallen:

Programmierstil:
Bitte nutze beim Programmieren Tabulatoren zum Einrücken... In #25 siehst Du, wie schön übersichtlich ein CASE aufgebaut sein kann.
Ich würde nicht jeden kleinen Teil einzeln in die Datei schreiben, Schreibvorgänge kosten viel Zeit. Erst eine komplette Zeile zusammenbauen und dann in einem Rutsch wegschreiben. Zumal SysFileWrite eine blockierende Funktion ist: Das SPS-Programm hält an, so lange die Daten geschrieben werden. Dein Prozeß hält also an!
Was machst Du, falls mal nicht alle Bytes geschrieben wurden (Datenträger voll?), dann bleibst Du in der Schleife hängen und kannst nur die SPS neu starten.

Ausgabe:
Warum hast Du so viel Abstand in den Spalten? Eigentlich müßte die Temperatur direkt hinter dem Semikolon stehen.
In der ersten Spalte stehen Zeitstempel von vor 10 bzw. 3 Sekunden!?

Wichtig wäre nochmal zu sehen, Deine Variablendeklarationen und der FileMode, den Du nutzt.

Du kannst Dir die Strings beim Debuggen ja mal online ansehen. Zumal, wenn Du eine komplette Zeile zusammenbaust.

Gruß
   Jens


----------



## winsterde (7 Dezember 2021)

Danke für deine Tipps. Ich habe Ablauf 3 u. 4 zusammengefasst. Geändert hat sich leider nichts. Warum Zeiten teils 10 Sekunden zurückliegen, frage ich mich auch. Vielleicht der Zeitpunkt, indem ich mich in die SPS einlogge bzw. das Programm drauf schreibe. 
Ich wollte erst mal den Grundbaustein legen. Und Probleme die, während dem Betrieb auftreten könnten, angehen, sodass die SPS nicht mitten im Programm stehen bleibt.
Anbei noch die Variabeln.


----------



## holgermaik (7 Dezember 2021)

Bei CS2.3 wurde ein String ohne Längenangabe mit einer definierten Zeichenanzahl erzeugt( ich glaub es waren 80, weiß es aber nicht mehr genau)


----------



## oliver.tonn (7 Dezember 2021)

holgermaik schrieb:


> Bei CS2.3 wurde ein String ohne Längenangabe mit einer definierten Zeichenanzahl erzeugt( ich glaub es waren 80, weiß es aber nicht mehr genau)


Ja, und das ist bei CS3.5 und Derivaten auch noch so.


----------



## JSEngineering (7 Dezember 2021)

Ich glaube, ich sehe was passiert:
Du ermittelst die zu schreibende Länge per SIZEOF: Die gibt Dir die Größe der Variablen zurück, nicht die Länge vom String.
Bitte nutze LEN, um die Stringlänge zu ermitteln.


----------



## winsterde (7 Dezember 2021)

Ich habe das Problem gefunden.. Aber keine Lösung dafür. Sobald WriteDate := DT_TO_STRING(ActTimeRTC) wird automatisch in die CSV datei geschrieben, aber total sinnfreie Zeiten. Wie kann ich das Lösen?


----------



## winsterde (7 Dezember 2021)

Okay, ich Probiere es mal aus. Danke


----------



## winsterde (7 Dezember 2021)

#JSEngineering, dass war die Lösung! Vielen Dank euch!


----------



## winsterde (7 Dezember 2021)

Ich hätte noch eine kurze Frage. 
Ich möchte noch einen CTD Counter programmieren. Dieser sollte pro Ablaufzyklus herunterzählen. Wie gehe ich da am besten vor?
Wie kann ich das programmieren. Eingangssignale habe ich ja keine.
Hoffe Ihr könnt mir helfen!


----------



## oliver.tonn (7 Dezember 2021)

Der Zähler zählt ja bei einer steigenden Flanke um eins herunter. Du musst jetzt also dafür sorgen, dass der Zähler FB in jedem Ablaufzyklus eine steigende Flanke sieht, z.B. in dem Du ihn zweimal nacheinander aufrufst. Einmal mit CD = TRUE und einmal mit CD = FALSE, oder umgekehrt, geht auch und dann hat er in dem Durchlauf sicher eine steigende Flanke.


----------



## winsterde (7 Dezember 2021)

Ich versuche gerade einen Ton Timer zu Programmieren, der Bsp. nach 60 Sekunden auf eine Variable vom Typ Bool springt und damit das Programm sozusagen stoppt. Solange der Timer aber von 60 sek runterzählt, soll das Programm weiterlaufen.

Dafür habe ich:

xTIme_END (xTime_END.IN, xTime_END.Q, PT:=T#60s);
IF xTime_END.IN THEN iState:=4;
IF xTime_END.Q THEN iState:=0;

Funktioniert aber nicht beziehungsweise bekomme ein Fehler angezeigt. Wie kann man das noch lösen?


----------



## oliver.tonn (7 Dezember 2021)

Lies Dir bitte in der Codesys Hilfe den Teil mit den Timern durch, Dein Aufruf ist nämlich völlig falsch. Ein Fehler ist die Verwendung Variablen IN und Q der Timer-Instanz im Aufruf.
Was soll dieses Konstrukt überhaupt bewirken, z.B. die IF-Abfragen darunter?


----------



## winsterde (7 Dezember 2021)

Ich möchte im Grunde, dass während der Timer herunterzählt das Programm weiterläuft. Sobald die Zeit abgelaufen ist, dass Programm beendet wird. Ist das so mit einem TON Timer überhaupt möglich?


----------



## Heinileini (7 Dezember 2021)

Wie sieht das EingangsSignal des Timers aus?
Ist sichergestellt, dass mit Ablauf des Timers der Eingang wieder auf 0 wechselt?
Sonst geht iState wieder auf 4, nachdem es einen Zyklus lang auf 0 gezerrt wurde.
ProgrammDarfLaufen := IN AND NOT Q ;


----------



## winsterde (7 Dezember 2021)

Und wie könnte ich das Programmieren?
Momentaner Stand:
xTime_END (IN:=NOT xTime_END.Q, PT:=T#60s);
IF xTime_END.Q THEN
iState:=4;
Hier wartet er 60 Sekunden und geht dann weiter zu 4: er sollte aber weiterlaufen und nach 60 Sekunden zu 0 wechseln (Anweisung fehtl noch).


----------



## Heinileini (7 Dezember 2021)

Wodurch soll Dein TON gestartet werden? So, wie Du es jetzt hast, wird der Timer immer wieder neu gestartet, sobald er abgelaufen ist. Ist das beabsichtigt?



winsterde schrieb:


> xTime_END (IN:=NOT xTime_END.Q, PT:=T#60s);
> IF xTime_END.Q THEN
> iState:=4;


Evtl. tauschen:

```
IF xTime_END.Q THEN iState:=4;
xTime_END (IN:=NOT xTime_END.Q, PT:=T#60s);
// bzw.
bHilfsVariable := xTime_END.Q ;
xTime_END (IN:=NOT bHilfsVariable, PT:=T#60s);
IF bHilfsVariable THEN iState:=4;
```


----------



## winsterde (7 Dezember 2021)

Genau. Das Ziel sollte sein: Timer zählt runter Programm läuft weiter und zeichnet Temperaturwerte auf. Timer wird auf ca. 1 Woche eingestellt. Wenn der Timer abgelaufen ist, sollte durch eine Variable vom Typ Bool Bsp. ein Schalter das Programm gestoppt werden.


----------



## JSEngineering (7 Dezember 2021)

```
StartTrigger : BOOL --> Wird z.B. durch HMI gesetzt

TOF(IN := StartTrigger, PT:=t#7d);    // Schaltet die Aufzeichnung frei
StartTrigger := False;

TON(NOT TON.Q, PT:=t#1s);            // Triggert die Aufzeichnung

...

CASE step OF

0:    IF TOF.Q AND TON.Q THEN            // Zeichnet auf, wenn Aufzeichnung freigegeben und Trigger aktiv
        step := step + 1;
    END_IF
1:    ...

END_CASE
```


----------



## winsterde (7 Dezember 2021)

Fehlermeldung "TOF ist keine Funktion "


----------



## winsterde (7 Dezember 2021)

Die IF Abfrage habe ich mit IF TON.Q AND TOF.Q bereits "TON" ist keine Funktion und bei Zeile 6 wird eine Bezeichnung erwartet.


----------



## JSEngineering (7 Dezember 2021)

xTime muß von Dir als TON deklariert sein (kann ich nicht sehen). Und dann mußt Du natürlich in Zeile6 das NOT TON.Q durch NOT xTime.Q ersetzen.

In Zeile 11 mußt Du xTime.Q und xTime_END.Q verwenden.


----------



## winsterde (7 Dezember 2021)

Ja natürlich stimmt.. VIleen Dank!


----------

