Seite 2 von 3
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 01:06
von Daffy0815
@TheCube & ts-soft
Leider zu früh gefreut!
Die Sache funktioniert offenbar nicht in einer Prozedur zwischen While und Wend.
Da ändert sich der Timer rein gar nicht.
Hier ein Beispiel:
Code: Alles auswählen
Enumeration
#Window_0
#Image1
#ImageGadget1
EndEnumeration
CreateImage(#Image1,50,20)
Global Flag
Procedure ToggleFlag(hWnd, uMsg, idEvent, time.l)
StartDrawing(ImageOutput(#Image1))
DrawText(3,2,Str(Flag),$AAAAAA)
StopDrawing()
SetGadgetState(#ImageGadget1,ImageID(#Image1))
flag+1
EndProcedure
Procedure TestProc()
While 0 = 0
Debug Flag
If Flag >= 5
Break
EndIf
Wend
EndProcedure
If OpenWindow(#Window_0, 100, 100, 200, 60, "Testfenster", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar)
ImageGadget(#ImageGadget1,20,20,0,0,ImageID(#Image1),#PB_Image_Border)
Else: End : EndIf
SetTimer_(WindowID(#Window_0), 1, 500, @ToggleFlag())
Repeat
TestProc()
Until WaitWindowEvent() = #WM_CLOSE
Gruß Daffy
PS. @ts-soft
Ist die andere Routine in der Lage einen SICHER einen Timer abzubilden (Habe sie im Programm noch nicht getestet)?
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 01:55
von TheCube
Ich hoffe mal, das war nur ein schlechtes Beispiel. (Konzept?)
1. Soo schnell kommt die Debug Ausgabe auch nicht hinterher (->Delay hinter Debugausgabe)
2. Ohne Fenstereventabarbeitung gehts nicht, da musst du vielleicht ts-soft´s Link versuchen
Aber hier eine schlechte Code-Antwort
Code: Alles auswählen
Enumeration
#Window_0
#Image1
#ImageGadget1
EndEnumeration
CreateImage(#Image1,50,20)
Global Flag
Procedure ToggleFlag(hWnd, uMsg, idEvent, time.l)
StartDrawing(ImageOutput(#Image1))
DrawText(3,2,Str(Flag),$AAAAAA)
StopDrawing()
SetGadgetState(#ImageGadget1,ImageID(#Image1))
Flag+1
EndProcedure
Procedure TestProc(*dummy)
While 0 = 0
Debug Flag : Delay (50)
If Flag >= 5
Break
EndIf
Wend
Debug "Thread beendet"
EndProcedure
If OpenWindow(#Window_0, 100, 100, 200, 60, "Testfenster", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar)
ImageGadget(#ImageGadget1,20,20,0,0,ImageID(#Image1),#PB_Image_Border)
Else: End : EndIf
Thread=CreateThread(@TestProc(),0)
SetTimer_(WindowID(#Window_0), 1, 500, @ToggleFlag())
Repeat
Until WaitWindowEvent() = #WM_CLOSE
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 02:03
von BSP
Hallo Daffy0815
Dein "hochinteressanter Code" funktioniert schon,
er frist nur die ganze Rechenleistung.
Baue mal in Deine Procedure die inzwischen "berühmt berüchtigte"
"While not WindowEvent() : Wend" ein.
Dann läuft alles weiter und Du siehst, was Du da eigentlich machst.
Das läuft auch weiter, während ich mich hier angemeldet habe und dieses hier tippe.
Gruß: BSP
Code: Alles auswählen
Procedure TestProc()
;While 0 = 0
Repeat
Debug Flag
If Flag >= 5
Break
EndIf
While Not WindowEvent():Wend
;Wend
ForEver
EndProcedure
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 02:06
von Daffy0815
@theCube
Das war natürlich nur ein "schlechtes Beispiel" da ich diesmal "Beschwerden" über die Größe der realen Routinen vermeiden wollte.
Mit der Geschwindigkeit der Debug-Ausgabe hat das aber nichts zu tun (sonst würde die While-Wend-Schleife ohne die Debug-Ausgabe ja abgebrochen werden).
Habe zwischenzeitlich mal die andere Lösung mit While-Wend getestet.
Scheint zu funktionieren!
Code: Alles auswählen
Define TimerResolution.TIMECAPS
Global Dim TimerHandles(15)
Global Dim TimerProcedures(15)
Procedure Timer_Init()
Shared TimerResolution
If timeGetDevCaps_(@TimerResolution, SizeOf(TIMECAPS)) = #TIMERR_NOERROR
If timeBeginPeriod_(TimerResolution\wPeriodMin) = #TIMERR_NOERROR
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure Timer_End()
Protected I
Shared TimerResolution
timeEndPeriod_(TimerResolution\wPeriodMin)
For I = 0 To 15
If TimerHandles(I)
timeKillEvent_(TimerHandles(I))
EndIf
Next
EndProcedure
Procedure Timer_Callback(TimerHandle, Message, TimerID, wParam, lParam)
If TimerProcedures(TimerID)
CallFunctionFast(TimerProcedures(TimerID))
EndIf
EndProcedure
Procedure TimerStart(TimerID, Delay, ProcAddr)
If TimerID > 15 Or TimerID < 0 : ProcedureReturn #False : EndIf
If TimerHandles(TimerID)
timeKillEvent_(TimerHandles(TimerID))
EndIf
TimerProcedures(TimerID) = ProcAddr
TimerHandles(TimerID) = timeSetEvent_(Delay, 0, @Timer_Callback(), TimerID, #TIME_PERIODIC)
ProcedureReturn TimerHandles(TimerID)
EndProcedure
Procedure TimerStop(TimerID)
If TimerID > 15 Or TimerID < 0 : ProcedureReturn #False : EndIf
If TimerHandles(TimerID)
timeKillEvent_(TimerHandles(TimerID))
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure TimerGetMaxRes()
Shared TimerResolution
ProcedureReturn TimerResolution\wPeriodMax
EndProcedure
Procedure TimerGetMinRes()
Shared TimerResolution
ProcedureReturn TimerResolution\wPeriodMin
EndProcedure
Procedure mytimer1()
Shared hoehe
Debug "Timer 1"
If hoehe = 1000: hoehe = 100: EndIf
Beep_(hoehe,100)
hoehe+100
EndProcedure
Procedure mytimer2()
Beep_(1800,5)
Debug "Timer 2"
EndProcedure
Procedure mytimer3()
Beep_(1800,100)
Debug "Timer 3"
EndProcedure
Procedure mytimer4()
Beep_(800,100)
Debug "Timer 4"
EndProcedure
Procedure TestProc()
While 0=0
Wend
EndProcedure
Timer_Init()
hWnd = OpenWindow(0, (GetSystemMetrics_(#SM_CXSCREEN)-200)/2,(GetSystemMetrics_(#SM_CYSCREEN)-277)/2, 400, 360, "High Resolution Timer by Danilo", #PB_Window_SystemMenu|#PB_Window_SizeGadget)
TimerStart(0, 1000, @mytimer1())
TimerStart(1, 200, @mytimer2())
TimerStart(2, 2000, @mytimer3())
TimerStart(3, 600, @mytimer4())
Repeat
EventID.l=WaitWindowEvent()
; IF LeftMouseButton pressed...
If EventID = #WM_LBUTTONDOWN
TimerStop(1): TimerStop(2): TimerStop(3)
EndIf
TestProc()
; pressed CloseButton or ALT+F4 ??
If EventID = #PB_Event_CloseWindow
Quit = 1
EndIf
Until Quit = 1
Timer_End()
Hoffe nur, das mich nicht noch weitere Überraschungen erwarten
Gruß
Daffy
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 02:20
von Daffy0815
@BSP
Mein "hochinteressanter" Code war doch nur das "Worst-Case-Beispiel"!
In Wirklichkeit werden zwischen dem While und Wend jede Menge Dinge ausgeführt (Bargraphen aufgefrischt, Messwerte via RS232 geholt und und und...).
Dies aber eben nur dann, wenn der Timer einen bestimmten Wert überschreitet. Sonst wäre der Timer ja für die Katz denn schließlich soll er ja die Abfragerate reduzieren.
Es ging ja darum festzustellen ob der Timer in der Lage ist eine andere, laufende Prozedur zu unterbrechen.
Und das kann er offensichtlich nicht.
Mein Problem ist sicherlich das, dass ich normalerweise Microcontroller in Assembler programmiere und da ist man halt mit Interrupts und Timern zu "verwöhnt"
So sieht das in meinem Basic für DS89C450 aus:
Code: Alles auswählen
Clock 0,0
Time(0)=0
On Time(0, 0.5) Gosub IsrTi0
Clock 0,1
Do
Loop
:IsrTi0
? Time(0)
Time(0)=0
RetI
Gruß
Daffy
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 05:42
von BSP
@BSP
Mein "hochinteressanter" Code war doch nur das "Worst-Case-Beispiel"!
In Wirklichkeit werden zwischen dem While und Wend jede Menge Dinge ausgeführt.....
Ja, das habe ich so auch vermutet.
Gruß:BSP
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 11:39
von matbal
@Daffy0815
Wenn ich dich richtig verstehe, willst du nur die Bildschirmausgaben reduzieren. Warum lagerst du dann deine "Arbeistsprozedur" nicht in einen Thread aus. Die Eventschleife wird so nicht mehr aufgehalten. Das heißt, auch das PB-Timerevent kommt an.
SetTimer geht auch. Wenn hWnd = 0, dann gilt er scheinbar für alle Fenster. (zumindest unter XP)
Code: Alles auswählen
EnableExplicit
Enumeration
#FormMain
#FormMain_Text_Ausgabe
#Timer_1
EndEnumeration
Global ergebnis
Procedure Arbeit(dummy)
Repeat
ergebnis + 1
Delay(1)
ForEver
EndProcedure
; (1) Wird vom PB-Timer aufgerufen
Procedure Ausgabe()
Debug "pbTimer"
SetGadgetText(#FormMain_Text_Ausgabe, Str(ergebnis))
EndProcedure
; (2) Wird von SetTimer aufgerufen
Procedure cbTimer(hWnd, uMsg, wParam, lParam)
Debug "cbTimer"
SetGadgetText(#FormMain_Text_Ausgabe, Str(ergebnis))
EndProcedure
Procedure FormMain_Open()
If OpenWindow(#FormMain, 100, 200, 200, 50, "programm")
TextGadget(#FormMain_Text_Ausgabe, 10, 10, 80, 25, "Ausgabe")
; (1)
AddWindowTimer(#FormMain, #Timer_1, 500)
; (2)
;SetTimer_(0, #Timer_1, 500, @cbTimer())
EndIf
EndProcedure
FormMain_Open()
CreateThread(@Arbeit(), 0)
While IsWindow(#FormMain) Or IsWindow(2)
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
CloseWindow(EventWindow())
Case #PB_Event_Timer
Select EventTimer()
Case #Timer_1
Ausgabe()
EndSelect
EndSelect
Wend
;(2)
;KillTimer_(0, #Timer_1)
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 13:14
von Daffy0815
@ts-soft
Ich habe nun den von Ihnen überarbeiteten Code eingebaut.
Was mir nur etwas Kopfzerbrechen bereitet, ist das mir die verwendeten Datentypen nicht klar sind.
Auch was die Zeiten betrifft ist mir da etwas unklar.
Was sind das für Werte Mikrosekunden, Millisekunden oder was?
Ich vermute mal Millisekunden.
Ich habe nämlich festgestellt, dass wen man den Wert zu klein wählt (z. B. 10) mein Programm mit "ungültigem Speicherzugriff" aussteigt.
Ist alles was nicht bezeichnet ist ".i" ?
Auch die Proceduren haben mal Rückgabewerte und mal keine Rückgabewerte.
Wie sehen da denn die Prototypen aus?
Gruß
Daffy
PS. Also nach stundenlangem Herumprobieren geb ich es auf mit der Routine.
Sie führt auch bei höheren Werten (z. B. 200) in meinem Programm zu sporadischen Abbrüchen mit "ungültigem Speicherzugriff"
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 13:28
von Daffy0815
@matbal
Nein, es geht nicht um die Ausgaberate auf dem Bildschirm wenngleich das auch ein "Nebeneffekt" wäre.
Das Problem ist ein Anderes:
Am PC hängt via serieller Schnittstelle ein Subsystem mit einem Microcontroller.
Der Microcontroller leistet die "eigentliche Arbeit".
Der PC mit dem PureBasic-Programm dient lediglich zur Parametrierung und Visualisierung des Ganzen.
Ein Beispiel:
Auf dem PC befindet sich ein Bild in dem Messwerte in numerischer Form und als Bargraphen dargestellt werden.
Der PC sendet in diesem Fall an das Subsystem die Anforderung "AI<Kanalnummer><CR><Prüfsumme>"
Das Subsystem antwortet mit "AI<Kanalnummer>=<Analogwert><CR><Prüfsumme>
Nun wird/werden der/die empfangene(n) Wert(e) dargestellt.
Die Anfragen erzeugen im Subsytem einen Interrupt und wenn die Anfragen zu häufig kommen dann hat das Subsystem keine Zeit mehr die "eigentliche Arbeit" zu verrichten.
Gruß
Daffy
Re: Frage zu AddWindowTimer()
Verfasst: 27.02.2012 16:30
von Daffy0815
Hallo Leute,
nachdem alle Versuche mit den hier vorgeschlagenen Methoden einen Timer zu programmieren der in meinem Programm keine "Nebenwirkungen" hat gescheitert sind habe ich mal selbst was zusammengebastelt.
Ob das eine optimale Lösung ist weiß ich nicht aber zumindest funktioniert sie überall und ganz ohne Fenster einwandfrei!
Hier das Testprogramm:
Code: Alles auswählen
Global Time.i
Procedure Timer(*Dummy)
;
TimeOld.i = ElapsedMilliseconds()
If Sign(TimeOld.i) = -1
TimeOld.i = TimeOld.i + 2147483648
EndIf
;
Repeat
TimeNew.i = ElapsedMilliseconds()
If Sign(TimeNew.i) = -1
TimeNew.i = TimeNew.i + 2147483648
EndIf
;
If TimeNew.i <> TimeOld.i
Time.i = Time.i + (TimeNew.i - TimeOld.i)
TimeOld.i = TimeNew.i
EndIf
ForEver
EndProcedure
Thread=CreateThread(@Timer(), 0)
#TimeOut = 5000 ;Millisekunden
Repeat
;
Time.i = 0
While Time.i < #TimeOut
Debug Time.i
Wend
;
Until Time.i >= #TimeOut
KillThread(Thread)
End
Gruß
Daffy