# Zeitmessung im us bereich #Hilfe bei SysTimeGetUs()



## CodeSysStarter (28 November 2017)

Moin Ich schlage mich seit einer Woche mit einem Problem rum.

Ich möchte eine Zeitmessung machen. Messe Systemzeit an Punkt A und an Punkt B. Die Differenz ergibt die Laufzeit.
Soweit so gut. 

In meinem Programm habe Ich mit* SysTimeGetMs(*) aus der SysTimeCore bereits eine Funktionierende aber nicht ausreichende Zeitmessung implementiert.
Jetzt möchte Ich *SysTimeGetUs() *verwenden und habe keine Idee wie ich mit dier funktion umgehen soll.
 Im speziellen wie müssen die Pramameter übergeben werden. Welche Parameter müssen über geben werden?

Ich verwende Codesys 3.5 Patch 2 und alles soll erstmal auf dem Imulator laufen.

ICh bin für jede Hilfe Dankbar.

mfg CodeSysStarter


----------



## _Eddi_ (28 November 2017)

Also soweit ich Dokumentation dazu gefunden habe (Google ist da nicht besonders hiflreich): SysTimeGetUs bekommt als in/out-Parameter die Variable, in der die Zeit gespeichert werden soll, und gibt als Rückgabewert einen Fehlercode.


----------



## weißnix_ (28 November 2017)

Ist den die messende Task schnell genug für die Genauigkeitsanforderung?


----------



## CodeSysStarter (28 November 2017)

weißnix_ schrieb:


> Ist den die messende Task schnell genug für die Genauigkeitsanforderung?



Also die zeitdifferenz ist im normalen durchlauf gleich 0 im debug moduss nicht. scheint also zu funktionieren. die übergabe Variable sind ihrgend wie auch pointer oder timer pointer das versteh ich gerade garnicht. Ein kleines Code Beispiel wäre sehr hilfreich


----------



## CodeSysStarter (28 November 2017)

Ja also ich hatte das mal porbiert wie folgt:

VAR
t1: TIMER;
END_VAR

___________________________

fehler := SysTimeGetUs(ADR (t1));

dabei wirft der kompiler mir aber vor das Ich einen wert mit schreibzugriff über geben muss


----------



## weißnix_ (28 November 2017)

Du musst mal nachsehen, welche Datentypen die Funktion haben möchte.
Ichkenne die Funktion nicht, habe hier aber ein Beispiel mit deren Anwendung+ Variablendeklaration gefunden. Gemessen wird hier eine Codeausführungszeit.


----------



## HausSPSler (29 November 2017)

Hi 
so:

1. SysTime library im Bibliotheksmanager hinzu
2. Dekalration:


```
VAR
 dwTime: DWORD;
 st1, st2: SysTime;
 std: SysTimeDate;
 TimeStamp: SYSTIME;
 i: DINT;
 diValue1: DINT:=10000;
 diCounter: DINT;
 nState: INT;
END_VAR
```

Implementierung:


```
SysTimeGetUs(st1);
 
//code to measure
FOR i:=1 TO diValue1 DO
 diCounter:=diCounter+1;
END_FOR
 

SysTimeGetUs(st2);
dwTime := ANY_TO_DWORD(st2 - st1);
```

Grüße


----------



## CodeSysStarter (29 November 2017)

Danke für die Unterstüzung,
@weißnix_ und @Edwin:

Danke für die grandiose Hilfe:
Der gebene Link war Super hilfreich und das Code Bsp noch viel mehr.
Ich hatte erwarteet das Codesys alle Projekt bekannten Datentypen farblich hervorhebt ,aber das war wohl mein Trugschluss.
Aufjedenfall läuft es jetzt. 

Danke für die schnelle und kompetente Unterstüzung


----------



## PAHO (1 August 2021)

Hallo zusammen,

es ist zwar schon eine Zeit lang her, als dieser Thread eröffnet wurde, aber kann hier nicht ein Überlauf bei der Berechnung der Differenz entstehen, also die Startzeit < Endzeit? Zugegeben, wir haben einen 32 bit Wert... aber ich weiß nicht wo weggezählt wird.
Meine Bedürfnisse sind zwar nur im ms-Bereich, aber theoretisch ist das doch möglich?

LG, PAHO


----------



## Heinileini (1 August 2021)

PAHO schrieb:


> Zugegeben, wir haben einen 32 bit Wert... aber ich weiß nicht wo weggezählt wird.


Doch! Beim 1. Einlesen der Zeit liest Du den Wert "wo weggezählt wird".
Und von dem beim 2. Einlesen eingelesenen Wert ziehst Du den "wo weggezählt wordenen" Wert ab.
Die Wahrscheinlichkeit, dass das 1. Einlesen direkt vor dem Überlauf stattfindet und das 2. direkt danach ist zwar klein, aber durchaus nicht 0.
Das ist aber kein Grund zur Panik. Wenn Du z.B. von 1 (beim 2. Einlesen) eine -1 (beim 1. Einlesen) abziehst, ist das Ergebnis - oh Wunder - 2, also völlig korrekt.


----------



## PAHO (3 August 2021)

Ok, da ich eine etwas andere Anforderung habe (Laufzeitmessung von z.B. Stellantrieben), wird der 1. Wert bei mir über viele Zyklen gespeichert. Genauer gesagt, vom Startzeitpunkt der Bewegung des Antriebes bis zum Ende der Bewegung.

Ich verwende Codesys mit einem Revpi Connect+ und habe nun einen eigenen "Time-Task" mit einer Zykluszeit von 100us angelegt. Dort Zählt mir ebenfalls ein 32bit-Wert mit dem Programmdurchlauf hoch bzw. runter. Meinen ersten Test nach dürfte das ganz brauchbar sein. Da ich aus der Sparte Mikrocontroller komme und dort mit eigenen Interrupts von Timern der Controller gearbeitet habe, ist das hier ein wenig anders.

Könnte das Zählen mit dem Programmzyklus ein Problem werden? Meine Auflösung ist nicht sehr hoch - komme normal mit 100ms Schritten aus.

LG, PAHO


----------



## PN/DP (3 August 2021)

Dein letzter Beitrag verwirrt mehr als das er aufklärt...
Wie lang sind die Zeiten die Du messen willst und mit welcher Auflösung brauchst Du die? Kann es passieren daß während einer Zeitmessung die SPS AUS oder in STOP ist?

Harald


----------



## Heinileini (3 August 2021)

PN/DP schrieb:


> Wie lang sind die Zeiten die Du messen willst ...?


Genau! Ich hatte die Aufgabenstellung eigentlich so verstanden, dass Anfang und Ende der MessPeriode im selben Zyklus (oder zwei aufeinander folgenden Zyklen) liegen.
Können innerhalb der MessPeriode mehr als ein (eigentlich ein "halber") Überlauf stattfinden? Aber ich möchte Harald nicht vorgreifen. Er kann so perfekt beschreiben, dass auch dieser Fall leicht beherrschbar ist.


----------



## PAHO (3 August 2021)

Vorweg mal danke für die Antworten! Da ich bei meiner Suche nach Zeitmessungen auf diesen Thread gestoßen bin, habe ich nicht bedacht dass meine Anforderung etwas abweicht...

Die Anforderung ist: Laufzeitmessung von Stellantrieben in Millisekunden mit Prozentberechnung der aktuellen Öffnung. Ich möchte also mitzählen, wie lange der Stellantrieb bei Signale "Öffnen" und Schließen" läuft. Öffnen natürlich hochzählen und Schließen runterzählen. Grenzwerte sind die von mir vorgegebene Gesamtlaufzeit in Millisekunden -> z.B. 150 Sekunden Laufzeit = 150000ms = 100%.

Bei der SysTime dachte ich mir eben, weil ich ja über X-Zyklen die Zeit messe, dass ein Überlauf sehr wohl stattfinden könnte und die Berechnung dann komplett falsch ist. Da müsste ich den Überlauf erkennen und ebenfalls in die Berechnung einbinden.
Jetzt dachte ich mir, ich lege einen Task an welcher mit einer definierten Zykluszeit von 100us läuft, zähle mit einem Byte bis 10 und lasse dann meinen Millisekunden-INT32 hoch bzw. runterzählen, welcher dann die tatsächliche Laufzeit darstellt.

Grundsätzlich funktioniert das auch recht gut beim simulieren - aber ich weiß eben nicht ob diese Zykluszeiten grundsätzlich eingehalten werden, oder ob man doch eher auf SysTime ausweichen sollte.

Danke und LG!


----------



## winnman (3 August 2021)

Für die Messung der Zykluszeit gibt es hier einige Beispiele.

Wenn Ausgang gesetzt ist, merkst du dir das für den nächsten Zyklus (DB, . . .)
am Zyklusanfang merkst du dir die Zykluszeit vom letzten Zyklus

Am Anfang deines aktuellen Zyklus addierst du einfach die Zykluszeit vom letzten Zyklus wenn der Ausgang gesetzt war.
Danach den Ausgangsmerker (DB, . . .) zurücksetzen

danach erst dein reguläres Programm aufrufen.


----------



## PN/DP (3 August 2021)

PAHO schrieb:


> Jetzt dachte ich mir, ich lege einen Task an welcher mit einer definierten Zykluszeit von 100us läuft, zähle mit einem Byte bis 10 und lasse dann meinen Millisekunden-INT32 hoch bzw. runterzählen, welcher dann die tatsächliche Laufzeit darstellt.


Was soll das bringen, eine Task von 100µs zu verwenden, wenn Du nur ganze Millisekunden zählen willst/brauchst? Da kannst Du auch direkt in einer 1ms Task zählen.

Bei der Schließzeit mußt Du nicht rückwärts zählen, Du kannst auch den skalierten %-Wert von 100% abziehen.



PAHO schrieb:


> Bei der SysTime dachte ich mir eben, weil ich ja über X-Zyklen die Zeit messe, dass ein Überlauf sehr wohl stattfinden könnte und die Berechnung dann komplett falsch ist. Da müsste ich den Überlauf erkennen und ebenfalls in die Berechnung einbinden.


Da brauchst Du nichts besonderes beachten. Mit einem Millisekunden-INT32-Zähler kannst Du ohne weiteren Aufwand Zeiten bis ca 596 Stunden (ca. 24,8 Tage) messen mit einer Auflösung von 1 ms (mit ein bisschen mehr Programmierung doppelt so lange). Du brauchst auch nicht den Zählerstand beim Mess-Start auf 0 setzen, sondern kannst den Zähler frei laufen lassen und Dir nur den Zählerstand_Start merken. Es ist egal ob während der Messung ein 32-Bit-Überlauf stattfindet, weil bei einem reinen Vorwärtszähler dank des genialen Zweierkomplements die Differenz "Zählerstand_Ende - Zählerstand_Start" immer die korrekte positive Differenz ist, solange die Zeitdifferenz kleiner als der halbe Zählumfang (die 24,8 Tage) ist. Wenn es in der CPU schon einen 32 Bit Systemzeitzähler der Millisekunden gibt, dann würde ich den direkt verwenden.

Harald


----------



## Oberchefe (3 August 2021)

Wenn da in jedem Zyklus eine gerundete ms Zeit dazu gezählt bzw. abgezogen wird, kann sich ein zusätzlicher Fehler aufsummieren, ich würde daher eher die Zeit messen solange die Ansteuerung dauert.

`tonOeffnen: TON;
    tonSchliessen: TON;
    tOeffnungMem : TIME;
    tOeffnungTotal : TIME;
    bSchliesst: BOOL;
    bOeffnet: BOOL;`

`IF NOT bOeffnet AND tonOeffnen.ET > T#0ms THEN
    tOeffnungMem:=tOeffnungMem+tonOeffnen.ET;
END_IF;
IF NOT bSchliesst AND tonSchliessen.ET > T#0ms THEN
    tOeffnungMem:=tOeffnungMem-tonSchliessen.ET;
END_IF;
tOeffnungTotal:=tOeffnungMem+tonOeffnen.ET-tonSchliessen.ET;

tonOeffnen(IN:=bOeffnet , PT:=T#5d , Q=> , ET=> );
tonSchliessen(IN:=bSchliesst,PT:=T#5d,Q=> ,ET=>);`

Das geht mit einem ganz normalen Timer. Bleibt das Problem, dass bei jeder Signalzustandsänderung auch ein Rundungsfehler passiert und sich aufsummieren kann. Desweiteren ist das Ding irgendwann ganz offen oder geschlossen. Wie wird das erkannt? Hat das Ding Endschalter die abgefragt werden können um ggf. die Zeit auf Min bzw. Max zu setzen?


----------



## holgermaik (4 August 2021)

Hallo Paho
Das genaueste Ergebnis liefert das Auslesen der Systemzeit.
Die IEC Timer sind immer an die Tasklaufzeit gebunden.
.
PS
Die tatsächliche Laufzeit deines Stellantriebes ist allerding von viel mehr als das setzen einer Variable abhängig.
Dazu kommen Buslaufzeiten, Ansprechzeiten der I/O Karten, Reaktionszeiten der Relais/Schütze sowie mechanische Verzögerungen (Getriebe, Reibung...)
Du solltest dir viel mehr Gedanken darüber machen wie du deine Positionen syncronisierst als der letzten ms hinterher zu laufen.
Es wird immer eine Diskrepanz zwischen Soll- und Istposition bei reiner theoretischen Betrachtung geben.


----------



## Oberchefe (5 August 2021)

> Die IEC Timer sind immer an die Tasklaufzeit gebunden.


Genau wie die Ansteuerung der Stellmotoren. Abgesehen davon wird für die IEC Timer ebenfalls auf die Systemzeit zugegriffen


----------



## holgermaik (6 August 2021)

Oberchefe schrieb:


> Abgesehen davon wird für die IEC Timer ebenfalls auf die Systemzeit zugegriffen


prinzipiell JA aber hier wird die Zeit beim Eintritt in die Task genommen und nicht aktualisiert. Darum kann ein IEC Timer auch nur vielfaches der Taskzeit annehmen, dafür sind aber Zustände im Zyklus konsistent.


----------

