Timing im 100usec-Bereich

Für allgemeine Fragen zur Programmierung mit PureBasic.
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Timing im 100usec-Bereich

Beitrag 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
THEEX
Beiträge: 804
Registriert: 07.09.2004 03:13

Beitrag 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
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Beitrag 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
Benutzeravatar
Rings
Beiträge: 977
Registriert: 29.08.2004 08:48

Beitrag 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.
Rings hat geschrieben:ziert sich nich beim zitieren
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Beitrag 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.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Sven
Beiträge: 374
Registriert: 23.09.2004 12:01

Beitrag 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
Benutzeravatar
Andre
PureBasic Team
Beiträge: 1765
Registriert: 11.09.2004 16:35
Computerausstattung: MacBook Core2Duo mit MacOS 10.6.8
Lenovo Y50 i7 mit Windows 10
Wohnort: Saxony / Deutscheinsiedel
Kontaktdaten:

Beitrag 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)
Bye,
...André
(PureBasicTeam::Docs - PureArea.net | Bestellen:: PureBasic | PureVisionXP)
Antworten