Hallo, wie kann ich folgendes Problem lösen? Ich programmiere einen ATmega32 in C. Ich löse einen Interrupt per Timer1 aus. In der Interrupt-Funktion führe ich ein paar Befehle aus. Soweit funktioniert alles wunderbar. Wie kann ich die Interrupt-Funktion verlassen und im Hauptprogramm an einer bestimmten Stelle (Label) weitermachen. Momentan läuft das Programm an der Stelle weiter an der es unterbrochen wurde. Mit dem Goto-Befehl funktioniert es nicht, da er innerhalb der Interrupt-Funktion das Label aus dem Hauptprogramm nicht kennt??? Danke Gruß Ralf
solche Faxen solltest du in gar keinem Fall anfangen. Extrem fehleranfällig. 2 prinzipielle Möglichkeiten: -die zu erledigenden Sachen in der ISR bearbeiten, je nach Zeitbedarf dafür und nur unkritischen oder gar keinen anderen Interrupts ist das möglich -in der ISR ein flag setzen, welches in der main abgefragt wird und dann evtl. die zu erledigende Funktion aufruft Was du vorhast, gibt garantiert Chaos. Das kleinste Problem ist noch der Hardwarestack, den wieder "gerade" zu biegen, bekommt man noch hin, ebenso das durch das fehlende reti noch nicht wieder freigegeben I-flag. Aber der Compiler arbeitet auch viel mit den Indexregistern (X,X,Z) zur Parameterübergabe, Datenstack u.a., was du mit SIcherheit gar nicht überblickst. Kann auch sein, dass das nächste Compiler-update in diesem Bereich völlig anders arbeitet, dann stehst du komplett auf dem Schlauch. Lass es sein, ist der einzige Rat, den ich dir geben kann.
noch was vergessen: Bei Eintritt in die ISR werden (wenn nicht extra abgeschaltet) automatisch diverse Register gerettet, normalerweise auf dem stack. Wieviele, weist du nicht, das ergibt das Studium des listings. Um nun nicht in kürzester Zeit einen stack-overflow zu produzieren, musst du den SP um exakt diese Zahl+2 (Rücksprungadresse) korrigieren. Eine kleine Änderung in der ISR, und schon kann die Anzahl der in der ISR geretteten Register anders sein, da hast du kaum EInfluss drauf.
Die Idee eine Variable auf 1 zu setzen und sie im Hauptprogramm abzufragen hatte ich auch schon. Aber ich kann doch nicht an jeder Stelle im Programm ständig diese Variable abfragen!? Ganz wichtig ist das er nach der Interrupt-Funktion auf keinen Fall an der Stelle weitermachen darf an der er unterbrochen wurde! Wie soll ich schaffen das immer nach dem Interrupt direkt die Variablen-Abfrage kommt? ??? Gruß Ralf
Erklär doch mal, warum "auf keinen Fall an der Stelle weitermachen darf an der er unterbrochen wurde", welche Aufgabe hinter dieser seltsamen Anforderung steht.
Keine Ahnung ob das bei einem AVR geht. Aber diese Situation löst man in C sonst mit setjmp und longjmp. Also irgendwo im Hauptprogramm das setjmp und in der Interruptroutine das longjmp. longjmp bewirkt daß das Programm an der Stelle des setjump weiterläuft als wenn nichts gewesen wäre. Am Rückgabewert des setjmp erkennt man ob es normal aufgerufen wurde oder per longjmp 'angesprungen'.
Das ganze ist eine Steuerung für einen Automaten. Im Automaten sind 3 Pneumatik-Zylinder drin. Um ein Fertigteil im Automat herzustellen muß ein bestimmter Ablauf (Zyl. 1,2,3 nacheinander) 4x durchlaufen werden. Ein einzelner korrekter Ablauf dauert etwa 1 sek. Ich überprüfe mit meinem Timer im Programm ob der Ablauf innerhalb dieser Sekunde erledigt wurde. Bleibt z.B. ein Zylinder hängen weil sich ein Teil verkantet hat, so wird die Zeit überschritten und ein Interrupt wird ausgelöst! Im Interrupt wird dann eine Fehlermeldung im Display angezeigt und alle Zylinder werden abgeschaltet. Der Bediener des Automaten entfernt das verklemmte Teil und bestätigt mit einer Taste. *** jetzt steht das Programm irgendwo innerhalb dieser 4-fach-Schleife --> wichtig ist jetzt das ich das ganze von vorne beginnen kann (Grundstellung) --> also muß ich aus der Schleife sofort nach dem Interrupt raus!!! ???
Warte in der Interrupt-Routine, bis der Taster gedrückt wurde und lass danach der Watchdog überlaufen. So setzt dein Programm ganz neu auf. Oder, wie oben schon erwähnt, setz ein Flag Fehler, der in jedem Arbeitszyklus abgefragt wird. MW
würde ich in dem Fall auch so ähnlich machen. In den watchdog laufen lassen, dann startet das Programm neu, darin erstmal alle Aktoren in einen sicheren Zustand steuern. Dann abfragen, ob es ein power-on oder ein watchdog-reset war, dementsprechend dann den Bestätigungstaster abfragen (oder bei power-on-reset eben nicht). Falls der watchdog sonst im Programm genutzt wird und die Auslösezeit evtl. zu lang sein sollte, kannst du auch einen Portpin mit dem Reset-Eingang verbinden. Und da gibts gleich die schöne Möglichkeit clear OCx on compare, du musst regelmässig den Timer zurücksetzen, dass der compare-Wert nicht erreicht wird, wenn doch, gibts einen auf die Mütze.
Du solltest den Automaten als state maschine programmieren. Dort kannst du in dem jeweiligen Zustand Status Flags abfragen. Hat auch den ganz ganz großen Vorteil, daß du jederzeit ganz genau weißt, an welcher Stelle dein Programm sich befindet. So vermeidet man enorm viele Probleme. Nachteil : relativ viel code.
Hm.. Dasselbe Thema hatten wir schon ein paar Zeilen tiefer unter "Interrupt + Sprungadresse" .. Lässt sich dein "Problem" anders lösen? Tim O.
"Du solltest den Automaten als state maschine programmieren." Ganz genau ! Eine Statemaschine ist in diesem Fall die sauberste Lösung. Bei einer Statemaschine wird der augenblickliche Programmzustand durch eine Variable gekennzeichnet und deren Wert entscheidet, welche Aktion als nächstes auszuführen ist und welcher Zustand danach einzunehmen ist. Die einzelnen Zustände definiert man zweckmäßiger Weise mit Namen für die einzelnen Werte. Also z.B.: #define START 0 #define AKTION_X 1 ... main() { char zustand = START; for(;;){ switch( zustand ){ case AKTION_X: // mache irgendwas zustand = AKTION_Y; // nächster Zustand break; case ... ... } } } Sieht im ersten Augenblick komplizierter aus als alles hintereinander zu schreiben. Aber die großen Vorteile erschließen sich schnell: Es sind beliebige Zustandswechsel möglich, z.B. ist es kein Problem, bei einem Timeroverflow wieder in den Startzustand zu wechseln: if( TIFR & 1<<TOV0 ){ TIFR = 1<<TOV0; // rücksetzen zustand = START; } Und man braucht nicht mal mehr einen Interrupthandler. Um Wartezeiten in so einer Statemaschine zu erzeugen, kann man z.B. einen Timer auf die Wartezeit setzen und wechselt dann erst in den nächsten Zustand, wenn das Overflow-Bit gesetzt wurde: ... case AKTION_X: if( TIFR & 1<<TOV1 ){ TIFR = 1<<TOV1; // rücksetzen zustand = AKTION_Y; } break; ... Der 2. große Vorteil ist, das nirgends Zeit verwartet wird, d.h. man kann mehrere dieser Statemaschinen hintereinander schreiben. Die CPU kann also 2 oder mehr Automaten gleichzeitig steuern, quasi Multitasking. Bei der Watchdogmethode kann nichts anderes gleichzeitig gemacht werden, da ja die CPU komplett von vorn beginnt. Auch ist zu beachten, daß dabei alle Ausgänge hochohmig werden, dadurch können Störimpulse entstehen. Peter
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.