Timer
Timer
Frohe Ostern,
habe ein neues Problem !
Mein Timer mit einem Interval := 60000; sollte eigentlich bei jeder neuen Minute eine Reihe von Anweisungen ausführen.
Die Dauer der Anweisungen (DHT-Temperatur ermitteln, DS18B20-Temperatur ermitteln und ein paar If-Anweisungen) dauert ca. 3 bis 5 Sekunden.
Das Problem ist : Der Timer springt machmal erst in den letzten Sekunde der aktuelle Minute an. Dadurch werden meine Anweisungen nicht vollständig abgearbeitet.
Dadurch, dass eine Zeit verglichen wird, wird diese alle 4 bis 3 Minuten übersprungen. (if (s_Zeit_soll = s_Zeit_Ist) then ..)
Machmal springt der Timer bei xx.04 Minuten an und dann xx.57.
Beispiel :
OnTimer(Sender ;Tobject);
begin
Memo.Lines.Add('1 ' + TimeToStr(now));
....
.....
Memo.Lines.Add('2 ' + TimeToStr(now));
end;
-> String '2 ' xx.xx.xx wird nicht ausgegeben.
Wie kann ich das verhindern ?
Grüße (Ich hoffe es ist verständlich)
Peter
habe ein neues Problem !
Mein Timer mit einem Interval := 60000; sollte eigentlich bei jeder neuen Minute eine Reihe von Anweisungen ausführen.
Die Dauer der Anweisungen (DHT-Temperatur ermitteln, DS18B20-Temperatur ermitteln und ein paar If-Anweisungen) dauert ca. 3 bis 5 Sekunden.
Das Problem ist : Der Timer springt machmal erst in den letzten Sekunde der aktuelle Minute an. Dadurch werden meine Anweisungen nicht vollständig abgearbeitet.
Dadurch, dass eine Zeit verglichen wird, wird diese alle 4 bis 3 Minuten übersprungen. (if (s_Zeit_soll = s_Zeit_Ist) then ..)
Machmal springt der Timer bei xx.04 Minuten an und dann xx.57.
Beispiel :
OnTimer(Sender ;Tobject);
begin
Memo.Lines.Add('1 ' + TimeToStr(now));
....
.....
Memo.Lines.Add('2 ' + TimeToStr(now));
end;
-> String '2 ' xx.xx.xx wird nicht ausgegeben.
Wie kann ich das verhindern ?
Grüße (Ich hoffe es ist verständlich)
Peter
- kupferstecher
- Beiträge: 431
- Registriert: Do 17. Nov 2016, 11:52
Re: Timer
Du kannst den Zeitpunkt fuer die Berechnung am Anfang zwischenspeichern. Wenn du den Timer mit niedrigerem Intervall einstellst (z.b. alle 20sek) und auf die Minutenaenderung pruefst, kannst du dir sicher sein, dass wirklich jede Minute erfasst ist.
OnTimer(Sender ;Tobject);
var
CallTime: TDateTime;
begin
CallTime:= Now;
Memo.Lines.Add('1 ' + TimeToStr(CallTime));
....
.....
Memo.Lines.Add('2 ' + TimeToStr(CallTime));
end;
OnTimer(Sender ;Tobject);
var
CallTime: TDateTime;
begin
CallTime:= Now;
Memo.Lines.Add('1 ' + TimeToStr(CallTime));
....
.....
Memo.Lines.Add('2 ' + TimeToStr(CallTime));
end;
Re: Timer
Nö...braspi hat geschrieben:Ich hoffe es ist verständlich
"Bei jeder neuen Minute" - heißt das, dass dein Prozess mit den Minuten der Uhrzeit synchronisiert sein muss? In diesem Fall würde ich dem Timer ein erheblich kürzeres Intervall geben, je nachdem wie genau du den Minutenwechsel erwischen willst, wahrscheinlich maximal 1 Sekunde. Jedes Mal, wenn der Timer feuert, berechnest du die aktuelle Minute und vergleichst sie mit der vorigen Minute, die du beim Programmstart gespeichert hast. Wenn sich die aktuelle Minute von der vorigen Minute unterscheidet, ist der Minutenwechsel erfolgt - du speicherst die neue Minute wieder als vorige Minute ab und kannst deinen Prozess ausführen, für den du 1 Minute Zeit hast.braspi hat geschrieben: Mein Timer mit einem Interval := 60000; sollte eigentlich bei jeder neuen Minute eine Reihe von Anweisungen ausführen.
Hier ein paar Code-Zeilen, wie ich mir das vorstelle:
Code: Alles auswählen
var
AktuelleMinute, VorigeMinute: Word;
procedure TForm1.FormCreate(Sender: TObject);
var
h,s,s100: Word;
begin
DecodeTime(Time(), h, VorigeMinute, s, s100);
end;
procedure TForm1.Timer1Timer(Sender: TObject); // Intervall: 1000 ms oder kürzer
var
t: TTime;
h,s,s100: Word;
begin
t := Time();
DecodeTime(t, h, AktuelleMinute, s, s100);
if AktuelleMinute <> VorigeMinute then begin
VorigeMinute := AktuelleMinute;
Memo1.Lines.Add(TimeToStr(t)); // <---- Hier würde dein Prozess aufgerufen, ich schreibe nur einen Eintrag in ein Memo
end;
Caption := TimeToStr(t);
end;
Re: Timer
Danke,
ich habe es jetzt so gemacht.
Alle 20 Sekunden schaue ich nach (Intervall := 20000). Der Zeitversatz ist jetzt ca 4 Sekunden, sicher kann ich damit leben.
Bei Intervall := 60000; war der Zeitversatz zwischen 2 Sekunden und 57 Sekunden, heißt für mich im Umkehrschluss, Alles Glückssache.
ich habe es jetzt so gemacht.
Alle 20 Sekunden schaue ich nach (Intervall := 20000). Der Zeitversatz ist jetzt ca 4 Sekunden, sicher kann ich damit leben.
Bei Intervall := 60000; war der Zeitversatz zwischen 2 Sekunden und 57 Sekunden, heißt für mich im Umkehrschluss, Alles Glückssache.
- procedure Tgt.On_Timer_Min(Sender: TObject);
var
hh_n, mm_n, ss_n, ms_n : Word;
hh_o, mm_o, ss_o, ms_o : Word;
begin
gv.t_MinNew := now;
DecodeTime(gv.t_MinNew, hh_n, mm_n, ss_n, ms_n);
DecodeTime(gv.t_MinOld, hh_o, mm_o, ss_o, ms_o);
if (mm_n <> mm_o) then
begin
gv.t_MinOld := gv.t_MinNew; // gv sind bei mir globale Variablen
myRun(gv.t_MinNew); // Durchlauf ca. 4 Sekunden, DHT22 und DS18B20 brauchen ihre Zeit
end;
end;
-
- Beiträge: 582
- Registriert: Sa 22. Okt 2016, 23:12
- OS, Lazarus, FPC: W10, L 3.8
- CPU-Target: 32+64bit
- Wohnort: Dresden
Re: Timer
@braspi, für welches OS brauchst du den Timer?
Vielleicht wäre so was auch Interessant für dich https://forum.lazarus.freepascal.org/in ... #msg318567 ?
mfg Maik
Vielleicht wäre so was auch Interessant für dich https://forum.lazarus.freepascal.org/in ... #msg318567 ?
mfg Maik
LG Maik
Windows 10,
- Lazarus 3.8 (stable) + fpc 3.2.2 (stable)
- Lazarus 4.99 (trunk) + fpc 3.3.1 (main/trunk)
Windows 10,
- Lazarus 3.8 (stable) + fpc 3.2.2 (stable)
- Lazarus 4.99 (trunk) + fpc 3.3.1 (main/trunk)
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Timer
Nö.braspi hat geschrieben:Mein Timer mit einem Interval := 60000; sollte eigentlich bei jeder neuen Minute eine Reihe von Anweisungen ausführen.
Nicht " bei jeder neuen Minute", sondern "möglichst bald nachdem dieser Zeitpunkt überschritten wurde". (So funktioniert TTimer.)
Und "möglichst bald" kann je nach Belastung des gesamten Rechners "beliebig" lange dauern. (Theoretisch auch mehr als eine Minute)
Auch nö.braspi hat geschrieben: if (s_Zeit_soll = s_Zeit_Ist) then ..
Ich vermute dass die "Zeit" den Pascal datetime-Typ hat, und der ist ein Real-Wert. Real - Werte darf man (eigentlich) nie auf Gleichheit testen.
Der neue Code ist da auch nicht besser !
-Michael
-
- Beiträge: 958
- Registriert: Mo 11. Sep 2006, 22:56
Re: Timer
Ohne jetzt deine Berechnungen/Anweisungen zu kennen die du ausführst, es könnte helfen die in einen seperaten
Thread auszulagern der nur von dem Timer angestossen wird.
In der Theorie sollte es ja nicht vorkommen das die Threads sich überholen
Thread auszulagern der nur von dem Timer angestossen wird.
In der Theorie sollte es ja nicht vorkommen das die Threads sich überholen

-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Timer
In der Praxis braucht dafür nur der Sensor nicht antworten.creed steiger hat geschrieben:In der Theorie sollte es ja nicht vorkommen das die Threads sich überholen
Das kann jetzt noch schiefgehen, wenn der Computer eine neue Zeit bekommt. Was aber selten vorkommen dürfte.braspi hat geschrieben:if (mm_n <> mm_o) then
Das klingt nach schlechter Programmierung. Ich hoffe, Du blockierst das Programm nicht so lange.braspi hat geschrieben:myRun(gv.t_MinNew); // Durchlauf ca. 4 Sekunden, DHT22 und DS18B20 brauchen ihre Zeit
Normalerweise macht man das so, dass man die Messung anstößt, sich ein Timeout setzt, bis wann die Messung fertig sein soll und dann die Messwerte abfragt. Oder einen Scheduler macht, der die Sensoren zyklisch durchgeht.
Ich mache es auf dem AVR z.B. so, Pseudocode:
Schleife
Zähler inc, Überlauf bei 20
wenn Zähler = 1
Sensor 1 starten, dauert 750msec
wenn Zähler = 2
Sensor 1 auslesen
wenn Zähler = 3
Sensor 2 starten
wenn Zähler = 4
Sensor 2 auslesen
Werte Sensor 2 berechnen
wenn Zähler = 5
Ausgänge nach Messwerten berechnen
Ausgänge an I2C setzen
wenn Zähler = 20
Messwerte senden
Zähler = 0
Display aktualisieren
Warte 1sec
Ende Schleife
Hat den Vorteil, egal wie lange ein Sensor braucht (da muss man eventuell mehrere Zählerschritte überspringen), das Programm läuft immer mit 1sec Taktung, das Display wird immer aktualisiert, der Nutzer hat nie den Eindruck, das Programm wäre stehengeblieben.
Die Zyklenzeit und Zyklenzahl wird natürlich den Erfordernissen angepasst, von einigen Millisekunden für Datenlogger bis Sekunden für Temperatursensoren, die nur ab und zu mal einen Wert messen.
-
- Beiträge: 958
- Registriert: Mo 11. Sep 2006, 22:56
Re: Timer
Timm Thaler hat geschrieben:
In der Praxis braucht dafür nur der Sensor nicht antworten.
bei den Dallas one wire gibts das Problem bei mir nicht
(w1-gpio w1-therm aufm raspi)
fehlerhafte Werte werden halt Verworfen
bei /sys/bus/w1/devices/ auslesen gibts keinen Timeout
(und der 750ms Abfrageintervall sollte auch reichen)
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Timer
??? Worker Threads kann man nicht mit einem TTmer anstoßen !!!creed steiger hat geschrieben:Ohne jetzt deine Berechnungen/Anweisungen zu kennen die du ausführst, es könnte helfen die in einen seperaten
Thread auszulagern der nur von dem Timer angestossen wird.
Da muss man andere Mechanismen verwenden.
-Michael
Zuletzt geändert von mschnell am Di 30. Apr 2019, 11:05, insgesamt 1-mal geändert.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Timer
Ich halte es für eine extrem schlechte Idee, davon auszugehen, dass "NOW" in irgendeiner Weise mit TTimer synchron läutf.Timm Thaler hat geschrieben:Was aber selten vorkommen dürfte.
-Michael
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Timer
Das hört sich katastrophal an: Das darf nur ein paar Mikrosekunden dauern. Nichts, was in einem "TTimer" Event passiert, darf auf irgendetwas warten !!!braspi hat geschrieben:Die Dauer der Anweisungen (DHT-Temperatur ermitteln, DS18B20-Temperatur ermitteln und ein paar If-Anweisungen) dauert ca. 3 bis 5 Sekunden.
-Michael
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Timer
Nein, läuft es definitiv nicht.mschnell hat geschrieben:Ich halte es für eine extrem schlechte Idee, davon auszugehen, dass "NOW" in irgendeiner Weise mit TTimer synchron läutf.
Wenn ich bei einem Programm eine Sekundenanzeige haben will, setzte ich den Timer auf 100msec, max. 125msec. Dann laufen die Sekunden flüssig durch, mit einem Jitter von 100msec, den man nicht sieht.
Nimmt man für eine Sekundenanzeige einen Timer von 1sec, wird regelmäßig ein Wert vergessen, und dann folgen zwei Werte kurz hintereinander. Eben weil sie nicht synchron laufen. Physikalisch entspricht das einer Schwebung.
Nach Nyquist wäre für eine Sekunde ein Timer von <500msec ausreichend. Dann werden zwar alle Werte angezeigt, aber man sieht, dass die Werte nicht gleichmäßig aufeinander folgen.
Ich muss mir also überlegen, wie "genau" ich die Minute treffen will, und so muss ich meinen Timer setzen. Reicht mir ein Wert pro Minute, reichen 29sec Timer, möchte ich den Wert jede Minute mit maximal 5sec Fehler, muss ich den Timer auf 2sec setzen.
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Timer
Weil bei 1-wire der Master den Takt vorgibt. Bei I2C kann der Slave einen Clock stretch machen, und dann muss theoretisch der Master warten, bis der Slave den Bus wieder freigibt. Damit kann ein Slave einen Bus blockieren. (Allerding ist mir noch kein I2C Chip untergekommen, der das macht, aber das Protokoll sieht es vor.)creed steiger hat geschrieben:bei den Dallas one wire gibts das Problem bei mir nicht
Ich weiss nun nicht, was z.B. der Raspi an dieser Stelle macht. Arduino-Libs sind ja teilweise so bescheuert programmiert, dass sie dann wirklich den µC erstmal lahmlegen. Und ich hatte auch schon nRF24 Code für den Raspi, der beim Warten auf den Interrupt am SPI den Prozessor in die 100% Kernellast getrieben hat, was natürlich eine ganz blöde Idee ist.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: Timer
"Vorgibt" schon, dann muss das Timing aber auf wenige Prozent konstant bleiben. Davon kann man bei einem User-Programm, das in einem Betriebssystem läuft i.A. nicht ausgehen.Timm Thaler hat geschrieben:Weil bei 1-wire der Master den Takt vorgibt.
Hardware-Chips sind ja im Allgemeinen "beliebig" schnell und brauchen das nicht. Wenn man aber einen kleinen Prozessor als I²C Slave programmiert kann es nötig sein.Timm Thaler hat geschrieben:Allerding ist mir noch kein I2C Chip untergekommen, der das macht,
Ich vermute der RASPi Chip hat I²C Hardware. Deshalb sollte ein Linux-Treiber das richtig machen. Das I²C-Protokoll - oder sonst irgendeinen getimeten direkten Hardware-Zugriff in einem User-Programm (das in einem Betriebssystem läuft) zu basteln, halte ich ohnehin für ziemlich daneben.Timm Thaler hat geschrieben:Ich weiss nun nicht, was z.B. der Raspi an dieser Stelle macht.
-Michael