Forum: Mikrocontroller und Digitale Elektronik TimerInterrupt für 10sek Timer und Retriggerung in einer anderen ISR


von Spice (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Spice (Gast)


Lesenswert?

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

von Spice (Gast)


Lesenswert?

keine Timergurus unterwegs?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Spice (Gast)


Lesenswert?

Vielen Dank für die kompetente Hilfe...
eine Frage noch, welchen Modus nehme ich am besten am Atmega8?
Besten Dank und gruß
Spice

von Karl H. (kbuchegg)


Lesenswert?

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
volatile uint8_t Sekunden;
2
uint8_t TickCnt = 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.

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
Noch kein Account? Hier anmelden.