Hallo, verwende den Atmega 649A und will auf 2 Pins den PinChange Interrupt aktivieren. Das Datenblatt dazu: http://www.atmel.com/Images/doc8284.pdf Ich will den PCINT12 und PCINT14 (Pins 14 und 16) aktivieren, alle anderen sollen nicht aktiv sein. Zuerst setze ich das PCINT1 Bit im EIMSK Register, damit die Interrupts PCINT8-PCINT15 aktiviert sind. Den globalen Interrupt enable führe ich mit sei() aus. Seite 64: Register EIFR, Bit 5: Wenn nun auf einen dieser Pins (PCINT8-15) eine Flanke auftritt, wird dieses Bit gesetzt (1) und die ISR ausgeführt, richtig? Wenn die ISR ausgeführt ist, wird dieses Bit automatisch wieder gelöscht?! Warum steht dann da im letzten Satz, dass man dieses Flag auch löschen kann, wenn man eine 1 reinschreibt, es also setzt?!! Verstehe ich da was falsch oder ist das ein Fehler im Text? Vielen Dank für die Hilfe!!
Manuel schrieb: > steht dann da im letzten Satz, dass man dieses Flag auch löschen kann, > wenn man eine 1 reinschreibt, es also setzt?!! Verstehe ich da was > falsch oder ist das ein Fehler im Text? Weil die ISR auch angesprungen werden muss, damit das BIt gelöscht wird. Manchmal ist man aber gar nicht daran interessiert, dass es eine ISR gibt. Alles was man will ist, dass die Hardware das betreffende Bit setzt. Und dann muss es eine Möglichkeit geben, es auch wieder zu löschen. Und ja. Das ist schon richtig. Diese Bits werden durch einschreiben einer 1 gelöscht.
Folgenden Code verwende ich:
1 | EIMSK |= (1<<PCIE1); // Pin Change Interrupt Enable1 (PCINT15 - PCINT8) |
2 | EIMSK &= ~(1 << PCIE0); // disable PCINT7 - PCINT0 |
3 | |
4 | |
5 | PCMSK1 |= (1<<PCINT12); //Pin Change 12 interrupt enable |
6 | PCMSK1 |= (1<<PCINT14); //Pin Change 14 interrupt enable |
7 | PCMSK1 &= ~((1 << PCINT8) |(1 << PCINT9) | (1 << PCINT10) | (1 << PCINT11) | (1 << PCINT13)| (1 << PCINT15)); // disable the other Interrupts of this group |
8 | |
9 | sei(); // Enable Interrupt |
Ist das so korrekt, wenn ich will, dass NUR PCINT12 und PCINT14 aktiv sind, das heißt, alle anderen können keine Interrupts auslösen? Ich frage nach, weil diese Gruppe (PCINT8-PCINT15) eine GEMEINSAME ISR haben. Wird eigentlich ein Interrupt Flag auch gesetzt, wenn ein Interrupt disabled ist? Wenn cih z.B. irgendwo später iom Programm den PCINT12 so disable:
1 | PCMSK1 &= ~(1<<PCINT12); |
wird dann trotzdem ein Flag gesetz, die ISR aber nicht ausgeführt? Oder wird dann auch das Flag nicht gesetzt? Wenn es troptzdem gesetzt wird, kann es dann passieren, dass wenn ich den Interrupt wieder enable:
1 | PCMSK1 |= (1<<PCINT14); |
dass dann sofort ein Interrupt ausgelöst wird, auch wenn gerade kein Pin Change stattgefunden hat? Vielen Dank!!!
Manuel schrieb: > Wird eigentlich ein Interrupt Flag auch gesetzt, wenn ein Interrupt > disabled ist? Ja. Diese Flags registrieren das Auftreten des Ereignisses. Unabhängig davon, ob die Interrupts dafür auch aktiviert sind. > dass dann sofort ein Interrupt ausgelöst wird, auch wenn gerade kein Pin > Change stattgefunden hat? Ganz genau. Jetzt hast du einen 2.ten Grund gefunden, warum man diese Bits händisch löschen können muss.
OK vielen Dank :) Trotzdem sind jetz noch ein paar Unklarheiten offen: 1.) Ich habe deinen ersten Beitrag nicht ganz verstanden: wenn ich das Flag löschen will, schreib ich eine 1 rein, damit die ISR ausgeführt wird und dadurch das Flag gelöscht wird? Was ist aber wenn ich nicht will dass die ISR ausgeführt wird? Warum kann ich nicht einfach eine 0 rein schreiben, ohne dass die ISR ausgeführt wird? 2.) Meiner Meinung nach müsste nun nach deinen Erklärungen mit folgender Zeile ein Interrupt ausgelöst und die ISR ausgeführt werden (zusätzlich zu vorigem Code):
1 | EIFR |= (1<<PCIF1); |
Funktioniert aber nicht, warum? 3.) Ich hatte das Problem, dass die ISR ungewollt aufgerufen wurde. Erst danach ist mir eingefallen, dass es einer der anderen Pins sein könnte, da ja alle eine gemeinsame ISR haben. Erst danach habe ich folgende Zeile im obigen Code hinzugefügt:
1 | PCMSK1 &= ~((1 << PCINT8) |(1 << PCINT9) | (1 << PCINT10) | (1 << PCINT11) | (1 << PCINT13)| (1 << PCINT15)); // disable the other Interrupts of this group |
ich wollt nun trotzdem noch auf nummer sicher gehn und jedesmal, wenn ich einen der beiden Interrupts wieder freigeben (werden innerhalb des Codes auch deaktiviert) vorher das dazugehörige Flag löschen, damit nicht sofort und ungewollt ein Interrupt ausgelöst wird, weil das Flag gerade gesetz ist. Wie mache ich das, wenn ich nicht wioll dass dabei die ISR aufgerufen wird? Bzw. ist das überhaupt sinnvoll? Dankesehr :)
und noch eine Frage: 4.) Gibt es überhaupt eine Möglichkeit, innerhalb der ISR herauszufinden, welcher der 8 Interrupts (PCINT8-15) den Interrupt ausgelöst hat?
Manuel schrieb: > 1.) Ich habe deinen ersten Beitrag nicht ganz verstanden: wenn ich das > Flag löschen will, schreib ich eine 1 rein, damit die ISR ausgeführt > wird und dadurch das Flag gelöscht wird? Von welchen Bits reden wir eigentlich? Ich rede von den Bits im EIFR. Das sind die Bits, welche von der Hardware gesetzt werden, wenn ein bestimmtes Ereignis (in diesem Fall eben Pin Change) eintritt. Wird von der Hardware ein Pin Change festgestellt, wird das zugehörige Bit im EIFR auf 1 gesetzt. Damit ist noch nichts ausgesagt, was weiter passiert. Diese Bits registrieren nur, dass das Ereignis stattgefunden hat. Das muss auch so sein, denn es muss einen Mechanismus geben, der genau dieses registriert, wenn die zugehörige ISR nicht ausgeführt werden kann, zb weil gerade eine Timer-ISR am arbeiten ist. Die wird ja deswegen nicht unterbrochen, sondern arbeitet fertig ab, nach dem Return von dieser ISR werden die Interrupts global wieder freigegeben und dann bemerkt die CPU, dass eines dieser Flags in EIFR gesetzt ist und entscheidet weiter ob das zugehörige Mask Bit gesetzt ist und wenn ja, wird die ISR aufgerufen. Du hast also 2 Mechanismen am Werk * der eine ist dafür zuständig, das Auftreten eines Ereignisses zu registrieren. Das sind die Bits im EIFR, oder allgemeiner ausgedrückt sind das die Bits, die im Datenblatt immer irgendwie etwas mit "Interupt Flag" im Namen haben. Das 'Flag' ist der Hinweis darauf, dass das die 'Merker' sind, die sich das AUftreten eines Ereignisses merken. Das sind auch die Bits, die mittels einschreiben einer 1 gelöscht werden. * der andere Mechanismus ist der Mechanismus, der darüber entscheidet, ob eine ISR aufgerufen wird. Auch das ist bei allen Interrupts systemweit gleich. Zum einen gibt es ein Bit, das spezifisch für einen bestimmten Interrupt ist. Zum anderen gibt es die globale Interrupt Freigabe. Damit eine ISR aufgerufen wird, müssen also 3 Bedingungen zutreffen, die man mit 2 Schalgworten zusammenfassen könnte: Das Ereignis muss eingetreten sein UND die entsprechenden ISR müssen freigegeben sein. * Das entsprechende Ereignis muss aufgetreten sein, sprich das zugehörige 'Interupt Flag' Bit muss gesetzt sein. Logisch, gab es keinen Timer Overflow, wird auch kein Timer Overflow Interrupt ausgelöst. * Das spezifische Interupt Freigabe Bit für diesen Interrupt muss gesetzt sein. Auch logisch. Nur weil ein Timer Overflow aufgetreten ist, bedeutet das ja nicht, dass mich der interessiert. Ich muss also explizit sagen: Ich will auf Timer Overflows in Form einer ISR reagieren. * Die globale Interrupt Freigabe muss gesetzt sein (sei()). Auch logisch. Es muss einen Mechanismus geben, mit dem man alle Interrupts auf einen Schlag abschlaten kann, ohne dann beim Wiedereinschalten durch die ganze Neukonfiguration aller Interrupts gehen zu müssen. Ein Hauptschalter sozusagen. > Was ist aber wenn ich nicht > will dass die ISR ausgeführt wird? Dann gibst du den Interrupt eben nicht frei. Aber deswegen tritt ja das Ereignis immer noch auf, auch wenn du nicht in Form einer ISR darauf reagierst. > Warum kann ich nicht einfach eine 0 > rein schreiben, ohne dass die ISR ausgeführt wird? Ich denke, wir reden im Moment von verschiedenen Bits. Es sind ausschliesslich die 'Interupt Flags' die durch einschreiben einer 1 gelöscht werden. Das sind aber die Merker-Bits. Die, in denen das Auftreten eines Ereignisses registriert wird. > 2.) Meiner Meinung nach müsste nun nach deinen Erklärungen mit folgender > Zeile ein Interrupt ausgelöst und die ISR ausgeführt werden (zusätzlich > zu vorigem Code): >
1 | > EIFR |= (1<<PCIF1); |
2 | >
|
> Funktioniert aber nicht, warum?
Weil du so das Bit löscht und nicht setzt.
Diese Bits im Flag Register werden durch das Auftreten des zugehörigen
Ereignisses gesetzt. Von der Hardware. Wenn du sie gewollte setzen
willst, dann steht es dir frei selber im Programm durch Beschreiben der
Port Register ein derartiges Ereignis auszulösen. Aber abgesehen davon
kannst du die nicht setzen. Du kannst sie nur löschen, wenn du willst.
:
Bearbeitet durch User
Hi >4.) Gibt es überhaupt eine Möglichkeit, innerhalb der ISR >herauszufinden, welcher der 8 Interrupts (PCINT8-15) den Interrupt >ausgelöst hat? Geht nur wenn du dir den Zustand vom vorherigen Interrupt gemerkt hast. Dann reicht ein Ex-Or. MfG Spess
Hmmm, danke für die ausfürliche Antwort. Wenn ich nun wie oben im Code beschrieben nur die bedien externen Interrupts PCINT12 und PCINT14 aktiviert (1 gesetzt) habe und die anderen 6 dieser Gruppe (8-15) deaktiviert (0 gesetzt) habe, kann ich davon ausgehen, dass die (gemeinsame) ISR nur von ereignissen an PCINT 12 und 14 aufgerufen wird? Alle anderen setzten zwar das PCIF1 im EIFR, lösen aber die ISR NICHT aus? Ist das korrekt? Aber wenn die deaktivierten auch eine 1 ins EIFR schreiben, woher weiß der Controller dann, welcher INterrupt das war? Es gibt ja nur 1 Bit im EIFR (PCIF1) für 8 Interruptquellen? Warum sollte man dann das Interrupt Flag eigentlich löschen, wenn die ISR sowiso nicht ausgelöst wird? Und wie ist das mit dem Erkennen des Interrupts in der ISR? habe ich da eine Chance zu erfahren, von welchem der 8 Interrupts die ISR ausgelöst wurde (angenommen alle wären aktiviert)? Tut mir leid, aber ich denke ich steh noch auf der Leitung... Vielen Dank für die Hilfe!
Manuel schrieb: > Hmmm, danke für die ausfürliche Antwort. > > Wenn ich nun wie oben im Code beschrieben nur die bedien externen > Interrupts PCINT12 und PCINT14 aktiviert (1 gesetzt) habe und die > anderen 6 dieser Gruppe (8-15) deaktiviert (0 gesetzt) habe, kann ich > davon ausgehen, dass die (gemeinsame) ISR nur von ereignissen an PCINT > 12 und 14 aufgerufen wird? Alle anderen setzten zwar das PCIF1 im EIFR, > lösen aber die ISR NICHT aus? Ist das korrekt? Nicht ganz. Das PCMSK3 Register sitzt noch vor dem EIFR Register. D.h. damit wählst du aus, welche Pins überhaupt bis zum EIFR durchkommen. > Warum sollte man dann das Interrupt Flag eigentlich löschen, wenn die > ISR sowiso nicht ausgelöst wird? Wenn dich dieses Flag im ganzen restlichen Programm nirgends interessiert, brauchst du dich auch nicht darum kümmern. > > Und wie ist das mit dem Erkennen des Interrupts in der ISR? habe ich da > eine Chance zu erfahren, von welchem der 8 Interrupts die ISR ausgelöst > wurde (angenommen alle wären aktiviert)? Nur weil du einen Pin-change aktiviert hast, bedeutet das ja nicht, dass der Pin seine normale reguläre Funktion verliert. Du kannst selbstverständlich nach wie vor das PINx Register auslesen und daraus deine Schlüsse ziehen.
Warum PCMSK3??? Meinst du PCMSK1? Jetz verstehe ich gar nichts mehr :( Mit PCMSK1 stelle ich PCINT12 und 14 auf High und die anderen 6 auf Low... Was muss ich denn im PCMSK3 tun, damit die ISR definitiv nur von diesen beiden (PCINT12 und 14) ausgeläöst wird????
Manuel schrieb: > Warum PCMSK3??? Meinst du PCMSK1? Jetz verstehe ich gar nichts mehr :( Ja, mein ich. Mein Fehler. Hab beim Scrollen durch das Datenblatt nicht aufgepasst. Wobei: Im MOment bin ich mir jetzt selbst auch unsicher, wie das wirklich läuft. Die Beschreibung ist da etwas seltsam
1 | • Bit 7:0 – PCINT15:8: Pin Change Enable Mask 15:8 |
2 | Each PCINT15:8-bit selects whether pin change interrupt is enabled |
3 | on the corresponding I/O pin. If PCINT15:8 is set and the PCIE1 bit |
4 | in EIMSK is set, pin change interrupt is enabled on the corresponding |
5 | I/O pin. If PCINT15:8 is cleared, pin change interrupt on the |
6 | corresponding I/O pin is disabled. |
Das fällt der Beschreibung nach in den Zustaändigkeitsbereich Auswerten des Interupt Flag Bits und nicht Setzen des Interupt Flag Bits Leider finde ich im Datenblatt keine Zeichnung, in der die Anordnung und der Einflussbereich der diversen Flags ersichtlich ist. Im Zweifelsfall: mit einem Testprogramm ausprobieren und ergründen wie die Zusammenhänge wirklich sind.
Karl Heinz schrieb: > Leider finde ich im Datenblatt keine Zeichnung, in der die Anordnung und > der Einflussbereich der diversen Flags ersichtlich ist. Doch. Hier in der Figure 12-1 sieht man es. Die PCMSK(x) Register beeinflussen die Verarbeiteung, an deren Ende das Setzen der PCIF (also der Flag Register) steht. Passt also schon. Mittel PCMSKx wählst du aus, welche Eingangsleitung überhaupt zugelassen sind, das zugehörige Flag Bit zu setzen. Edit: IMHO ist die Beschreibung dir Registerfunktionalität nicht ganz glücklich gewählt.
:
Bearbeitet durch User
Hi Wenn PCINT12 und PCINT14 einen Interrupt auslösen sollen müssen PCIE1 in EIMSK sowie PCINT14 und PCINT12 in PCMSK1 gesetzt sein. Bei einem PinChange wird dann PCIF1 in EIFR gesetzt und ggf. PCINT1 ausgelöst. MfG Spess
Das bedeutet, dass das PCIF1 in EIFR nun doch nur durch Pinchanges an PCINT12 und 14 gesetzt wird und nicht durch alle 8?
Hi >Das bedeutet, dass das PCIF1 in EIFR nun doch nur durch Pinchanges an >PCINT12 und 14 gesetzt wird und nicht durch alle 8? Ja. Sonst hätten die PCMSK-Register ja keinen Sinn. MfG Spess
OK, das wurde dann ursprünglich falsch interpretiert... Danke euch beiden für die Hilfe!!!
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.