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!
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.
Ja, von dieser Reihenfolge bin ich auch ausgegangen. So ein Mist, irgendwo hab ich mir da ein Bug reingestrickt.
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
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.
"plot_calc_show(); // mit printf wird auf ein GLCD geschrieben " Ob sowas wirklich in eine ISR gehört? Das bezweifle ich.
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.
> 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. ...
>// 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?
"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?
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.
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.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.