Moin zusammen, bin gerade dabei die Software RTC von ATMEL zu übernehmen, und stelle fest, dass die die ganzen if-Entscheidungen (also ist ++sekunde >60 ...) in der Interrupt-Routine haben. Ist das nicht ungeschickt? - Da wäre es doch besser lieber nur eine FLAG zu setzen, welche dann in der while Routine aufgefangen und dann die if-Verzweigungen durchforstet... ? In diesem Zusammenhang wollte ich Fragen, wie viele Cycles eigentlich so ne Interrupt-Routine haben sollte. Natürlich so wenig wie geht - doch wo hört da der Spaß auf? Danke Marcel if (++t.second==60) //keep track of time, date, month, and year { t.second=0; if (++t.minute==60) { t.minute=0; if (++t.hour==24) { t.hour=0; if (++t.date==32) { t.month++; t.date=1; } else if (t.date==31) { if ((t.month==4) || (t.month==6) || (t.month==9) || (t.month==11)) { t.month++; t.date=1; } } else if (t.date==30) { if(t.month==2) { t.month++; t.date=1; } } else if (t.date==29) { if((t.month==2) && (not_leap())) { t.month++; t.date=1; } } if (t.month==13) { t.month=1; t.year++; } } } }
"Soviele dass der Interrupt beendet ist, bevor er erneut auftritt". In dem Fall hätte die ISR also 60 Sekunden. das mit den vielen ifs darin geht also in Ordnung, die sind sowieso nicht besonders aufwändig (=> generierte ASM-Sources lesen).
Marcel schrieb: > Moin zusammen, > > bin gerade dabei die Software RTC von ATMEL zu übernehmen, und stelle > fest, dass die die ganzen if-Entscheidungen (also ist ++sekunde >60 ...) > in der Interrupt-Routine haben. > Ist das nicht ungeschickt? Von dem ganzen Code wird aber bei der überwiegenden Mehrzahl der Aufrufe nur ein verschwindend kleiner Bruchteil ausgeführt. Und der Rest sind triviale Operationen. Wenn der Compiler das übersetzt hast schrumpft das auf vielleicht 15 bis 20 Assembler Operationen zusammen. - Da wäre es doch besser lieber nur eine FLAG > zu setzen, welche dann in der while Routine aufgefangen und dann die > if-Verzweigungen durchforstet... ? In dem Fall nicht. Du willst auf keinen Fall haben, dass eine Sekunde verloren geht, weil der µC gerade beschäftigt ist. Da soll er lieber ab und an die 15 oder 20 Instruktionen durchackern und gut ists. Und wenns alle 4 Jahre, am 28 Februar um Mitternacht, mal ein paar µSekunden länger dauert, wird das wahrscheinlich auch kein Beinbruch sein. Wenn doch, dann kann man natürlich den kompletten Datums-Teil rausziehen und nur diesen über ein JobFlag in der Hauptschleife anstossen. In 24 Stunden wird der kleine Racker dann ja doch irgendwann Zeit haben, das Datum nachzuziehen.
Nachtrag: Natürlich nur eine Sekunde. Ist trotzdem eine Ewigkeit für den µC.
Marcel schrieb: > In diesem Zusammenhang wollte ich Fragen, wie viele Cycles eigentlich so > ne Interrupt-Routine haben sollte. Es empfiehlt sich, dass ein sekündlich auftrender Interrupt weniger als eine Sekunde braucht. ;-) Wenn dir diese Auskunft zu blöd klingt: Das hängt ganz davon ab, welche maximale Latenzzeit deine Anwendung verkraftet. Jedenfalls ist so eine ISR durchaus üblich.
Hilfs-Sysop schrieb:
> "Soviele dass der Interrupt beendet ist, bevor er erneut auftritt".
Werden eigentlich auch die anderen Interrupts-Flags bei einem Ereignis
gesetzt, wenn der Controller sich noch in einer anderen
Interrupt-Routine befinden?
Marcel schrieb: > Hilfs-Sysop schrieb: >> "Soviele dass der Interrupt beendet ist, bevor er erneut auftritt". > > Werden eigentlich auch die anderen Interrupts-Flags bei einem Ereignis > gesetzt, wenn der Controller sich noch in einer anderen > Interrupt-Routine befinden? Ja, klar. Aber die zugehörige ISR wird erst dann ausgeführt, wenn die momentane (+ 1 Befehl) beendet ist.
Karl heinz Buchegger schrieb: > Ja, klar. > Aber die zugehörige ISR wird erst dann ausgeführt, wenn die momentane (+ > 1 Befehl) beendet ist. Nur, wenn deren Ausfuehrung nicht freigegeben ist.
Supi - vielen Dank an alle Habt mir wie der Wind geantwortet! Grüße Marcel
Für die Betrachtung ist noch wichtig wie lange not_leap() dauert... ich vermute mal nicht so lange aber....
Hier nochmla die leap Funktion für die die es interessiert :) char not_leap(void) //check for leap year { if (!(t.year%100)) return (char)(t.year%400); else return (char)(t.year%4); } Sehe gerade, dass hier geteilt wird, ich glaube da ist es einfacher die nächten xx Schaltjahre im Klartext zu schreiben als diese Divison Bib noch einzubinden Noch ne Frage meinerseits die nicht ganz in diesen Thread passt: Ich nutze jetzt nen Timer2 als RTC (OVERFLOW_INTERRUPT). Nun möchte ich mit diesem TIMER auch noch einen Taster entprellen. Kann ich ohne weiteres das Output-Compare Register beschreiben und dann das OUTPUT_COMPARE Interrupt aktivieren oder muss ich erst den momentanen Zählerstand speichern, den Timer anhalten, um dann das Output-Compare Interrupt und das Register zu setzen/beschreiben und dann wieder den Timer starten?
Marcel schrieb: > Hier nochmla die leap Funktion für die die es interessiert :) > > char not_leap(void) //check for leap year > { > if (!(t.year%100)) > return (char)(t.year%400); > else > return (char)(t.year%4); > } > > Sehe gerade, dass hier geteilt wird, ich glaube da ist es einfacher die > nächten xx Schaltjahre im Klartext zu schreiben als diese Divison Bib > noch einzubinden Wie schon gesagt: 1) tritt der Fall nur alle 4 Jahre auf 2) wenn das tatsächlich ein Problem ist, kann man das ganze Datumshochzählen auch in die Hauptschleife (mit Jobflag) auslagern. > Noch ne Frage meinerseits die nicht ganz in diesen Thread passt: > Ich nutze jetzt nen Timer2 als RTC (OVERFLOW_INTERRUPT). Nun möchte ich > mit diesem TIMER auch noch einen Taster entprellen. Soweit so gut > Kann ich ohne > weiteres das Output-Compare Register beschreiben und dann das > OUTPUT_COMPARE Interrupt aktivieren Wozu brauchst du den Output Compare? Tasten entprellen ist zeitlich gesehen ziemlich anspruchslos. Ob du die Tasten alle 5ms, oder alle 10ms oder alle 15ms abfrägst, ist Jacke wie Hose. Wenn dein Overflow Interrupt so ungefähr in dieser zeitlichen Größenordnung aufgerufen wird, dann passt das schon. Das muss nicht genau alle 10ms sein. Gerade beim Tastenentprellen kann man es sich leisten, dass die Zeit zwischen zwei Abfragen sich an dem orientiert, was gerade vorhanden ist. Kein menschlicher Benutzer dieser Welt kann per Gefühl feststellen ob ein Tastendruck jetzt nach 40 oder doch erst nach 60ms zu einer Aktion führt. > Kann ich ohne weiteres das Output-Compare Register beschreiben und > dann das OUTPUT_COMPARE Interrupt aktivieren Ja kannst du. > oder muss ich erst den momentanen Zählerstand speichern, wozu? Ein gestoppter Timer verliert nicht seinen Zählerstand. > den Timer anhalten, Das willst du eigentlich nicht. Denn dann gehen deiner Uhr Takte verloren
Karl heinz Buchegger schrieb:
> Wozu brauchst du den Output Compare?
Ich bin im Energiesparmodus meines Mikrocontrollers. Wenn der dann durch
einen PCINT-Interrupt geweckt wird. Wenn der Taster gedrückt wurde, dann
wird bem Timer Output-Compare aktiviert (µC legt sich wieder schlafen).
Alle 200ms bspweise wird im Output Compare Interrupt geschaut, ob der
Taster noch gedrückt ist (press_long wenn insgesamt über 5s) oder wenn
der Taster nicht mehr gedrückt ist (press_short <5s)
Haste da sogar eine bessere Idee?
Grüße
Marcel
Marcel schrieb: > Karl heinz Buchegger schrieb: >> Wozu brauchst du den Output Compare? > > Ich bin im Energiesparmodus meines Mikrocontrollers. Ah. OK > Haste da sogar eine bessere Idee? Vielleicht stell ich mich jetzt blöd an. Aber du sagtest, du hättest den Timer 2 als RTC benutzt. Ich hab das so verstanden, dass du da einen 32kHz Quarz drann hast und du den Overflow Interrupt benutzt um die Uhr hochzuzählen. Korrekt? Wenn du jetzt aber sowieso den Overflow Interrupt schon am laufen hast, dann kannst du ja auch dort im Overflow mal einen Rundumblick auf alle Tasten machen und die (natürlich entprellt) auswerten (zb. Danegger Entprellung) Geh ich jetzt von falschen Voraussetzungen aus?
Karl heinz Buchegger schrieb: > Vielleicht stell ich mich jetzt blöd an. > Aber du sagtest, du hättest den Timer 2 als RTC benutzt. Ich hab das so > verstanden, dass du da einen 32kHz Quarz drann hast und du den Overflow > Interrupt benutzt um die Uhr hochzuzählen. Ja das ist Korrekt. :) Klar man kann das einfach in die Routine mit reinbauen, denn Flags setzte ich bereits in der PCINT-Routine, dass der Taster gedrückt wurde. Ne Gute Idee - Der einzige Nachteil wäre doch aber hier, dass der Benutzer wenns hart kommt 1Sekunde warten müsste bis der Tasten-Druck (entprellt) erkannt würde. (Overflow Interrupt ist sekündlich) Oder ich mache das anders: In dem PCINT INTERRUPT wird ja der Pinchange-Interrupt für den Taster abgestellt. Den könnte man jetzt wieder in dem Overflow Interrupt an stellen. Doch würde auch dies bedeuten, dass der Benutzer max. eine Sekunde zwischen 2Tastendrücken warten müsste :( Hmm - ich glaube da führt kein Weg an dem Output Compare drüber - gerade weil ich da auch fest 200ms Abstände einbauen kann und nicht ne Schwankung von 0.00001 bis 1.0 Sekunden habe. oder?
Marcel schrieb: > Karl heinz Buchegger schrieb: >> Vielleicht stell ich mich jetzt blöd an. >> Aber du sagtest, du hättest den Timer 2 als RTC benutzt. Ich hab das so >> verstanden, dass du da einen 32kHz Quarz drann hast und du den Overflow >> Interrupt benutzt um die Uhr hochzuzählen. > > Ja das ist Korrekt. :) > > Klar man kann das einfach in die Routine mit reinbauen, denn Flags > setzte ich bereits in der PCINT-Routine, dass der Taster gedrückt wurde. > > Ne Gute Idee - Der einzige Nachteil wäre doch aber hier, dass der > Benutzer wenns hart kommt 1Sekunde warten müsste bis der Tasten-Druck > (entprellt) erkannt würde. (Overflow Interrupt ist sekündlich) OK. Das wusste ich nicht. Bin von 32kHZ / 256 = 125Hz ausgegangen. Alle ~80ms einmal kurz auf die Tasten geschaut reicht ja auch aus. Aber wenn du natürlich die 32kHz mit einem Prescaler auf 256Hz runtergebrochen hast, gehts nicht. 1 Sekunde istzu lahm. Da musst du zu deinem Gerät eine Flasche Baldrian mit ausliefern. > Hmm - ich glaube da führt kein Weg an dem Output Compare drüber - gerade > weil ich da auch fest 200ms Abstände einbauen kann und nicht ne > Schwankung von 0.00001 bis 1.0 Sekunden habe. Ja ist ok. Ich bin von falschen Zahlen ausgegangen.
Karl heinz Buchegger schrieb: > Da musst du zu > deinem Gerät eine Flasche Baldrian mit ausliefern :-D O.K Dank Dir Grüße Marcel
Ein Denkanstoss zu deiner RTC-Int als Frage formuliert: Sperrst du die Interrupts (bzw. zumindest den RTC-Int), wenn du deine t-Struktur irgendwo im Hauptprogramm ausliest ? Nur mal so eine Überlegung zum Restrisiko.
APW schrieb: > Sperrst du die Interrupts (bzw. zumindest den RTC-Int), wenn du deine > t-Struktur irgendwo im Hauptprogramm ausliest ? Nein bislang noch nicht. - Ist das ratsam?
Marcel schrieb: > APW schrieb: >> Sperrst du die Interrupts (bzw. zumindest den RTC-Int), wenn du deine >> t-Struktur irgendwo im Hauptprogramm ausliest ? > > Nein bislang noch nicht. - Ist das ratsam? Das könnte hilfreich sein Angenommen es ist 03 Uhr 59 und 59 Sekunden Du fängst an die Uhrzeit auszulesen 3 Stunden. gut Jetzt kommt der Interrupt. Als Folge davon wird die Uhrzeit erhöht. Zu 4:00:00 Der Interrupt ist beendet und deine Ausleseroutine macht weiter. 0 Minuten und 0 Sekunden Hoppla. Deine Ausleseroutine hat ermittelt, das es jetzt gerade 3:00:00 ist. Deine in der ISR geführte Uhr sagt aber es sei 4 Uhr!
Man kann das auch ohne Interrupt-Sperre machen. Erst die kleinste Einheit lesen, dann den Rest, und hinterher nochmal die kleinste Einheit mit dem vorher gelesenen Wert vergleichen. Und das solange wiederholen bis es übereinstimmt.
@ A. K. (prx) >Man kann das übrigens auch ohne Interrupt-Sperre machen. Erst die >kleinste Einheit lesen, dann den Rest, und hinterher nochmal die >kleinste Einheit mit dem vorher gelesenen Wert vergleichen. Und das >solange wiederholen bis es passt. Und was hat man da gewonnen, vor allem im Worst Case? Eine kurze Interruptsperre ist sicher und vorhersagbar. MfG Falk
Das ist nur eine Alternative. In diesem Fall hier ist es meistens egal was man macht. Es gibt freilich Fälle, wo die Update-Sperre während des Auslesens problematisch oder unmöglich ist. Beispielsweise wenn man dafür mehrere Hardware-Register ausliest, z.B. einen Timer und seinen Prescaler.
A. K. schrieb: > Das ist nur eine Alternative. In diesem Fall hier ist es meistens egal > was man macht. Es gibt freilich Fälle, wo die Update-Sperre während des > Auslesens problematisch oder unmöglich ist. Beispielsweise wenn man > dafür mehrere Hardware-Register ausliest, z.B. einen Timer und seinen > Prescaler. Hm, da ist die Variante mit dem kurzen sperren der Interrupts aber vermutlich einfacher und schneller.
Karl heinz Buchegger schrieb: > Hoppla. Deine Ausleseroutine hat ermittelt, das es jetzt gerade 3:00:00 > ist. Deine in der ISR geführte Uhr sagt aber es sei 4 Uhr! Oh mann, Danke A.K. für den Denkanstoß, dass hatte ich gar nicht bedacht.
Klaus schrieb: > Hm, da ist die Variante mit dem kurzen sperren der Interrupts aber > vermutlich einfacher und schneller. Macht kaum einen Unterschied, je nachdem auf aufwendig es ist, die Interrupts zu sperren (bei ARM7 sind das beispielsweise mehrere Befehle). Und wenn die Werte per Hardware hochgezählt werden, dann hilft eine Interrupt-Sperre rein garnichts.
Naja bei HW Registern gibt es ja meistens eine gewisse Reihenfolge wo sowas dann nicht auftritt. Und genausogut könnte man sage, wenn das incrementierungsintervall im gleichen Zeitrahmen wie: Auslesen, Speicher, Auslesen, Vergleichen liegt liest du unendlich oft den nächsten Wert ohne zu einem Ergebnis zu kommen...
Läubi .. schrieb: > Naja bei HW Registern gibt es ja meistens eine gewisse Reihenfolge wo > sowas dann nicht auftritt. Bei den 16-Bit Timer-Registern einen AVRs ja. Bei Timer/Prescaler eines LPC2000 oder STM32 ist mir davon nichts bekannt. > Und genausogut könnte man sage, wenn das incrementierungsintervall im > gleichen Zeitrahmen wie: Ja, das muss man berücksichtigen. In diesem Zeitbereich hat man aber ohnehin keine Alternative. Wertebereich überprüfen geht dann.
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.