Forum: Mikrocontroller und Digitale Elektronik Sprung nach Interrupt


von Ralf (Gast)


Lesenswert?

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

von crazy horse (Gast)


Lesenswert?

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.

von crazy horse (Gast)


Lesenswert?

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.

von Ralf (Gast)


Lesenswert?

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

von crazy horse (Gast)


Lesenswert?

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.

von Ingo Eichenseher (Gast)


Lesenswert?

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'.

von Ralf (Gast)


Lesenswert?

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!!!

???

von Michael Wilhelm (Gast)


Lesenswert?

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

von crazy horse (Gast)


Lesenswert?

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.

von chrissy (Gast)


Lesenswert?

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.

von Tim O. (Gast)


Lesenswert?

Hm..

Dasselbe Thema hatten wir schon ein paar Zeilen tiefer
unter "Interrupt + Sprungadresse" ..
Lässt sich dein "Problem" anders lösen?

Tim O.

von Ralf (Gast)


Lesenswert?

Perfekt, hab es mit Hilfe des Watchdog gelöst bekommen.

Danke!

von Peter D. (peda)


Lesenswert?

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