Laden...

Delay/Verzögerung in C#

Erstellt von MartinH vor 18 Jahren Letzter Beitrag vor 18 Jahren 9.268 Views
MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren
Delay/Verzögerung in C#

Hallo,

ich habe folgendes Problem:

Ich muss über die serielle Schnittstelle mit einem älteren Gerät kommunizieren.
Die Daten die ich sende sind aber zu schnell für das Gerät.

Ich übertrage jetzt jedes byte einzeln, und brauche jetzt eine verzögerung zwischen den bytes.
Mit Thread.sleep funktioniert das ganze nicht zuverlässig, da die Zeiten variieren.

Kann mir da jemand weiterhelfen?

Martin

S
8.746 Beiträge seit 2005
vor 18 Jahren

Zuverlässiger wirds nicht. Windows ist kein Echtzeit-System. Ansonsten gibts da ja noch das RS232-Handshaking, was für solche Fälle gedacht ist. Vielleicht unterstützt dein Gerät das.

A
57 Beiträge seit 2005
vor 18 Jahren

man kann doch in den Systemeinstellungen die Baud-Rate einstellen. Oder wird das wenn du die Bytes einzeln in Eigenregie überträgst ignoriert ???

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Das ist kein Problem der Baudrate, sondern der Geschwindigkeit des PCs, die Bytes werden zu schnell hintereinander gesendet.
Ich habe als QuickandDirty-Lösung eine for-Schleife eingebaut, nur sind ja dort auch die Zeiten der Abarbeitung je nach PC und anzahl der laufenden Anwendungen unterschiedlich.

Ich brauche einfach ca 5ms Verzögerung zwischen dem Senden der einzelnen Bytes.

P
8 Beiträge seit 2005
vor 18 Jahren

Wenn du "ca. 5ms" delay brauchst, müsste es mit Thread.Sleep(5) doch recht gut gehen? Wie groß sind da die Schwankungen?

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Das Problem bei Thread.Sleep ist, das nicht vorhersehbar ist, wie lange das System braucht, um den Thread schlafen zu legen.
Ich habe das ganze mit dem Oszi kontrolliert, und da sind die schwankungen sehr groß. Je nachdem wie viele Programme ich geöffnet habe.
Thread.sleep ist mir auch als erstes einfefallen, aber funzt nicht.

L
667 Beiträge seit 2004
vor 18 Jahren

Keine Ahnung ob das besser ist als mit Thread.Sleep aber hast Du mal einen Timer mit 5ms Ticks probiert ?

"It is not wise to be wise" - Sun Tzu

P
8 Beiträge seit 2005
vor 18 Jahren

eine andere möglichkeit, wenngleich auch nicht sehr schön, wäre, dass du eine while-schleife baust:

DateTime start = DateTime.Now;
while(start + "5ms" > DateTime.Now) ;

Die hält sich solange auf, bis die 5ms vorbei sind. Vielleicht ist das genauer. Vielleicht musst du statt DateTime auch TimeSpan benutzen.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Original von MartinH
Das Problem bei Thread.Sleep ist, das nicht vorhersehbar ist, wie lange das System braucht, um den Thread schlafen zu legen.

Wie bereits gesagt: Die Latenz eines Windows-System ist so groß, dass du solche Anwendungen einfach nicht schreiben kannst, zumindest nicht im User-Mode. Wenn dann hast du vielleicht die Chance mit einem Kernel-Treiber die erforderliche Genauigkeit zu erreichen. 5 ms sollten da drin sein.

Du hast das falsche BS für deine Aufgabe gewählt... nimm was echtzeitfähiges wie QNX.

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Ich versuchs mal mit dem Timer, bis ich eine bessere Lösung finde.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Original von MartinH
Das ist kein Problem der Baudrate, sondern der Geschwindigkeit des PCs, die Bytes werden zu schnell hintereinander gesendet.

Ähem, genau DAS ist doch die Baudrate. Bits pro Sekunde. Und hast du es mal mit aktiviertem Handshake probiert? Bei 300 Baud werden 30 Zeichen pro Sekunde gesendet, das sind alle 33 ms ein Zeichen, viel langsamer als 5 ms.

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Das Gerät ist fest auf 9600/8/n/2 eingestellt.

Ein Handshake ist nicht möglich.
Das Problem ist wirklich die geschwindigkeit, mit der ich das gesamte Datenwort sende. Das lässt sich sehr gut am Oszi nachvollziehen. Werden die Bytes zu schnell hintereinander gesendet, verschluckt das Endgerät einzelne Zeichen.

Ich habe jetzt eine Schleife eingebaut, der Wert kann über einen Parameter geändert weden. So funktionierts jetzt, das mit dem Timer versuch ich aber auch noch.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Ich würde mal versuchen, immer 4 Byte-Pakete mit einer anschließenden Verzögerung zu verschicken. 4 Bytes werden vom UART des Gerätes mindestens gecached (selbst die Uralt-UARTs des Homecomputer-Zeitalters hatte 4 Byte Cache). Somit kannst du die Verzögerungszeit um den Faktor 4 erhöhen, was vielleicht in die mögliche Reichweite von Windows kommt, zur Not bist du halt ein Stück langsamer als möglich.

Sehr komisch das ganze: Wenn das Gerät fest mit 9600 arbeitet, sollte es auch die Datenmenge verkraften können, sonst hätte man 2400 wählen sollen.

Die Schleifenlösung ist natürlich nicht das Gelbe vom Ei. Produziert ordentlich Rechenlast und das Laufzeitverhalten verändert sich je nach Systemlast. Mache noch einen Prozess mit so einer Schleife auf und deine Wartezeit verdoppelt sind locker. Schleifen können auf Multi-Tasking-Systemen nicht für Warteoperationen genutzt werden.

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Da ich nur ab und zu ein 10-Byte Datenwort senden muss, hält sich die Last durch die Schleife eigendlich in Grenzen.

4.506 Beiträge seit 2004
vor 18 Jahren

Hallo MartinH!

Wenn ich damals richtig aufgepasst hab, dann läuft das Übertragen von Bytes über die serielle Schnittstelle doch so ab:

Das Programm überträgt die Daten an den UART-Chip auf der Platine, dieser legt es in seinen Puffer. Der angehängte Kommunikationspartner holt die Daten dann Stück für Stück ab. Da kann eigentlich der Sender nicht zu "schnell" sein, denn das BS regelt hier ja die Baudrate.

Also ist Dein Problem, dass irgendwann zu viele Daten an den UART geraten, und dessen Speicher überläuft, was dann natürlich zum Abbruch der Kommunikation zw. Programm und Chip veranlässt.

Also könntest Du das auch so machen, dass Du die belegte Puffergröße abfrägst, und zwar bevor Du die Daten versuchst zur Versendung freizugeben, das würde dann schematisch so aussehen:



while (Daten.Length > 0)
{
   int pufferGroesse = GetPufferData();
   
   if (pufferGroesse < Schwellwert)
   {
      SendData( Datenteil );
      Daten.Length = Daten.Length - Datenteil;
   }
}


Wie gesagt, nur rein schematisch der Code, da ich nicht weiß wie die Daten bei Dir vorliegen, noch welche API Du für serielle Schnittstelle verwendest.

So sollte es doch machbar sein, oder?

Ciao
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

S
8.746 Beiträge seit 2005
vor 18 Jahren

Die lesende Applikation muss aber die Daten vom eigenen UART abholen. Tut sie das nicht schnell genug (bei 9600 als mit 1000 Zeichen pro Sekunde), so muss der UART das Handshake auslösen und so den Sender blockieren. Gibt es kein Handschaking - wie in diesem Fall - muss die abholende Applikation einfach schnell genug sein. Das scheint hier nicht der Fall zu sein. Problem ist also die Firmware des Gerätes, nicht die Schnittstelle selbst, bzw. die Nicht-Benutzung von Handshake / falsche Baudrate.

Vielleicht hängt sogar geräteseitig nichtmal ein UART dran, gibt ja immer so ein paar Spezis, die glauben, man reisst die Leitungen besser per Hand hoch.

Insofern ist das "Ausbremsen" des Sendens tatsächlich die einzige Lösung.

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Meine Daten werden alle übertragen, das ist nicht das Problem, auch die Baudrate stimmt.
Ich habe auch schon mal einen V25-Rechner mit 8MHz unter TurboPascal programmiert. Da hatte ich auch solche Probleme. Da dort alles Interruptgesteuert ist, konnte es auch vorkommen, daß Zeichen einfach verschluckt wurden.
Jetzt sitze ich an der anderen Seite, und muss versuchen dem Rechner die Zeichen nicht zu schnell hintereinander zu schicken.
Unter Delphi war das auch kein problem mit Verzögerungen.

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

@svenson

genau das ist das problem 😁

S
8.746 Beiträge seit 2005
vor 18 Jahren

Wie hast du es denn mit Delphi gelöst?

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Ich habe da mit Async Professional gearbeitet, da gab es verschiedene Funktionen zum Warten. Entweder angabe in Millisekunden oder Ticks

S
8.746 Beiträge seit 2005
vor 18 Jahren

Ja, Async hab ich auch oft benutzt. Gibts davon nicht eine COM-Variante? Die könntest du doch problemlos unter .NET einsetzen.....

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

Möchte ich eigendlich nicht. Hab ich mir schon angeschaut, finde ich aber nicht so gut.

4.506 Beiträge seit 2004
vor 18 Jahren

Damit ich da dann auch noch mitkomme:

Die lesende Applikation

ist das nun die Firmware auf dem angesteckten Gerät?
Und die verschluckt Daten?

Und dann hilft eine Serverseitige Redutzierung der Baudrate nicht? Oder kommt dann keine Kommunikation mehr zustande?

Ich würde diesen Vorgang gerne aus pers. Interessensgründen nachvollziehen können.

Ist es nicht so, dass der Server-UART Chip nicht auf Daten wartet, bis er sie dann nach der eingestellten Baud-Rate zum Empfänger schickt? Versendet er das nicht Byteweise?

Reduzierung der Baudrate würde natürlich auch das Empfangen von Rücksende-Bytes beeinträchtigen, lässt sich das Gerät von der Baud-Rate einstellen?

Das sind erst mal ein paar Fragen, würde mir aber helfen das Problem wirklich nachvollziehen zu können.

Ciao
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

MartinH Themenstarter:in
185 Beiträge seit 2005
vor 18 Jahren

@norman_timo

genau, das angesteckte Gerät verschluckt die Zeichen, nicht der sendende PC. Auch habe ich keine probleme die ankommenden Daten zu lesen.

Da sich die Baudrate nicht ändern lässt, muss ich beim senden einfach Byte für Byte mit kurzen pausen wegschicken.

4.506 Beiträge seit 2004
vor 18 Jahren

Hallo MartinH!

Dann ist schlichtweg das angesteckte Gerät Sche***, sorry, aber das ist ja n Ding, das hab ich noch nicht gesehen. Also wenn Baud-Rate 9600 angegeben sind, dann sollte es das normalerweise auch können (sollen).

Schöner Mist, mein Beileid.

Ciao
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

S
8.746 Beiträge seit 2005
vor 18 Jahren

Tja, aber manchmal kann man sich eben den Mist nicht aussuchen, mit dem man arbeiten muss. Da ist das Suchen nach Workarounds angesagt.....