Hallo bei meinem Programm wird die Subroutine SET_dac8532() immer mit ausgeführt, wenn der Interrupt ausgelöst wird. Kann mir das jemand erklären ? Vielen Dank fürs lesen S. Streibl
Mal die generierten Asm-Sources angeschaut, ob dort die Interrupt-routine auch richtig mit einem return abgeschlossen wird? /Ernst
Den Grund dafür an sich sehe ich jetzt auf Anhieb nicht, aber Du führst in der ISR eine elend lange Funktion mit Wartezeiten aus. Das allein kann schon zu undefinierbaren Fehlern führen. Wenn der Tip von Ernst nicht helfen sollte, stell mal die ISR vor alle anderen Funktionen. Das globale Interrupt disable bei Einsprung in die ISR passiert übrigens automatisch und das Sichern des SREG macht der Compiler. Das brauchst Du nicht extra zu programmieren. Gruß Johnny
Hallo Ernst, so wie es aussieht wird die Interruptroutine mit RJUMP abgeschlossen. OUT 0x0D,R1 SEI Global Interrupt Enable RJMP PC-0x0000 Relative jump Ist RJMP mit RCALL identisch ? Sollte jedenfalls funktionieren, so wie es AVRStudio anzeigt @ Johnny : heisst das, ich kann in der ISR cli() weglassen? Aber doch nicht sei() ? Die ISR kann ich nicht umstellen, da das alles sehr verschachtelt ist. Vielleicht sollte ich die gesamte Struktur ändern und die ISR so kurz wie nur möglich halten. Gruß Basti
Nachtrag : in der Simulation siehts dann so aus als wär die RJMP Zeile die while(1)-Schleife von main(). Das würde bedeuten, dass die ISR nicht mit RET oder RCALL beendet wird. Wie kann ich das im C-Code beheben ? Grüße Basti
und noch ein Nachtrag : in der Simulation wird das Unterprogramm nicht ausgeführt. Das ist mal wieder sehr praktisch ... Falls ihr noch Tipps habt, raus damit. Grüße Basti
Hallo Basti Ich weiß nicht, wie es bei Dir mit Assembler-Kenntnissen aussieht (nach dem was oben steht, nicht besonders:-), deshalb versuche ich mal, es ohne zuviel davon zu beschreiben. Hilfreich zum Verständnis ist, sich mal nach dem Compilieren die List-Datei anzusehen. Da kann man sehr schön sehen, was der Compiler aus dem C-Code gemacht hat. Wenn ein Interrupt auftritt und der Controller über die Interrupt-Vektortabelle in die ISR springt, wird hardwaremäßig automatisch das I-Bit (globales Interrupt-Enable) im Register SREG gelöscht. Ist die ISR beendet (in Assembler mit dem Befehl reti [return from interrupt]) wird dieses Bit ebenfalls automatisch durch die µC-Hardware wieder gesetzt. Möchte man, dass eine ISR durch einen anderen Interrupt unterbrochen werden kann, dann kann man durch manuelles Setzen des I-Bits in der ISR dafür sorgen, was aber meist mit größter Vorsicht zu genießen ist! Wenn man sich den Assembler-Code der ISR anschaut, sieht man am Anfang jede Menge push-Befehle. Diese 'retten' alle wichtigen Register auf den Stack. Irgendwo steht da dann auch push 0x3F, das ist das SREG. Am Ende der ISR (vor dem reti) werden die ganzen Daten mit pop-Befehlen wieder vom Stack geholt. Diesen Code erzeugt der Compiler selbst. Da brauchst Du Dich als C-Programmierer nicht drum zu kümmern! Generell sollte man den Inhalt einer ISR wirklich auf das allernötigste beschränken. Da Du in Deiner Hauptprogramm-Endlos-while-Schleife sowieso nix machst außer warten, solltest Du in der ISR lediglich ein Flag setzen (Das kann ein beliebiges Bit in irgendeiner globalen Variablen sein oder auch eine komplette Variable) und dieses Flag im Hauptprogramm abfragen. Man sollte in einer ISR auch nach möglichkeit keine Funktionsaufrufe unterbringen. Das kann zu Ärger führen. Auch die Erzeugung von Wartezeiten mit Zählschleifen ist sehr fragwürdig. Warum benutzt Du keine Bibliotheksfunktionen (delay)? Ich weiß natürlich nicht, ob Du das Programm noch erweitern möchtest, aber wenn Du es tun solltest, dann solltest Du es auf jeden Fall ein wenig 'umbauen'. Gruß Johnny
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.