Seite 1 von 1

Timing im 100usec-Bereich

Verfasst: 16.11.2004 13:14
von Sven
Hallo,

ich möchte bei einer Ausgabe von Datenstrings an der RS232 eine definierte Pause zwischen den einzelnen Strings einfügen. Dabei ist die Baudrate 38.4kBaud, die Strings sind 9 bis 18 Byte lang, die Pause soll 0.6msec mit einer Toleranz von +/-0.1msec sein. Der Pegel darf sich in dieser Zeit nicht ändern, also kein Startbit.

Bisherige Ansätze:

- Delay funktioniert unter Win98 nur in Schritten von 5msec, unter Win2000 10msec, ist zu lang und zu unzuverlässig.

- zu WM_TIMER habe ich gelesen, dass es niedrige Priorität hat und deshalb im unteren msec-Bereich nicht sicher funktioniert, auch können keine Zeiten unter 1msec gesetzt werden.

- eine While-Wend-Schleife, die mit einer vorher kalibrierten Anzahl Durchläufe pro Zeit abläuft. Scheint sehr von der Systemauslastung abhängig zu sein.

Ideen:

- Einfügen von entsprechenden "leeren" Bytes in den String. Das müsste sehr zuverlässig sein, aber die Startbits stören (Pegelwechsel). Gibt es eine Möglichkeit, die Startbits zu unterdrücken. Zum Beispiel eine RS232 ohne Startbits aufzumachen, und die nötigen Startbits per Software (das wäre dann das erste gesendete Datenbit) zu erzeugen?

- Eine von der Systemauslastung unabhängige Schleife. Die Kalibrierung wäre wohl nicht das Problem.

- Eine WM_TIMER oder Callback-Prozedur, die entsprechend zuverlässig ist.

- Ein extra Threat, der mit exakten Zeiten abläuft. Geht sowas?

- Ein direktes Ansprechen des RS232-Ausganges (TxD) mit softwareseitiger Generierung des Signales. Habe aber keine Ahnung, wie das gehen soll und ob das ein besseres Timing ermöglicht.

Wäre schön, wenn ihr mir sagen könnt, was geht und was man lassen sollte. Und vielleicht, wie es geht, falls schon mal jemand sowas gemacht hat.

Danke, Sven

Verfasst: 16.11.2004 23:30
von THEEX
Ich hab mal 'nen alten Code von Rings ausgegraben und an die neue PureBasic-Version angepasst. Der könnte Dir behilflich sein, damit kannst zumindest genauere Zeitabstände messen. Pausen mußt natürlich selbst einbauen, aber das dürfte ja normal kein Problem sein.

Code: Alles auswählen

T1.Large_integer 
FREQ.Large_integer 
M1=AllocateMemory(8);speicher reservieren, sonst gehts nich 
Result=QueryPerformanceFrequency_(M1) ;bestimmen der frequenz 
If Result=0 
  Debug  GetErrorDLL()  ;Kein Hardwaretimer ? 
  End 
Else 
  CopyMemory(M1,@FREQ,8) ;Variable kopieren 
EndIf 
Debug FREQ\lowpart ;Counts pro Sekunde 
Debug FREQ\highpart 
Result=QueryPerformanceCounter_(M1) 
If Result 
  CopyMemory(M1,@T1,8) 
  Debug T1\lowpart 
  Debug T1\highpart 
  OldT1L=T1\lowpart ;Alten Low-wert sichern! 
EndIf 

Delay(200) ;Mal 200 ms warten 

Result=QueryPerformanceCounter_(M1) 
If Result 
  CopyMemory(M1,@T1,8) 
  Zeit.f=T1\lowpart-OldT1L 
  Debug Zeit 
  Zeit.f=Zeit.f /   (FREQ\lowpart) 
  Debug "200 Milliskeunden benötigen genau: "+ StrF(Zeit)+"Sekunden" 
EndIf 
If M1 
  FreeMemory(M1) 
EndIf

Verfasst: 18.11.2004 22:12
von Sven
Danke, CSprengel! Das funktioniert soweit.

Kann ich jetzt irgendwie verhindern, dass mir Windows zwischen der ersten und der zweiten Bytefolge dazwischenlangt und das Timing stört? So eine Art disable für das Multitasking, nur ein paar Millisekunden? Oder bleibt mir nur, nach der Pause zu überprüfen, ob die Zeiten eingehalten sind und es entsprechend nochmal zu versuchen?

Sven

Verfasst: 18.11.2004 23:08
von Rings
Windows ist nicht Echtzeitfähig, dementsprechend kann die keiner garantieren das du mit diesen einfachen Mittel die 'Zeit' einhälst.
Abhilfe kann schaffen:

1) einen treiber programmieren der im Kernel-Mode läuft.Nicht mit PB so einfach möglich, C oder C++ ist hier die bessere Wahl.
2) die Hardware die Zeiten für dich Regeln lassen(z.Bsp für EIB-bus nimmt man besser fertige Bausteine die das Protokoll zeitlich besser beherschen
3) Ein DOS-Programm schreiben, da hat man volle Hardware-Kontrolle.

4)
ach, fällt mir grad ein, du kannst aber auch mal probieren die Process-Priorität höher zu setzen, das hilft meist ungemein, nähere Infos in meiner Process-lib.

Und da wäre glaub ich noch die Geschichte mit den Critical Sections, obwohl das betrifft nur ein Process mit mehreren Tasks.

Verfasst: 19.11.2004 09:19
von Danilo
Sven hat geschrieben:Kann ich jetzt irgendwie verhindern, dass mir Windows
zwischen der ersten und der zweiten Bytefolge dazwischenlangt
und das Timing stört?
So eine Art disable für das Multitasking, nur ein paar Millisekunden?
Wie Rings schon sagte, Windows ist kein Echtzeit-Betriebssystem
und die kleinste Timer-Auflösung die Windows bietet ist 1ms.

Wenn Du die Priorität hochsetzt kannst Du es aber schonmal
ganz gut verbessern:

Code: Alles auswählen

SetPriorityClass_(GetCurrentProcess_(),#REALTIME_PRIORITY_CLASS)

  ; Hier Dein Zeitkritischer Code

SetPriorityClass_(GetCurrentProcess_(),#NORMAL_PRIORITY_CLASS)
Sollte man aber nicht allzu lang benutzen, da daß System
dadurch schon ziemlich lahm gelegt werden kann (Maus reagiert evtl.
nicht mehr richtig usw.).

In dem zeitkritischen Code darf kein Delay() sein, da dieser
Befehl in der Pause zu anderen Prozessen schaltet und somit
Störungen auftreten können.
Da Du eine Pause von 0.6ms haben möchtest, und Windows
eh als kleinste Auflösung 1ms unterstützt, solltest Du dafür
gleich ASM nehmen.

Verfasst: 21.11.2004 11:08
von Sven
@Danilo

Danke, wenn ich das jetzt mit dem PerformanceCounter verbinde, sollte es auch für unter 1ms reichen. Und wenn eine Unterbrechung auftritt, müßte ja der PerformanceCounter einen viel höheren Wert liefern, worauf ich die Daten nochmal schicken kann. Stimmt das?

@Rings

>> 4) ach, fällt mir grad ein, du kannst aber auch mal probieren die Process-Priorität höher zu setzen, das hilft meist ungemein, nähere Infos in meiner Process-lib.

Werde das Beispiel von Danilo probieren, wo finde ich event. die Process-lib? Code-Archiv?

>>Und da wäre glaub ich noch die Geschichte mit den Critical Sections, obwohl das betrifft nur ein Process mit mehreren Tasks.

Ähm, ja, die Idee war noch, die Zeitschleife in einen Thread zu verschieben, um unabhängig vom Hauptprogramm zu sein, das dann auch länger (20-50ms) schlafen darf. Wird das durch diese Critical Sections berührt?

Und kann ich die Priorität nur für diesen Thread erhöhen, während das Hauptprogram mit normaler Priorität läuft?

Sven

Verfasst: 21.11.2004 17:58
von Andre
Sven hat geschrieben:Werde das Beispiel von Danilo probieren, wo finde ich event. die Process-lib? Code-Archiv?
Noch heute abend auf PureArea.net in den UserLibs. 8)