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
Timing im 100usec-Bereich
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)
EndIfDanke, 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
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
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.
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
Wie Rings schon sagte, Windows ist kein Echtzeit-BetriebssystemSven 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?
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)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
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
@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
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