Forum: Mikrocontroller und Digitale Elektronik Timer OV-Interrupt von T1 und T3


von Peter Pan IV (Gast)


Lesenswert?

Hallo zusammen,

ich habe ein Problem:

In meiner Schaltung mit mega128 werkeln der Timer1 und der Timer3. Von
beiden wird der Timer-Overflow-Interrupt ausgewertet.
T1 löst ca. jede Sekunde aus und T3 löst ca. alle 10,1 Sekunden aus.

Bis auf den Interrupt von T1 klappt alles. Denn dieser Interrupt wird
ab und zu nicht ausgeführt.

Bei der Ursachenforschung stellt sich mir die Frage: Was passiert wenn
die T3-Interrupt-Routine noch läuft und währenddessen T1 seinen
Overflow-Interrupt meldet?
Wird(sollte) die T1-Interrupt-Routine ausgeführt werden sobald
diejenige von T3 beendet ist?

Hat jemand einen Tipp für mich? Vielen Dank!

von Peter M (Gast)


Lesenswert?

so weit ich weiß sollte die T3 ISR beendet werden und dann die T1 ISR
ausgeführt werden.
Der T1 OVF hat eine "höhere Priorität" als der T3, unterbricht aber
die ISR vom T3 nicht, da der ATmega kein Prioritätensystem unterstützt.

Folglich sollte die T1-ISR nach der T3-ISR ausgeführt werden.

mfg Peter M.

von Peter Pan IV (Gast)


Lesenswert?

Ja, von dieser Reihenfolge bin ich auch ausgegangen.

So ein Mist, irgendwo hab ich mir da ein Bug reingestrickt.

von johnny.m (Gast)


Lesenswert?

Hallo

Wie sieht denn der Code in den ISRs aus? Das hört sich fast so an, als
ob da irgendwelche komplizierten Sachen oder Wartezeiten drin sind?!?
Dann kann es natürlich passieren, dass ein oder mehrere Interrupts
geschlabbert werden. Wenn ein Interrupt-Ereignis eintritt und ein
anderes von der selben Quelle noch nicht bearbeitet ist, dann geht das
neue verloren.

Gruß

Johnny

von Peter Pan IV (Gast)


Lesenswert?

Hier der Code für ISR von Timer1:

// Timer 1 overflow interrupt service routine, Sekundentakt
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
tp_time--;
if(tp_time == 0)
   {
   plot_calc_show(); // mit printf wird auf ein GLCD geschrieben
   }
TCNT1H=0x8F;   // Neuladen des Timers
TCNT1L=0x85;
}

Die T1-ISR wird ab und zu unterdrückt. Diese Unterdrückung geschiet im
Ganzzahligen Raster von Timer3, also alle 10sec, oder alle 50sec. In
plot_calc_show() wird die Länge eines senkrechten Striches berechnet
und mit printf, über RS232(9600 Baud) auf ein GLCD ausgegeben.

Die gesammte Verweildauer innerhalb der T1-ISR dürfte bei ca. 2msec
liegen, sie ist also kurz genug, bevor nach einer Sekunde der neue
Interrupt kommt.


Und hier der Code für Timer3

// Timer 3 overflow interrupt, alle ca. 10,1 Sekunden
interrupt [TIM3_OVF] void timer3_ovf_isr(void)
{
brighttime_count++;
if(brighttime_count == bt)
   {
   Timer3_AUS;
   Timer3_IE_AUS;
   brighttime_count = 0;
   brightm = 0;
   }
}


Ich arbeite nur mit dem AVR-JTAG. Ein Echtzeittrace ist damit ja nicht
möglich.

Peter P.

von Rahul (Gast)


Lesenswert?

"plot_calc_show(); // mit printf wird auf ein GLCD geschrieben "

Ob sowas wirklich in eine ISR gehört? Das bezweifle ich.

von Peter Pan IV (Gast)


Lesenswert?

Rahul, Deine Zweifel sind natürlich berechtigt. Normalerweise kommt
soetwas in die main.
Da ich die senkrechte Linie im GLCD aber Sekundengenau zeichnen
muss(Plot im 1-Sekundenraster), habe ich diese feste Anbindung an den
Sekundentakt gewählt.

In der main würden sich Zeitabweichungen von wenigen ms zu großen
Zeitfehlern aufaddieren.


Peter P.

von Hannes L. (hannes)


Lesenswert?

> In der main würden sich Zeitabweichungen von wenigen ms zu großen
> Zeitfehlern aufaddieren.

Das glaube ich nicht.
In der ISR wird ein Flag gesetzt. In der Main wird dieses Flag geprüft
und falls es gesetzt ist, wird es gelöscht und der Job erledigt. Sollte
es Verzögerungen geben, weil die Main noch andere Arbeiten zu erledigen
hat, so kommt doch die nächste ISR pünktlich und setzt das Flag für die
nächste Ausgabe auch pünktlich. Es können sich also keine Verzögerungen
addieren.

...

von Wolfram (Gast)


Lesenswert?

>// Timer 1 overflow interrupt service routine, Sekundentakt
>interrupt [TIM1_OVF] void timer1_ovf_isr(void)
>{
>tp_time--;
>if(tp_time == 0)
>   {
>   plot_calc_show(); // mit printf wird auf ein GLCD geschrieben
>   }
>TCNT1H=0x8F;   // Neuladen des Timers
>TCNT1L=0x85;
>}

>In der main würden sich Zeitabweichungen von wenigen ms zu großen
>Zeitfehlern aufaddieren.

wenn du mit deiner Overflowroutine wirklich einen Sekundentakt
generieren willst dann wirst du aber am Ende des Tages eine gewaltige
Abweichung haben.
Hast du schon mal in den erzeugten Assemblercode geschaut?
Dein Funktionsaufruf erzwingt das alle Register gesichert werden.
(Sind das nicht 32???)
ein printf aus einem Interrupt heraus finde ich sehr mutig.
(Ist printf eigentlich reentrant?)
der Zugriff auf ein LCD dürfte noch für zusätzliche verschiebung
sorgen.
Wenn du wirklich genau arbeiten willst dann nimm den Output Compare
Modus und setze ein Flag(volatile),dass du im Hauptprogramm pollst.
Ich denke das wird um einiges sekundengenauer.
Eine Interruptzeit sollte im unteren uSekundenbereich liegen!
BTW: was passiert eigentlich wenn tp_time <0 wird?

von Rahul (Gast)


Lesenswert?

"BTW: was passiert eigentlich wenn tp_time <0 wird?"
Das sollte am besten irgendwas "unsigned" sein, damit es zu einem
Überlauf kommt. Ob der richtig ausgwertet wird, ist fraglich, oder?

von Peter Pan IV (Gast)


Lesenswert?

Erstmal danke für Eure Meinungen.

Werde versuchen die Grafikausgabe in der main zu steuern. Obwohl dort
schon ein externer ADC gepollt wird.


Vielen Dank!


Peter P.

von Peter Pan IV (Gast)


Lesenswert?

So, es klappt!

Eure Tipps, die Grafikroutine mit printf in die main zuverlegen war
Goldrichtig.
Und Zeitsynchron ist es auch.

Nochmals, vielen Dank!


Peter P.

von Rahul (Gast)


Lesenswert?

*Muaahh!*

von Hannes L. (hannes)


Lesenswert?

> Obwohl dort
> schon ein externer ADC gepollt wird.

ADCs pollt man nicht! Das kostet nur Rechenzeit, in der der Controller
Sinnvolleres tun könnte.

ADC fragt man entweder im ADC-Complete-Interrupt ab, oder in einem
Timer-Interrupt. Und wenn man mehrere Messquellen hat, dann schaltet
man sie nicht erst um, wenn man sie auslesen möchte, sondern
vorausschauen nach dem Auslesen der letzten Messquelle. Somit kostet
das Auslesen des ADCs absolut keine Wartezeiten.

Ich habe fast den Eindruck, dass ein Mega8 (Mega8535) mit 1MHz bei
vernünftiger Programmierung für deine Aufgaben voll reichen würde.

...

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.