Hi Zusammen! Kurze Frage: Ich möchte am Ende des Interrupthandlers Timer0 nicht nur mit "reti" dahin springen wo der Interrupt ausgelöst wurde, sondern an ein bestimmte Programmpunkt viel weiter davor. Kann/muss ich einfach mit "pop Akku" den Stack um einen zurücksetzen (wurde ja mit dem Interruptsprung auch erhöht) und dann einfach mit "rjmp Start" an meinen Punkt springen? Oder handel ich mir mit sowas Probleme ein? Gibs elegantere Möglichkeiten? thx & greetz Danny
Nö, denn das entspricht einem ret, du brauchst aber reti. Es geht aber anderst: Mir 2x pop den Stack verringern und mit 2x push die neue Sprungadresse laden.
In Interruptroutinen am Stack herummanipulieren, das ist sehr gefährlich. Viel Spaß bei der Fehlersuche. Ich wüßte auch keinen Grund, so etwas zu machen - Interrupts und Unterprogramme sind eigentlich dafür da, daß sie ausgeführt werden, ohne den Ablauf des übrigen Codes zu stören. Denk mal z.B. über ein Flag nach, das in Deiner Hauptschleife abgefragt wird.
Naja, es geht darum das ich Daten synchron Empfange und den Takt (fallende Flanke) nicht über ein ext.Interrupt abfrage, sondern einfach mit "warte bis high" - "warte bis low". Ist sicher wenig professionell aber ich hab entschieden das es vom Programm her in diesem Fall einfacher ist. Falls der Empfänger nun aber mal ausser Takt fällt soll per Timer das "warten" unterbrochen werden. Würd ich den Stack nun nicht manipulieren würde ich nach dem "reti" im Interrupthandler ja wieder in der Warteschleife hängen... thx & greetz Danny
Ja, der war von von mir... Der Fehler lag am Ende woanderst, bzw. am Assembler, der Byte und Word Adressen gleichsetzt. Mit einem 8051 habe ich das schon oft genug gemacht, das geht wunderbar. Außerdem ist das überhaupt nicht gefährlich wenn man das in Assembler in einem Interupt macht. Es gibt ja nichts, das den Interrupt verändert, und wenn doch, das würde auch im normalen Betrieb den Stack verhauen.
"Mit einem 8051 habe ich das schon oft genug gemacht, das geht wunderbar." Wohl kaum ! Ohne ein RETI kannst Du beim 8051 nie wieder einen Interrupt ausführen. "Außerdem ist das überhaupt nicht gefährlich". Na aber und ob. Du holst doch nur die Returnadresse vom Stack, was da sonst noch so auf dem Stack liegt (Unterfunktionsreturnadressen, Daten) davon hast Du nicht die geringste Ahnung. D.h. Dein Stack läuft Dir irgendwann völlig aus dem Ruder. Die einzige Möglichkeit ist, man springt ins Main zurück und dort wird der Stack komplett neu initialisiert. Und beim 8051 mußt Du auch noch bis zu 4 Dummy-RETIs machen (eins je Interruptlevel). Peter
So ein Vorgehen macht durchaus Sinn, wenn man es bedacht anwendet. Und davon wurde auch z.B. in Heimcomputerzeiten viel Gebrauch gemacht. Ich hatte letztens so einen Fall, wo ich es auch brauchte. Leider lässt sich beim ATtiny 12 kein Stack manipulieren. Das Hauptprogramm musste in einer sehr kurzen Schleife einen Pin toggeln, mehr nicht. Da war aber keine Zeit, noch Bits abzufragen. Per Timerinterrupt sollte dann diese Schleife umgeschaltet werden zu einer anderen, die etwas länger oder kürzer läuft. Um ein unterschiedliches Tastverhältnis zu erreichen. Also: Sagt niemals nie, aber man sollte schon mit Bedacht sowas einsetzen. Oft gibt es bessere Lösungen. Winfried
Bevor hier wieder die selbe Diskussion losgeht wie letzes mal: a) es funktioniert einwandfrei ! b) ich lösche die Rücksprungadresse (=die letzen beiden Bytes auf dem Stack) mit 2x POP c) ich schreibe die neue Rücksprungadresse mit 2x push in den Stack d) dann kommt ein reti e) Bei einem Interrupt werden nur Adressen übergeben und keine Daten, außerdem müssen die Adressen die letzen Daten auf dem Stack sein, denn nach dem Interrupt befindet sich das Programm ja schon im Interrupt. In C geht das nicht so leicht, denn man weiß nie was der Compiler macht, aber in Assembler geht das problemlos.
man könnte auch den stack mit 2x pop befreien und dann mit nem rjmp und sei weitermachen, dann braucht man keinen push der zeitraubend ist. so: stimmt das eigentlich dass der µC durch ein falsches programm abrauchen kann? z.b. stack-overflow? dave
"so: stimmt das eigentlich dass der µC durch ein falsches programm abrauchen kann? z.b. stack-overflow?" Nein, es stimmt nicht. Allein durch falsche Software wirst du keinen µC kleinkriegen. mfg
"a) es funktioniert einwandfrei !" Aber nur, wenn Du absolut unstrukturierten Spaghettikode verzapfst, der keinerlei Unterfunktionen aufruft und keinerlei Daten pusht. Denn nur dann weißt Du, daß nur die Returnadresse auf dem Stack liegt und kannst diese löschen. Bei strukturierten Programmen, die Unterfunktionen verwenden liegen da noch ne Menge anderer Returnadressen und Daten drauf, je nach Unterfunktionstiefe und die bleiben dann als Müll liegen. Beispiel: Funktion A ruft Funktion B auf, die 2 Register puscht, dann kommt ein Interrupt C. Dieser entfernt die Returnadresse zu B und springt wieder nach A. Ergo die Returnadresse zu A und die 2 gepuschten Register bleiben liegen. Beim nächsten Interrupt dann wieder das gleiche usw. bis der Stack überläuft. Peter
>Funktion A ruft Funktion B auf, die 2 Register puscht, dann kommt ein >Interrupt C. Der Interrupt legt seine Rücksprungadresse auf den Stack. Und solange der Interrupt nicht durch einen anderen unterbrochen wird (zumindest nicht in dem Teil, wo der Stack manipuliert wird) passiert nichts ! >Dieser entfernt die Returnadresse zu B und springt wieder nach A. >Ergo die Returnadresse zu A und die 2 gepuschten Register bleiben >liegen. Nein ! Sonst würde das normale reti ja auch die Adresse von B löschen... >Beim nächsten Interrupt dann wieder das gleiche usw. bis der Stack überläuft. Nö, oder wie kommtst du bei folgender Rechnnung zu einem anderen Ergebnis als Stack(nachher)= Stack(vorher)? Stack(nachher)= Stack(vorher)+2*(-1)+2*(+1) -1=pop +1=push Peter
@Benedikt, kehrt der Interrupt normal zurück, so tut er dies zu Funktion B, die er ja unterbrochen hat. Diese wiederum popt die gesicherten Register wieder und kehrt dann zu A zurück. Geht der Interrupt aber direkt zu A, bleiben notgedrungen 4 Byte (ein Call + 2 Datenbyte) auf dem Stack liegen. Man kann aber auch nicht 6 Byte entfernen, da man ja nicht weiß, wo man unterbrochen hat, ob in B oder B bzw. in B vor oder nach dem Puschen. Im Interrupt können also bezogen auf Funktion A: 2, 4, 5 oder 6 Byte im Stack liegen. Peter
Ups ein Dreckfuhler, richtig: ... ob in A oder B bzw. in B vor oder nach dem Puschen. Peter
OK, stimmt. Wenn man aber keine Unterprogramme verwendet dann geht es, (ansonsten macht es ja auch wenig Sinn, zurück ins Hauptprogramm zu springen...
dann bastel mal einen halbwegs komplexen code in asm ohne unterprogramme. es ist schoon schwer genug mit welchen da ordnung und übersicht zu halten...
Das geht schon, kommt immer darauf an was das Programm machen soll. Ich habe mehrere Programme, die komplett ohne per call aufegerufene Unterprogramme auskommen. Alles läuft über Interrupts (mit Stackmanipulation) und rjmp. Ist ein Videogenerator.
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.