Laden...

Präzise Zeispanne warten mit Stopwatch und Task

Erstellt von ill_son vor 2 Jahren Letzter Beitrag vor 2 Jahren 619 Views
I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren
Präzise Zeispanne warten mit Stopwatch und Task

Hallo,

ich habe folgende Frage. Ich arbeite mit einem Drucksensor, der über Modbus arbeitet und der keinen eigenen Takt hat, sondern ständig gepollt werden muss. Sowohl für die Kommunikation als auch für den Abfragetakt hätte ich gern eine präzise Delay-Funktion, wobei ich festgestellt hab, dass Task.Delay nicht reicht. Wenn ich das richtig recherchiert habe, sind da etwa 15ms Unschärfe drin.

Ich habe folgendes versucht, was auch funktioniert nach meinem Dafürhalten. Ich möchte gern wissen, ob man das so machen kann oder ob das besser geht und wenn ja, wie.


public Task WaitPrecisely(int milliSeconds)
{
    return Task.Run(() =>
    {
        Stopwatch sw = new();
        sw.Start();
        while (sw.ElapsedMilliseconds < milliSeconds) { }
        sw.Stop();
     });
}

Danke und Grüße, Alex

Final no hay nada más

16.833 Beiträge seit 2008
vor 2 Jahren

Unter einem Nicht-Echtzeitsystem hast Du keine Chance sowas mit exakten Abtastraten im Millisekunden-Bereich zu bewerkstelligen.
Die Unschärfen kommen vom Betriebssystem.

Die Resolution von Windows sind 15.6ms; ergibt sich aus 64 Timer Aktivitäten pro Sekunde.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Hallo Abt,

danke für deine Antwort. Wie gesagt, mit der oben gezeigten Lösung funktioniert es. Meine Frage ist eher, ob man das so machen kann. Stichwort: best practice, anti pattern usw. Vor allem mit Blick auf die leere while-Schleife.

Final no hay nada más

16.833 Beiträge seit 2008
vor 2 Jahren

Es gibt keinen Weg, der Dir ein garantiertes Verhalten liefert.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Ich dachte bis jetzt, dass die Auflösung bzw. Genauigkeit der StopWatch Klasse besser sei als die oben genannten 15ms.

Final no hay nada más

16.833 Beiträge seit 2008
vor 2 Jahren

Das geht so lange, bis Dein System mal Last hat.
Mit Last hast Du bei so einer Sache immer ein anderes Verhalten: weil keine Echtzeitgarantie.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Das hatte ich so nicht auf dem Schirm. Ich dachte nur: geht, prima. Sind die 15,6 ms irgendwie sicher, oder kann das auch schlechter werden, wenn der Rechner zu tun hat?

Final no hay nada más

16.833 Beiträge seit 2008
vor 2 Jahren

Wie gesagt; Windows ist kein Echtzeitsystem.
Du hast niemals Ausführungsgarantien.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Danke für deine Rat.

Final no hay nada más

T
2.224 Beiträge seit 2008
vor 2 Jahren

Neben dem OS spielt hier auch die Software eine Rolle.
.NET ist keine Echtzeit Laufzeitumgebung bzw. ist dies nicht die primäre Zielgruppe für die Platform.

Für solche Verarbeitungen braucht man eher Systemnahe Programmiersprachen wie C/C++ die dann auch auf einem Echtzeitsystem die Abläufe zeitlich garantieren können.
Je nachdem was du hier machst, könntest du mit einem Linux mit Echtzeit Kernel und mit einem entsprechenden C/C++ Programm oder ggf. schon mit einem fertigen Tool dein Problem lösen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.833 Beiträge seit 2008
vor 2 Jahren

.NET ist keine Echtzeit Laufzeitumgebung bzw. ist dies nicht die primäre Zielgruppe für die Platform.

Das ist so nicht korrekt.

.NET kann durchaus in Real Time Szenarien verwendet werden, und hat auch eine Zielgruppe dafür, zB. in Form des Nano Frameworks für Microcontroller und IoT Szenarien.
Real Time ist dann etwas, wenn die Umgebung - meist dann das RTOS (Real Time OS) - das überhaupt unterstützt.

Auch C/C++ hilft Dir nicht, wenn das OS nicht RT-fähig ist.

T
2.224 Beiträge seit 2008
vor 2 Jahren

@Abt
Wusste nicht, dass es das gibt.
Macht die Umsetzung dann natürlich einfacher.

Der hinweis mit C/C++ bezieht sich ja extra auf ein Echtzeit OS.
Klar, dass es ohne passendes System auch nicht Echtzeit ist 🙂

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

4.939 Beiträge seit 2008
vor 2 Jahren

Hallo ill_son,

deine Schleife


while (sw.ElapsedMilliseconds < milliSeconds) { }

ergibt doch schon 100% Last auf einem Prozessorkern. Du mußt mindestens ein Sleep(0) bzw. Delay(0) einbauen, damit der Task (Thread) entlastet wird (s.a. The usages and suggestions about Thead.Sleep(0),Task.Delay(0),Thread.Yield(),Task.Yield()).

S
248 Beiträge seit 2008
vor 2 Jahren

Auch wenn du keine Echtzeit erreichen kannst, ist es trotzdem möglich die Auflösung der System-clock feiner einzustellen, siehe:
How to set timer resolution to 0.5ms
How to setup timer resolution to 0.5 ms?
Clockres

Grüße
spooky

16.833 Beiträge seit 2008
vor 2 Jahren

Spook, wenn Du Dir durchliest, wie der Timer unter Windows hier funktioniert, ist 0.5ms trotzdem eher theoretischer Natur und hängt extrem von der Hardware drunter ab.
Das ist halt nicht aushebelbar.

2.079 Beiträge seit 2012
vor 2 Jahren

Ergänzend zu Th69:

Warum nicht direkt Sleep(milliSeconds) bzw. Delay(milliSeconds)
Ist auch nicht exakt, aber weniger Code und arbeitet nicht mit solchen Krücken.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Hallo ill_son,

deine Schleife

  
while (sw.ElapsedMilliseconds < milliSeconds) { }  
  

ergibt doch schon 100% Last auf einem Prozessorkern. Du mußt mindestens ein Sleep(0) bzw. Delay(0) einbauen, damit der Task (Thread) entlastet wird (s.a.
>
).

In die Richtung zielte meine Frage. Die leere Schleife hat mir auch nicht gefallen. Die Links sind sehr aufschlussreich.

Warum nicht direkt Sleep(milliSeconds) bzw. Delay(milliSeconds)
Ist auch nicht exakt, aber weniger Code und arbeitet nicht mit solchen Krücken.

Das hatte ich probiert, war mir aber zu ungenau. Mit meiner Krücke ging es erst mal. Deshalb hier die Frage, ob das "sauber" ist.

Final no hay nada más

S
248 Beiträge seit 2008
vor 2 Jahren

Hallo Abt,

mir ist bewusst, dass man 0.5ms nicht zu 100% erreichen kann ... dies waren eben die ersten sinnvollen Google-Treffer wenn man nach der verwendeten Win-API Funktion gesucht hat. Es sollte lediglich den TE auf diese Option hinweisen.

Hallo ill_son,

vielleicht wäre es besser anstatt eines Sleep Ansatzs einen Timer zu verwenden.

Ich vermute einfach mal frech, dass du deinen Sensor immer im selben Takt abfragen möchtest. Da würde ein Timer, der in regelmäßigen Intervallen auslöst, vermutlich passen.
Da du eine hohe Präzision möchtest, würde ich dir den Multimedia-Timer empfehlen. (Es gibt auch andere Implementierungen im Netz, falls diese nicht zusagt). Dort kannst du die gewünschte Auflösung in ms angeben.
(Ja auch hier wirst du nicht auf die ns genau sein, aber besser als Sleeps oder Spin-Locks).

Grüße
spooky

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Ja, aller 100ms. Der verlinke Multimedia Timer ist leider für NET Core, ich hab hier noch .NET Framework. Habe bei Code Project aber was passendes gefunden. Danke für den Tipp.

Final no hay nada más

190 Beiträge seit 2012
vor 2 Jahren

Hallo,

nur um das Problem besser zu verstehen, welche Betriebsart hat der Modbus? An welcher Stelle brauchst du diese Genauigkeit?

  • Wer lesen kann, ist klar im Vorteil
  • Meistens sitzt der Fehler vorm Monitor
  • "Geht nicht" ist keine Fehlermeldung!
  • "Ich kann programmieren" != "Ich habe den Code bei Google gefunden"

GidF

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Hallo Wilfried,

der Sensor redet binär über RS485, das müsste dann RTU sein. Mir war es wichtig, eine genauere Zeitbasis zum Samplen zu haben. Ich hab 100ms Samplezeit, da waren mir die oben erwähnten 15ms Unschärfe zu viel.

Final no hay nada más

S
248 Beiträge seit 2008
vor 2 Jahren

Der verlinke Multimedia Timer ist leider für NET Core, ich hab hier noch .NET Framework.

Der Quellcode ist mit sehr sehr großer Wahrscheinlichkeit 1:1 .NET Framework kompatibel, da er fast identisch aussieht wie The Multimedia Timer for the .NET Framework.

190 Beiträge seit 2012
vor 2 Jahren

Ah ok,

dir geht es also darum, zu einem genau festgelegten Zeitpunkt den Messwert zu lesen.
Da würde ich zwei Lösungswege sehen.
Möglichkeit eins wäre die Softwarelösung. Da müsste man mit den bekannten Problemen leben. Ein normaler Büro-PC hat nun mal meistens andere Aufgaben. Man kann vielleicht an manchen Stellen noch schrauben, aber sicher kann man sich nie sein.
Möglichkeit zwei wäre eine Lösung mit externem Mikrocontroller. (z.B. Arduino Nano) Natürlich viel größerer Aufwand, aber man hat die volle Kontrolle. Der Controller puffert die Daten und der PC holt sie irgendwann ab.
Welche Variante die bessere ist, musst du entscheiden. Wenn die Daten nur für dich sind und du mit den Ungenauigkeiten leben kann, dann Variante eins.

  • Wer lesen kann, ist klar im Vorteil
  • Meistens sitzt der Fehler vorm Monitor
  • "Geht nicht" ist keine Fehlermeldung!
  • "Ich kann programmieren" != "Ich habe den Code bei Google gefunden"

GidF

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Der verlinke Multimedia Timer ist leider für NET Core, ich hab hier noch .NET Framework.

Der Quellcode ist mit sehr sehr großer Wahrscheinlichkeit 1:1 .NET Framework kompatibel, da er fast identisch aussieht wie
>
.

Danke. Den Link meinte ich, als ich schrieb, ich hätte was passendes gefunden.

Final no hay nada más

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 2 Jahren

Möglichkeit zwei wäre eine Lösung mit externem Mikrocontroller. (z.B. Arduino Nano) Natürlich viel größerer Aufwand, aber man hat die volle Kontrolle. Der Controller puffert die Daten und der PC holt sie irgendwann ab.

Das ist leider keine Option. Der Sensor kommt fertig mit Konverter und wird in großer Zahl im Feld eingesetzt.

Final no hay nada más