Hi Leute,
kurz zu meinem Problem, ich möchte mit einem ATmega8 und 3.686400 MHz
Quarz einen Timer realisieren und wenn 10 sekunden verstrichen sind,
dann soll ein flag gesetzt werden, es sei denn innerhalb dieser
10sekunden findet in der ISR(INT0_vect) eine Retriggerung bzw reset des
Timers statt. Wie gehe ich da am besten vor und welchen TimerInt
verwende ich da am besten, ich steig durch die vielen Modis der Timer
nicht wirklich durch... Von mir aus kann die TimerISR so oft wie nötig
aufgerufen werden, aber nach 10sekunden (ohne Timerreset) soll ein flag
in der TimerISR gesetzt werden. Allerdings benutze ich auch parallel die
UART und dummerweise habe ich hier neulich einen Beitrag gelesen, dass
der Timerinterrupt eventuell die UART stört?
Mit welchem Modus wäre ich auf der sicheren Seite, ohne unnötig
"hochfrequente" Timerinterrupts auszulösen???
Besten Dank, schönen Feierabend und LG
Spice
Falscher Ansatz, das direkt mit dem Timer machen zu wollen.
Du benutzt den Timer als Zeitgeber, der zb. alle 1/100 Sekunde eine ISR
auslöst. In der ISR zählst du eine Variable hoch. Hat die Variable den
Wert 1000 erreicht, sind vom Starten des Timers an gerechnet 10 Sekunden
vergangen. Willst du den Timer resetten, setzt du die Variable einfach
wieder auf 0 zurück.
Das Auswerten der Variablen machst du in der ominösen Hauptschleife in
main(). D.h. die Timer-ISR zählt einfach nur die Variable hoch und sonst
nichts.
> habe ich hier neulich einen Beitrag gelesen, dass> der Timerinterrupt eventuell die UART stört?
Das tut er nur, wenn die Timer-ISR zu lange dauert.
Da du dich aber brav an die Konvention hältst, dass eine ISR nur das
Allernotwendigste machen soll, und alles andere in die Hauptschleife
ausgelagert wird, kann dir das nicht passieren.
Vielen Dank für die Hilfe,
genau in der art meinte ich das eigentlich auch, nur dass halt keine 100
INTs in der Sekunde ausgelöst werden, sondern bissl weniger vielleicht
(damit die Uart nicht gestört wird) Aber da ja nix gestört werden soll,
wenn meine ISR "nur" zählt, werde ich da so vorgehen. Allerdings habe
ich noch eine Frage zu
>Das Auswerten der Variablen machst du in der ominösen Hauptschleife in>main(). D.h. die Timer-ISR zählt einfach nur die Variable hoch und sonst>nichts.
Ich habe in meinem Code eine Funktion (nicht MAIN), die auswerten soll,
ob der Timerwert erreicht wurde. Stellt das ein Problem dar? Spielts es
eine Rolle, wo geprüft wird, wenns nicht gerade in der ISR selbst ist?
Wenn nun beispielsweise meine Funktion zum auswerten der Hilfsvariable
eine "kleine" UART routine mit enthält, wo eine Zeichenkette ausgegeben
wird und diverse PORTs geschaltet werden. Kann es sein, dass mein
Programm zu lange braucht, bis an die eigentliche Prüfstelle zb
void foo(void)
{
.......
if (hilfsvariable==1000)
{
.... ;
hilfsvariable = 0;
}
...
}
zu gelangen und ich sozusagen genau die 1000 nicht abgefragt bekomme bzw
"verpasse" ??? Ist es hier sinnvoller mit if (hilfsvariable >=1000)
abzufragen, da der Wert der Hilfsvariable ja in der Zeit, bis mein
Programm es prüft, um 1 (oder mehr inkrementiert) worden sein kann?
Würde mich über weitere Hilfe sehr freuen
MFG Spice
Spice wrote:
> nur dass halt keine 100> INTs in der Sekunde ausgelöst werden, sondern bissl weniger vielleicht> (damit die Uart nicht gestört wird)
Vergiss die UART. Die UART wird von einem Timer nicht gestört. Und
vergiss auch die Vorstellung, dass dir 100 Interrupts in der Sekunde
grossartig viel Rechenzeit kosten. Wenn in der ISR lediglich eine
Variable hochgezählt wird, dann bewegt sich der prozentuelle
Rechenzeitverbrauch dafür bei winzigen Prozentbereichen. Nichts worüber
du dir Gedanken machen musst.
In Timing-Probleme kommt man erst dann, wenn in einer ISR viel zu viel
passiert, wie zb irgendwelche Ausgaben auf LCD oder UART.
> Ich habe in meinem Code eine Funktion (nicht MAIN), die auswerten soll,> ob der Timerwert erreicht wurde. Stellt das ein Problem dar?
Sollte egal sein.
> Spielts es> eine Rolle, wo geprüft wird, wenns nicht gerade in der ISR selbst ist?
Völlig wurscht.
> Wenn nun beispielsweise meine Funktion zum auswerten der Hilfsvariable> eine "kleine" UART routine mit enthält, wo eine Zeichenkette ausgegeben> wird und diverse PORTs geschaltet werden. Kann es sein, dass mein> Programm zu lange braucht, bis an die eigentliche Prüfstelle zb
Das könnte allerdings sein.
Bei der UART Ausgabe muss ja unter Umständen gewartet werden, bis die
UART wieder frei ist. Dann muss halt in diese Warteschleife ebenfalls
eine ABfrage rein.
>> void foo(void)> {> .......> if (hilfsvariable==1000)
Machs eher so
if (hilfsvariable >= 1000)
Der Unterschied:
Wenn du in deinem Code an irgendeiner Stelle zu lange gebraucht hast und
der Timer schon um 1 weiter gezählt hat, dann ist in deiner Version der
Teufel los. Fragst du aber sicherheitshalber auf größer ab, dann stimmt
zwar das Timing nicht mehr ganz 100%, aber zumindest kommt es nicht zu
einem extremen Timingfehler, weil hilfsvariable einmal rundum zählen
muss, bis das nächste mal wieder 1000 auftaucht.
Spice wrote:
> Vielen Dank für die kompetente Hilfe...> eine Frage noch, welchen Modus nehme ich am besten am Atmega8?
Im Grunde ist es völlig egal.
Wenn ich keine besonderen Anforderungen an den Timer habe, nehm ich
gerne den stinknormalen Modus mit Overflow-Interrupt.
Die viel wichtigere Frage lautet ja: welchen Vorteiler nehm ich?
Dazu muss man ein bichen rechnen und probieren.
Mal angenommen du nimmst den Timer0. Dann kriegst du nach jeweils 256
Timer Ticks einen Overflow.
Wie setzt du nun den Vorteiler, so dass du damit was vernünftiges
anfangen kannst? Du möchtest ja möglichst genau eine bestimmte Zeit
abzählen.
Mal angenommen du nimmst 1024 als Vorteiler, dann kriegst du
3686400/256/1024 = 14.0625
Interrupts in der Sekunde.
Nicht berauschend. Die Nachkommastellen verhindern, dass du einfach auf
eine ganzzahlige Anzahl an Interrupt-Aufrufen wartest um 1 Sekunde
abzuzählen. Und auf 0.0625 Interrupts kann man nun mal nicht warten
Anderer Vorteiler:
3686400/256/256 = 56.25
genauso schlecht
Was ist mit 64?
3686400/256/64 = 225.0
Bingo! Geht sich genau aus. Bei einem Vorteiler von 64 entstehen exakt
225 Overflows in der Sekunde.
Damit wär für mich die Sache klar:
Timer0, Vorteiler 64, Overflow-Interrupt
Willst du nur ganze Sekunden zählen? Wenn ja, dann sieht die Overflow
Routine so aus ....
1
volatileuint8_tSekunden;
2
uint8_tTickCnt=0;
3
4
ISR(....)
5
{
6
TickCnt++;
7
if(TickCnt==225){
8
TickCnt=0;
9
Sekunden++;
10
}
11
}
... und je nachdem wie genau dein Quarz tatsächlich auf 3686400Hz
schwingt, erhöht sich die Variable Sekunden tatsächlich im Sekundentakt.