Forum: Mikrocontroller und Digitale Elektronik Interrupt ein/aus schalten


von Marcel K. (viewer)


Lesenswert?

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

von Werner B. (Gast)


Lesenswert?

GICR &= ~0x40;

von Werner B. (Gast)


Lesenswert?

... statt "GICR &=(!(0x40));"

von Marcel K. (viewer)


Lesenswert?

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

von Werner B. (Gast)


Lesenswert?

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

von Pöhli (Gast)


Lesenswert?

Hast du sichergestellt das beim erneuten Einschalten nicht noch 
irgendein anderer Interrupt aktiv ist und auch das globale Interrupt 
Flag gesetzt ist?

von Marcel K. (viewer)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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

von Marcel K. (viewer)


Lesenswert?

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

von johnny.m (Gast)


Lesenswert?

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

von Marcel K. (viewer)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von johnny.m (Gast)


Lesenswert?

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.

von Marcel K. (viewer)


Lesenswert?

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