Hallo, habe ein Problem damit einen timeout von 100ms zuverlässig berechnen zu lassen. Ich lasse einen timerinterrupt jede millisekunde geschehen, wo dann ein millisekunden Zähler um 1 erhöht wird. Sobald 1000 ms, also 1 Sekunde erreicht ist, wird ein Sekunden zähler erhöht und der millisekunden Zähler wieder auf Null gesetzt. In meinem Programm messe ich den timeout, in dem ich die aktuelle ms-Zeit bei einem Ereignis in einer Variable abspeichere und bei einem weiteren Eregnis die gespeicherte ms-Zeit von der aktuelle ms-Zeit subtrahiere und das Ergebnis (die Differenz) mit dem festgesetzten Timeout-Wert vergleiche. Das funktioniert z.B. unter folgender Bedingung: Timeout: 100ms alte Zeit: 450ms neue Zeit: 650ms Differenz: 650ms - 450ms = 200ms ==> timeout erreicht Es funktioniert allerdings nicht z.B. unter dieser Bedingung: Timeout: 100ms alte Zeit: 980ms neue Zeit: 60ms Differenz: 60ms - 980ms = -920ms ==> timeout erreicht obwohl erst 80ms verstrichen sind. Hat jemand eine Idee, wie ich dieses Problem möglichst elegant umgehen kann, ohne auch noch jedesmal die Sekunden vergleichen zu müssen und dann entsprechend alles berechnen zu lassen? Ich habe den Quellcode jetzt nicht eingefügt, weil der nichts zur Sache tun sollte, geht ja eigentlich eher um ein mathematische Problem...
Du must abfragen ob die alte Zeit groesser als die neue Zeit ist. if (alteZeit > neueZeit) { Zeit = 1000-alteZeit + neueZeit; } else { Zeit = neueZeit - alteZeit; } Gruss Helmi
Hi Nach der Subtraktion Carry-Flag auswerten. Wenn gesetzt 1000 zu Ergebnis addieren. MfG Spess
Hallo, kommt jetzt zwar auf die Umgebung an, aber ich nahem für sowas ein Zählregister, das in jedem Interrupt um 1 erhöht wird. Eintretende Ereignisse setzen das Register einfach auf 0. Die auf das Timeout wartende Routine vergleicht nur mit der gewünschten timeout-Zeit und wenn erreicht oder größer -> Timeout. Gerade in ASM; sehr sparsam IRQ-Routine: inc timeout Bearbeitungsroutine: clr timeout Testroutine: cpi timeout, WARTEZEIT brsh timeout_da Wäre bei Dir bei 1ms-IRQ und 100ms Timeout passend für ein Register. Aber selbst im SRAM kosten push temp lds temp,time_reg inc temp sts time_reg,temp pop temp in einer Interruptroutine meist verkraftbar. Gruß aus Berlin Michael
Danke für die 3 Lösungsansätze. @amiga Das hatte ich auch erst überlegt, bzw. habe ich mit dieser Methode vorher überprüft, ob es tatsächlich an dem überlauf liegt. Das ist auch prinzipiell durchaus eine Idee, allerdings ist das in meinem Fall etwas blöd, da ich eine weitere Variable einführen muss (auch wenn diese, wie meine anderen auch im SRAM abgelegt wird). Den ms und s Zähler in der ISR brauche ich auch noch als Zeitbasis für andere Dinge, daher wollte ich diesen auch für den timeout verwenden. @spess53 Die Idee mit dem Carry Flag ist auch eine Möglichkeit allerdings eher für 8-Bit Operationen geeignet, oder irre ich mich?. @helmi1 Das schien mir in meinem Fall die beste Möglichkeit zu sein, ist auch sehr einleuchtend allerdings habe ich nun ein Problem, dass das ganze nicht so hinhaut, daher hier mal ein Codeschnipsel für den relevanten Bereich:
1 | lds XL, aktuelleZEIT_ms |
2 | lds XH, aktuelleZEIT_ms + 1 |
3 | lds YL, alteZEIT_ms |
4 | lds YH, alteZEIT_ms + 1 |
5 | |
6 | cp XL, YL ; aktuelleZEIT < alteZEIT ? |
7 | cpc XH, YH |
8 | brlo kleiner |
9 | |
10 | sub XL, YL ; aktuelle Zeit - alte Zeit |
11 | sbc XH, YH |
12 | |
13 | rjmp vergleich |
14 | |
15 | kleiner: |
16 | ldi temp, LOW(1000) ; (1000 - alte Zeit) + aktuelle Zeit) |
17 | ldi temp_2, HIGH(1000) |
18 | sub temp, YL |
19 | sbc temp_2, YH |
20 | add XL, temp |
21 | adc XH, temp_2 |
22 | |
23 | vergleich: |
24 | lds temp, LOW (timeout) ; Differenz > timeout ? |
25 | lds temp_2, HIGH (timeout) |
26 | cp XL, temp |
27 | cpc XH, temp_2 |
28 | brlo keinTIMEOUT |
29 | breq keinTIMEOUT |
30 | |
31 | ; . |
32 | ; . (Führe etwas aus) |
33 | ; . |
34 | |
35 | keinTIMEOUT: |
36 | ; . |
37 | ; . (Führe etwas anderes aus) |
38 | ; . |
Das müsste doch so die Umsetzung von amiga sein?
Hi >@spess53 >Die Idee mit dem Carry Flag ist auch eine Möglichkeit allerdings eher >für 8-Bit Operationen geeignet, oder irre ich mich?. Nein. geht auch bei 16 Bit. ldi r16,Low(20) ldi r17,High(20) ; neue Zeit Ldi r18,Low(980) ldi r19,High(980) ; alte Zeit sub r16,r18 sbc r17,r19 ; Subtrakion brcc cccc ldi r18,Low(1000) ldi r19,High(1000) add r16,r18 adc r17,r19 ; 1000 addieren cccc: cpi r16,100 ; fertig MfG Spess
Lass als Zeitgeber einfach (zusätzlich) ein Int hochzählen. Das wird zwar irgendwann überlaufen, aber der Windowstimer macht das auch. Du brauchst zwei Funktionen: 1) timer_start speichert den aktuellen Wert. 2) timeout (x) sagt, ob seit dem Start die Zeit x verstrichen ist oder noch nicht. Dazu bildest Du einfach nur die Differenz zwischen gespeichertem Zeitpunkt und dem aktuellen Zeitgeberwert und prüfst ab, ob der Wert <= 0 ist. Das funktioniert auch bei einem Zählerüberlauf. Nachteil ist eigentlich nur, dass die Auflösung durch die Zählerbreite beschränkt ist. So meine bescheidene Erfahrung...
> allerdings ist das in > meinem Fall etwas blöd, da ich eine weitere Variable einführen muss > (auch wenn diese, wie meine anderen auch im SRAM abgelegt wird). Den ms > und s Zähler in der ISR brauche ich auch noch als Zeitbasis für andere > Dinge, daher wollte ich diesen auch für den timeout verwenden. Diese Variable brauchst Du doch sowiso. Dabei ist es unerheblich, ob Du darin den Termin des Timeouts (als feste Zeit zum Vergleichen) oder einen weiteren Zähler führst. Ich würde es ähnlich wie Spess machen, vermutlich im 16ms-Raster, da ich aus dem 1ms-Int (nutze ich meist für LCD-update und Drehgeber-Abfrage) oft noch einen 16ms-Takt zur Tasten-Entprellung ableite. Dadurch reicht es dann meist auch achtbittig. ~
@spess53 Danke, habe vorerst deinen Vorschlag eingebaut!!! Funktioniert sogar jetzt beides, der Schnippel, den ich gepostet hatte (war noch ein Flüchtigkeitsfehler an anderer Stelle :-) ) und das was du geschrieben hast, wobei dein Schnippel noch um einiges kürzer ist. @Bobby und sinusgeek Auch euch nochmal vielen Dank. Natürlich führen mehrere Wege nach Rom, die Hauptsache ist, man kommt an. Ich möchte jetzt gar nicht beurteilen welche Methode besser ist (sofern man das überhaupt kann), funktionieren tun sie sicher alle. Meine Entscheidung für helmis und spess Lösung war hauptsächlich die, dass sich das ungefähr mit dem deckt, was ich mir "vorgestellt" hatte. Außerdem möchte ich die ISR vorerst wirklich nicht weiter auf blähen, auch wenn eine weitere Variable nicht all zu viel Ausführungszeit und SRAM Speicher belegt, vielleicht kommt da später noch was anderes mit rein. Falls trotzdem noch jemand veranschaulichen kann, dass es eine wesentlich effizientere Lösung gibt, bin ich dafür offen. Ansonsten habt ihr mir schonmal ein ganzes Stück weiter geholfen, zumindest funktioniert nun dieser Teil einwandfrei - Dankeschön!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.