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.
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?
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.
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)
Bruno M. schrieb: > Wenn ich in der Interruptroutine nur eine Flag umstelle, ... und du das Flag mit volatile deklariert hast ... leo
> 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.
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.
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?
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
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", ...
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
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
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.
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.
> Es handelt sich um einen Atmega128
Dessen Eigenart mit dem 'ATmega103 compatibility mode' wurde beachtet?
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.