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.
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.
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.
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.