Hallo Forumgemeinde, So, erst mal die Infos ;) ATmega 16 CodeVision Jetzt zu meinem Problem. Ich möchte in einem Programm dem den Int0 ein bzw auch ausschalten. Ich weiß jetzt nicht was ich falsch mache. Ganz am Anfang (vor der main) schalte ich den Int0 mit „GICR|=0x40;“ ein. Dann läuft auch alles ganz normal. Dann schalte ich den Int0 mit dem Befehl „GICR &=(!(0x40));“ wieder aus. Das klappt dann auch noch. Wenn ich dann aber wieder den Int0 mit „GICR|=0x40;“ einschalten will, geht das nicht mehr :o( Habe ich etwas falsch gemacht? Muss man beim einschalten etwas Bestimmtes beachten?? Ich wäre über eine Hilfe von euch wirklich sehr dankbar!!! Schönes Wochenende und Grüße, Marcel
Hallo Werner, danke für deinen Hinweis. Ich habe es gleich mal ausprobiert allerdings funktioniert es so auch nicht. Das Problem liegt ja auch nicht beim ausschalten, sondern beim einschalten. Ich habe das Gefühl das der Interrupt nur ein mal kommt und dann nicht mehr. Werd mal drüber schlafen.... Trotzdem danke für die schnelle Hilfe, Gruß Marcel
Wenn man ein LOGISCHES NICHT statt eines BITWEISEN NICHT verwendet ist das sicher ein Problem. Tanke mal Diesel statt Benzin. Du kommst zwar ein paar Meter weit ... bis die Bezinleitung voll Diesel ist ;-) Evtl. noch vor dem erneuten Freigeben das INT0 - Flag im Interrupt Flag Register löschen (GIFR |= 0x40)? (P.S. Ob das Flag Register den Namen GIFR hat weiss ich nicht genau. Manual nachsehen).
Hast du sichergestellt das beim erneuten Einschalten nicht noch irgendein anderer Interrupt aktiv ist und auch das globale Interrupt Flag gesetzt ist?
Hallo Werner und Pöhli, also ich habe mir das noch mal mit dem logisch und bitweise angeschaut. Logisch heißt einfach nur vergleich auf „true“ oder „false“. Bei bitweise werden die einzelnen Bit verglichen. Ich muss also das bitweise Verfahren anwenden. OK, das habe ich jetzt verstanden!!! Vielen Dank noch mal. @ Werner, du hast geschrieben dass ich eventuell vor dem einschalten des Int0, das Flag im GIFR löschen soll. Im Manuel steht das man das Bit allerdings setzen soll wenn der Int0 aktiv werden soll. Wie war das den von dir gemeint?? GIFR ist übrigens vollkommen richtig :o) @Pöhli, also deine Frage verunsichert mich etwas. Ich habe das Gefühl das ich da noch etwas noch nicht verstanden habe und noch nicht weiß. Dürfen keine zwei Interuppts aktiv sein? Es läuft noch ein Timer mit dem Overflow Interrupt. (8 Bit bei 15625Hz also alle 61ms) Mach das den etwas aus?? Ich gehe davon aus wenn der Timer läuft, dann ist auch das globale Interrupt Flag gesetzt. Danke für eure Mühe… Grüße Marcel
> Ganz am Anfang (vor der main) schalte ich...
VOR der main() kann man gar nichts schalten. In C müssen Anweisungen
grundsätzlich INNERHALB von Funktionen stehen...
Wenn Du vielleicht mal Deinen Code posten könntest, dann sieht man
vielleicht auch, was da verkehrt ist. Eine Zeile sagt überhaupt nichts
aus.
Hallo zusammen, johnny.m, du hast natürlich Recht. Ich habe da Müll geschrieben. Natürlich steht es unter der main, allerdings vor der while!!! Also das ganze Programm zu posten ist bestimmt zu unübersichtlich. Aber ich werde versuchen es zu erklären. Generell handelt es sich um die Auswertung vom DCF-Signal. Das Antennensignal ist am Int0 angeschlossen. Nachdem sich die Uhr synchronisiert hat, will ich den Interrupt abschalten. Wenn dann 56 Minuten vorbei sind, will ich den Int0 wieder einschalten. Vor der while-Schleife steht: [nach der main ;o)] GICR|=0x40; // INT0 eingeschaltet MCUCR=0x03; // steigende Flanke MCUCSR=0x00; GIFR=0x40; In der while-Schleife steht dann nichts mehr, es wird alles über Interrupt und Unterprogramm realisiert. Wenn das Signal erkannt wurde und auch die interne Uhr abgeglichen ist, schalte ich den Interrupt mit: GICR &= ~0x40; // INT0 ausschalten wieder aus. Soll dann wieder ein Abgleich stattfinden, dann schalte ich den Int0 mit: GIFR |= 0x40; GICR|=0x40; // INT0 eingeschaltet wieder ein. Also das ausschalten klappt ja ganz gut. Der Empfang der Antenne ist ausgeschaltet. Aber das wiedereinschalten klappt wie gesagt nicht!!! In der ganzen Zeit läuft aber nebenher noch der Timer0 für das interne Uhrwerk! Ich hoffe das es so etwas verständlicher ist :o( Danke für eure Hilfe… Viele Grüße, Marcel
> Also das ganze Programm zu posten ist bestimmt zu unübersichtlich.
Wenn Du meinst... Aber mit dem bisschen Code, das Du oben gepostet hast,
kann ich Dir leider überhaupt nicht weiterhelfen. Ohne den
programmtechnischen Zusammenhang kann man da alles Mögliche vermuten.
Eine unschöne Kleinigkeit ist allerdings Dein
1 | GIFR |= 0x40; |
In Deinem Programm ist das möglicherweise egal (zumindest dann, wenn Du außer diesem einen keine anderen externen Interrupts verwendest), aber Du musst wissen, dass diese Anweisung alle Flags in GIFR löscht, und nicht nur das, welches gelöscht werden soll. Soll nur ein Flag gelöscht werden, dann muss es heißen:
1 | GIFR = 0x40; |
Das aber nur am Rande.
Hallo johnny.m, Danke für deine Antwort. Also das was du mal so am Rande erwähnt hast war, so wie’s aussieht, die Lösung!!! Ich kann es nur nicht ganz verstehen. Wenn GIFR zum Beispiel so aussehen würde: 00000011 und ich schreibe dann GIFR=0x40 dann ändert sich doch GIFR auf 01000000. Das heißt das alles, außer das 6. Bit wird 1. Bei GIFR |= 0x40 würde doch dann 01100011 stehen, oder?? Auf jeden Fall mal Danke für deinen hilfreichen Tipp!!!! Mit bestem Gruß, Marcel
Das hängt damit zusammen, dass du einen Interrupt löscht indem du eine 1 nach GIFR schreibst. Schreibst du also 0x40, also 0100000, nach GIFR, dann wird bedingt durch das eine gesetzte Bit auch nur dieser eine Interrupt gelöscht. Alle anderen bleiben unangetastet. Der springende Punkt ist: Du schreibst nicht in GIFR welche Bits übrig bleiben sollen. Du schreibst explizit rein, welche Bits zu löschen sind. Machst du daher GIFR |= 0x40; Dann sind natürlich auch andere Bits gesetzt. Um bei deinem Beispiel zu bleiben: Wenn GIFR den Wert 00000011 hätte, dann kommt nach der Oder Verknüpfung 01000011 raus. Beim Zurückschreiben nach GIFR heist das aber: Lösche Bit 6, Bit 1 und Bit 0. Und das ist ja nicht das was du willst.
Das eigentliche Problem ist eben das "|". In C sieht es so aus, als wäre
1 | GIFR |= 0x40; |
eine einzige Anweisung und man denkt als C-Programmierer nicht weiter drüber nach, was da eigentlich passiert. Allerdings macht der Compiler da ganze drei Assembler-Befehle draus (Bsp.):
1 | in r16, GIFR |
2 | ori r16, 0x40 |
3 | out GIFR, r16 |
von denen der erste (in r16, GIFR) den aktuellen Inhalt von GIFR in ein Rechenregister lädt, der zweite die ODER-Verknüpfung mit der (konstanten) Bitmaske durchführt und der dritte den ganzen Murks wieder in GIFR schreibt. Da beim ersten Befehl alle zum Zeitpunkt der Ausführung gesetzten Bits als "1" gelesen werden und diese durch das "|" nicht angetastet werden, werden sie beim dritten Befehl auch als "1" wieder zurückgeschrieben, was im Falle von Interrupt-Flags dazu führt, dass alle, die beim Einlesen gesetzt waren, gelöscht werden. Bei
1 | GIFR = 0x40; |
wird nichts eingelesen, sondern einfach die konstante Bitmaskeins GIFR geschrieben. Dadurch werden alle Bits, die in der Maske nicht gesetzt sind, mit "0" beschrieben. Da das Schreiben einer "0" allerdings keinen Effekt auf das Interrupt-Flag hat, werden wirklich nur die Flags verändert, die man auch verändern will.
Hallo Karl heinz Buchegger und johnny.m!! Nochmal danke für eure Hilfe. Die letzten beiden Antworten von euch haben mir echt geholfen. Damit konnte ich echt etwas anfangen!! Das wurde von euch gut erklärt. Ich habe da einen klaren Denkfehler im Umgang mit Interrupts. Jetzt ist es mir klarer geworden. Danke und Grüße aus der nähe Heidelberg..... Marcel
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.