Forum: Mikrocontroller und Digitale Elektronik asm interrupt für Programmverzweigung


von Bruno M. (brumay)


Lesenswert?

Hallo,

nach längerer Pause versuche ich mich mal wieder in der 
Atmel-Programmierung und stoße prompt auf eine Frage, die mir bislang 
noch nicht untergekommen ist.

Was muß ich tun, um mit einem externen Interrupt in eine 
Programmverzweigung zu springen. D.h. ich habe keinen Rücksprung (reti), 
sondern ich möchte dann in dem angesprungenen Zweig bleiben, bis zum 
nächsten Interrupt.

von Bruno M. (brumay)


Lesenswert?

Ich meine, ich kann mir die Antwort schon selbst geben!

Wenn ich in der Interruptroutine nur eine Flag umstelle, die dann im 
eigentlichen Programm zum Umspringen führt, dann müßte es doch 
eigentlich gehen?

von Einer K. (Gast)


Lesenswert?

Das kannst du natürlich tun!
Musst nur den Stack bereinigen und die Interrupts wieder aktivieren.
Zeugt aber schon von einer gewissen Härte.

Bruno M. schrieb:
> Wenn ich in der Interruptroutine nur eine Flag umstelle, die dann im
> eigentlichen Programm zum Umspringen führt, dann müßte es doch
> eigentlich gehen?
Wohl meist die besser Wahl.

von S. Landolt (Gast)


Lesenswert?

Zwei der drei Teile des reti selbst ausführen: den Stackpointer SP um 
2 erhöhen und den globalen Interrupt wieder freigeben.


(Eine Sinnfrage wurde nicht gestellt und auch nicht beantwortet)

von leo (Gast)


Lesenswert?

Bruno M. schrieb:
> Wenn ich in der Interruptroutine nur eine Flag umstelle,

... und du das Flag mit volatile deklariert hast ...

leo

von S. Landolt (Gast)


Lesenswert?

> volatile

In Assembler?

von leo (Gast)


Lesenswert?

S. Landolt schrieb:
>> volatile
>
> In Assembler?

Oops, das habe ich wohl uebersehen.

leo

von Bruno M. (brumay)


Lesenswert?

Danke für die Antworten! Das hilft auf alle Fälle weiter.

von foobar (Gast)


Lesenswert?

> Was muß ich tun, um mit einem externen Interrupt in eine
> Programmverzweigung zu springen. D.h. ich habe keinen Rücksprung
> (reti), sondern ich möchte dann in dem angesprungenen Zweig bleiben,
> bis zum nächsten Interrupt.

Das kann man mit setjmp/longjmp machen.  Da hängen aber so viele 
Fallstricke dran, dass ein erfahrener Programmierer da einen rieeesen 
Bogen drum macht.

> Wenn ich in der Interruptroutine nur eine Flag umstelle, die dann im
> eigentlichen Programm zum Umspringen führt, dann müßte es doch
> eigentlich gehen?

Das ist die übliche Methode.

von Sebastian S. (amateur)


Lesenswert?

Bedenke bitte, dass ein Interrupt eine sehr brutale Angelegenheit ist!
Egal, was der Prozessor gerade mach, es wird unterbrochen!
Joggt der Kerl die ganze Zeit in einer Tu-Nix-Schleife rum (vorzugsweise 
NOP) so sollte nichts passieren. In allen anderen Fällen könne es 
problematisch werden.
Immer, natürlich den Stack im Auge behalten und ordentlich putzen.

Übrigens: Nach Murphy kommt eine Unterbrechung immer dann, wenn sie 
nicht kommen kann/soll und somit alles mögliche durcheinander bringt.

Ich würde in der Hauptschleife den Pin abfragen. Dann weist Du genau, 
was alle Beteiligten machen und kannst entsprechend agieren.

von Einer K. (Gast)


Lesenswert?

foobar schrieb:
> Das kann man mit setjmp/longjmp machen.

asm, nicht c

von Bruno M. (brumay)


Lesenswert?

Sebastian S. schrieb:
>
> Übrigens: Nach Murphy kommt eine Unterbrechung immer dann, wenn sie
> nicht kommen kann/soll und somit alles mögliche durcheinander bringt.
>
Ich muß mich doch noch mal melden. Murphy hat natürlich immer recht. Ich 
habe es nun mit der Flag versucht wie oben beschrieben. Ergebnis: Mal 
funktionierts, mal nicht.

> Immer, natürlich den Stack im Auge behalten und ordentlich putzen.

Wie stellt man das am besten an?

von Rainer V. (a_zip)


Lesenswert?

Bruno M. schrieb:
> Wie stellt man das am besten an?

Das hängt natürlich von deinem Hauptprogramm ab und davon, was der 
Interrupt bewirken soll. Wenn du in der I-Routine jetzt nur ein Flag 
setzt, mußt du dafür sorgen, dass das Hauptprogramm das regelmäßig und 
oft (genug) prüft. Eventuell kannst du aus der I-Routine in ein 
Unterprogramm springen, dass das ganze Programm verwaltet. Auf RETI 
würde ich nicht verzichten...das macht alles nur unübersichtlich und 
feheranfällig.
Gruß Rainer

von Carl D. (jcw2)


Lesenswert?

Bruno M. schrieb:
> Ich meine, ich kann mir die Antwort schon selbst geben!
>
> Wenn ich in der Interruptroutine nur eine Flag umstelle, die dann im
> eigentlichen Programm zum Umspringen führt, dann müßte es doch
> eigentlich gehen?

Wenn du im Interrupt nur ein Flag setzen willst, das das Hauptprogramm 
dann auswertet, dann kannst du das gleich der HW überlassen, denn 
praktisch immer gibt es dieses Flag schon in der HW. Und ein weiteres 
Flag, das gesetzt werden kann, um auch wirklich einen Interrupt 
auszulösen. Keine ISR -> kein Synchronisierung notwendig, keine Frage 
"jetzt RET oder doch RETI", ...

von Bruno M. (brumay)


Lesenswert?

Was verstehst du unter HW?

von Oliver S. (oliverso)


Lesenswert?

Sebastian S. schrieb:
> Bedenke bitte, dass ein Interrupt eine sehr brutale Angelegenheit ist!
> Egal, was der Prozessor gerade mach, es wird unterbrochen!
> Joggt der Kerl die ganze Zeit in einer Tu-Nix-Schleife rum (vorzugsweise
> NOP) so sollte nichts passieren. In allen anderen Fällen könne es
> problematisch werden.

Wenn der Atmel des TO ein AVR ist, dann passiert da gar nix 
problematisches. Der Prozessor wird eben nicht brutal bei irgendetwas 
unterbrochen, sondern der beendet den aktuellen Befehl, pusht den PC auf 
den Stack, und setzt den PC dann auf den Interrupt-Vektor. Das ist 
alles. Da passiert genau das gleiche, wie bei einem RCALL-Sprung in ein 
Unterprogramm, nur daß dabei noch das I-Flag gesetzt wird.

Oliver

von Michael U. (amiga)


Lesenswert?

Hallo,

wenn es Dinge im Ablauf gibt, die nicht gestört werden dürfen, gibt es 
CLI und SEI. Das daß ganze Programmkonzept passen muß, steht außer 
Frage, also ist doch nur wichtig, daß Laufzeiten der Teile passen. 
Wieviele IRQs kommen in welchen minimalen Zeitabständen, welche 
Reaktionszeit muß unbedingt eingehalten werden usw.
Ich habe gern in ASM programmiert, Z80, 6502, div. AVR. Es gab auch 
kleine Projekte, wo alles nur auf ext. Interrupt innerhalb der ISR 
ausgeführt wurde. Das Hauptprogramm bestand dann eben nur aus der 
Initialisierung, Interruptfreigabe und einer Endlosschleife. Geht alles.

Gruß aus Berlin
Michael

von Teo D. (teoderix)


Lesenswert?

Carl D. schrieb:
> Wenn du im Interrupt nur ein Flag setzen willst, das das Hauptprogramm
> dann auswertet, dann kannst du das gleich der HW überlassen, denn
> praktisch immer gibt es dieses Flag schon in der HW.

Bruno M. schrieb:
> Was verstehst du unter HW?

Auch wenn der Int gesperrt ist, wird das entsprechende Flag von der HW 
gesetzt. Dieses könntest du nun in deinem Programm /an geeigneter 
Stelle/ abfragen, löschen und in dem Zweig der vorgesehen ist weiter 
machen.

von Bruno M. (brumay)


Lesenswert?

Hinweis: Es handelt sich um einen Atmega128

Ich habe jetzt zwei Versionen versucht:

Aus der Interruptroutine springe ich zurück in das Hauptprogramm und 
frage dort die Flag ab.

In einem Programmzweig geht das gut, da ich dort eine tu nix Schleife 
habe.

Beim zweiten Zweig ist es schwieriger, da ich dort zwanzig 
Einzelaufgaben abarbeite und danach wieder von vorne anfange.

Setze ich die Flagabfrage ganz an das Ende (vor dem Rücksprung zum 
Anfang), dann funktioniert es. Allerdings verstreicht dann viel Zeit 
zwischen Interrupt und Ausführung. Setze ich die Flagabfrage aber in ein 
rcall Unterprogramm das ich mit jeder Einzelaufgabe anspringe, dann 
spielt er verrückt.

von S. Landolt (Gast)


Lesenswert?

> Es handelt sich um einen Atmega128

Dessen Eigenart mit dem 'ATmega103 compatibility mode' wurde beachtet?

von Einer K. (Gast)


Lesenswert?

Bruno M. schrieb:
> dann spielt er verrückt.
Du hast mein volles Mitgefühl.

Tipp:
Nur für den Fall, dass du mal mit jammern fertig wirst, könntest du den 
Problem Code mal minimieren und hier zeigen. Mit viel Glück findet sich 
dann jemand, der mit dem Finger auf die böse Stelle zeigt. Mit deiner 
Prosa kann keiner (zumindest ich nicht) was anfangen, außer es als 
Grund, zum Kopf schütteln, zu nehmen.

von Eberhard H. (sepic) Benutzerseite


Lesenswert?

Wenn du wissen willst, wo dein AVR-Programm vor dem Interrupt-Aufruf 
gerade gelaufen ist, kannst du das zunächst z. B. per:

POP ZH
POP ZL

im Register ZH:ZL feststellen und den jetzt um zwei Adressen geänderten 
Stackpointer entweder belassen (falls in dem Moment keine Unterprogramme 
aktiv oder Daten per PUSH gespeichert waren), sonst den SP entsprechend 
korrigieren oder neu setzen.

Falls das völlig egal ist, den SP neu auf den Anfangswert setzen (dann 
sind alle per PUSH gespeicherten Daten weg) und ggf. auch das 
Statusregister aktualisieren.

Ohne RET/RETI bzw. ohne SP-Korrektur gerät auf jeden Fall  der Stack 
durcheinander.

Vielleicht sollest du deine Programmstruktur nochmals überdenken, damit 
du ohne solche Maßnahmen auskommst.

von c-hater (Gast)


Lesenswert?

Bruno M. schrieb:

> Ich habe jetzt zwei Versionen versucht:
>
> Aus der Interruptroutine springe ich zurück in das Hauptprogramm und
> frage dort die Flag ab.

Du springst hoffentlich nicht wirklich, sondern machst einfach nur brav 
ein reti in der ISR?

> Beim zweiten Zweig ist es schwieriger, da ich dort zwanzig
> Einzelaufgaben abarbeite und danach wieder von vorne anfange.

So what? Wo auch immer der Scheiß durch die ISR unterbrochen wird, er 
wird ordentlich genau nach der Stelle weiterwerkeln, sobald das reti in 
der ISR ausgeführt ist. Naja, jedenfalls gilt das solange die ISR nix 
kaputt macht.  Es ist dein Job, sie so zu schreiben, dass sie das nicht 
tut.

> Setze ich die Flagabfrage ganz an das Ende (vor dem Rücksprung zum
> Anfang), dann funktioniert es. Allerdings verstreicht dann viel Zeit
> zwischen Interrupt und Ausführung. Setze ich die Flagabfrage aber in ein
> rcall Unterprogramm das ich mit jeder Einzelaufgabe anspringe, dann
> spielt er verrückt.

Sehr wahrscheinlich: Irgendwas kaputt gemacht. Und zwar nicht in der 
ISR, sondern in dem mit rcall angesprungenen Unterprogramm. 
Wahrscheinlich benutzt es in der Hauptschleife zur Übergabe zwischen den 
Teilaufgaben verwendete Register, ohne sie zu retten und 
wiederherzustellen.

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> Du springst hoffentlich nicht wirklich, sondern machst einfach nur brav
> ein reti in der ISR?

Du irrst.
Denn genau das ist sein Plan.

Siehe:
Bruno M. schrieb:
> Was muß ich tun, um mit einem externen Interrupt in eine
> Programmverzweigung zu springen. D.h. ich habe keinen Rücksprung (reti),
> sondern ich möchte dann in dem angesprungenen Zweig bleiben, bis zum
> nächsten Interrupt.
Und damit läuft ihm sein Stack voll, und was da sonst noch zerbrechen 
kann.

Wenn das ganze Programm auf ein A4 Blatt passt, (und man etwas aufpasst) 
kann man das so tun, von mir aus.
Aber der blendende Geniestreich ist das sicherlich nicht

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.