Forum: Mikrocontroller und Digitale Elektronik Interrupt mittels Flag erkenne, kein jump an die Interrupt Vector Addr.


von C. H. (hedie)


Lesenswert?

Hallo zusammen

Ich möchte, einen Interrupt mittels Polling erkennen.

Dazu möchte ich das EIRF Register auslesen.


Doch ich weiss nicht genau, wie ich die Register konfigurieren muss, 
damit der uC nicht an die Vector Addresse springt. Denn dann wird das 
Flag gelöscht.

Hier mein Code:
1
EICRA |= (1<<ISC11) | (1<<ISC01);  //INT0 und INT1 auf fallende Flanke (DB Seite: 67)
2
  EIMSK |= (1<<INT0)   | (1<<INT1);  //INT0 und INT1 aktivieren
3
4
  sei();

Das ich das EICRA beschreiben muss ist definitiv klar, aber muss ich 
auch die Bits im EIMSK setzen? oder bestimme ich damit das gesprungen 
wird?

Ich möchte nur, dass das Flag gesetzt wird.

Danke schonmal

von Marius W. (mw1987)


Lesenswert?

Wozu willst du das? Wenn du einen externen Interrupt mittels Polling 
überwachen wollst, dann überwache doch einfach den Pin und mach ne 
einfache Flankenerkennung:
1
aktuell = einlesen();
2
if(aktuell != gespeichert)
3
{
4
   foo();
5
}
6
gespeichert = aktuell;

Gruß
Marius

von C. H. (hedie)


Lesenswert?

Marius Wensing schrieb:
> Wozu willst du das? Wenn du einen externen Interrupt mittels Polling
> überwachen wollst, dann überwache doch einfach den Pin und mach ne
> einfache Flankenerkennung:aktuell = einlesen();
> if(aktuell != gespeichert)
> {
>    foo();
> }
> gespeichert = aktuell;
>
> Gruß
> Marius

Danke für die Antwort.

Das wäre eine Möglichkeit, jedoch kann ich das Polling nicht permanent 
durchführen.

Die Flanke ist nur kurzzeitig vorhanden, deshalb möchte ich einfach 
sobald ich im Programm Zeit fürs Polling habe, schauen, ob der INT 
bereits gekommen ist.

von Dr. Sommer (Gast)


Lesenswert?

Claudio Hediger schrieb:
> Die Flanke ist nur kurzzeitig vorhanden, deshalb möchte ich einfach
> sobald ich im Programm Zeit fürs Polling habe, schauen, ob der INT
> bereits gekommen ist.

Dazu im Interrupt Vektor ein Flag (globale Variable) setzen, und in der 
Mainloop abfragen, sobald Zeit dafür ist. So wird das üblicherweise 
gemacht

von Peter II (Gast)


Lesenswert?

Claudio Hediger schrieb:
> Die Flanke ist nur kurzzeitig vorhanden, deshalb möchte ich einfach
> sobald ich im Programm Zeit fürs Polling habe, schauen, ob der INT
> bereits gekommen ist.

dann setze doch ein Flag im der ISR - wie es andere auf machen.

von Mr. Interruptor (Gast)


Lesenswert?

Im Interrupt ein flag setzten (globale variable) und wieder zurück zum 
normalen programm kommen.

Sobald du Zeit hast -> Flag abfragen -> drauf reagieren

von Dr. Sommer (Gast)


Lesenswert?

Edit: Ich meinte natürlich nicht Interrupt Vector, sondern Interrupt 
Routine...

von Mr. Interruptor (Gast)


Lesenswert?

Ich meine natürlich nicht Interrupt sondern in der Interrupt Service 
Routine das flag setzten. ggg

von C. H. (hedie)


Lesenswert?

Peter II schrieb:
> Claudio Hediger schrieb:
>> Die Flanke ist nur kurzzeitig vorhanden, deshalb möchte ich einfach
>> sobald ich im Programm Zeit fürs Polling habe, schauen, ob der INT
>> bereits gekommen ist.
>
> dann setze doch ein Flag im der ISR - wie es andere auf machen.

Wäre eine Möglichkeit, aber wozu zusätzliche Flags benützen wenn es doch 
bereits ein vorhandenes gibt.

Hier ein Auszug aus dem DB:
1
• Bit 1 – INTF1: External interrupt flag 1
2
When an edge or logic change on the INT1 pin triggers an interrupt request, INTF1 becomes set
3
(one). If the I-bit in SREG and the INT1 bit in EIMSK are set (one), the MCU will jump to the corresponding
4
interrupt vector. The flag is cleared when the interrupt routine is executed.
5
Alternatively, the flag can be cleared by writing a logical one to it. This flag is always cleared
6
when INT1 is configured as a level interrupt.

Diesem Text nach, müsste es möglich sein ohne einen Aufruf 
durchzukommen.
Aber ich dachte wenn ich im EIMSK die INTs nicht setze, geht garnichts
1
Alternatively, the flag can be cleared by writing a logical one to it.
Macht diese stelle überhaupt Sinn?
Meiner Meinung nach müsste man eine logische 0 schreiben.
Denn es wird ja eine eins gesetzt wenn ein Interrupt eintritt

von Falk B. (falk)


Lesenswert?

@  Claudio Hediger (hedie)

>Ich möchte, einen Interrupt mittels Polling erkennen.

Kann man machen.

>Dazu möchte ich das EIRF Register auslesen.

Dann tu das.

>Doch ich weiss nicht genau, wie ich die Register konfigurieren muss,
>damit der uC nicht an die Vector Addresse springt. Denn dann wird das
>Flag gelöscht.

>Hier mein Code:

>EICRA |= (1<<ISC11) | (1<<ISC01);  //INT0 und INT1 auf fallende Flanke

OK.

>(DB Seite: 67)
>  EIMSK |= (1<<INT0)   | (1<<INT1);  //INT0 und INT1 aktivieren

Nö. FREIGEBEN darfst du die Interrupts nicht. Die Funktion zum setzen 
der Flags ist aber dennoch aktiv und kann per Polling gelesen und auch 
gelöscht werden. Siehe Datenblatt.

>auch die Bits im EIMSK setzen? oder bestimme ich damit das gesprungen
>wird?

Ja.

>Ich möchte nur, dass das Flag gesetzt wird.

Also MSK auf 0.

von C. H. (hedie)


Lesenswert?

Falk Brunner schrieb:
>>Ich möchte, einen Interrupt mittels Polling erkennen.
>
> Kann man machen.

Danke falk für deine Antwort


Was sagst du dazu:
1
Alternatively, the flag can be cleared by writing a logical one to it.

Macht diese stelle überhaupt Sinn?
Meiner Meinung nach müsste man eine logische 0 schreiben.
Denn es wird ja eine eins gesetzt wenn ein Interrupt eintritt

von Falk B. (falk)


Lesenswert?

@  Claudio Hediger (hedie)

>Aber ich dachte wenn ich im EIMSK die INTs nicht setze, geht garnichts

Doch. Die INterruptfunktionen sind praktisch immer aktiv, nur die 
Wirkung, nämlich das Ausführen der ISR, wird durch das entsprechende 
MSK-Bit gesteuert.

>Alternatively, the flag can be cleared by writing a logical one to it.

>Macht diese stelle überhaupt Sinn?

Ja, ist halt eine Ausnahme.

von C. H. (hedie)


Lesenswert?

Falk Brunner schrieb:
> @  Claudio Hediger (hedie)
>
>>Aber ich dachte wenn ich im EIMSK die INTs nicht setze, geht garnichts
>
> Doch. Die INterruptfunktionen sind praktisch immer aktiv, nur die
> Wirkung, nämlich das Ausführen der ISR, wird durch das entsprechende
> MSK-Bit gesteuert.
>
>>Alternatively, the flag can be cleared by writing a logical one to it.
>
>>Macht diese stelle überhaupt Sinn?
>
> Ja, ist halt eine Ausnahme.

Danke,

Aber den
1
 sei()
 brauchts schon oder?

von Vn N. (wefwef_s)


Lesenswert?

Nein. Wofür auch?

von Karl H. (kbuchegg)


Lesenswert?

Claudio Hediger schrieb:

> Was sagst du dazu:
>
>
1
Alternatively, the flag can be cleared by writing a logical one to
2
> it.
>
> Macht diese stelle überhaupt Sinn?

Natürlich macht das Sinn.
Was du brauchst, ist eine Möglichkeit, wie du gezielt eines oder mehrere 
Bits im Register atomar löschen kannst.

> Meiner Meinung nach müsste man eine logische 0 schreiben.

Sieh es so an:
Wenn du auf das Register schreibst, beschreibst du nicht das Bit, 
sondern du teilst den µC mit, welche Interrupt Request Flags zu löschen 
sind.

von Peter D. (peda)


Lesenswert?

Claudio Hediger schrieb:
> Meiner Meinung nach müsste man eine logische 0 schreiben.

Ja, da hatten die AVR-ler wohl den Schalk im Nacken.
Es stimmt aber, man muß setzen, um zu löschen.

Wenn man z.B. vom 8051 kommt, wo es logisch richtig implementiert ist, 
tappt man unweigerlich in diese Fallgrube.

Es gibt dadurch auch unschöne Seiteneffekte. Wenn das Register noch 
andere Bits enthält, können Interrupts "versehentlich" gelöscht werden 
(OR-/AND-Instruktionen), z.B. Beim TWI oder ADC.


Peter

von Marcus O. (marcus6100)


Lesenswert?

Peter Dannegger schrieb:

> Ja, da hatten die AVR-ler wohl den Schalk im Nacken.

Könnte man meinen wenn man noch nie davon gehört hat.
Aber es ist die beste Lösung.

Claudio Hediger schrieb:

> Meiner Meinung nach müsste man eine logische 0 schreiben.

Das schreiben einer 0 auf das Interrupt bit das du löschen
willst wäre nur dann eine Möglichkeit, wenn du gleichzeitig alle
Bits die du nicht löschen willst mit einer 1 beschreibst.

Da diese Logik aber noch seltsamer wäre als einfach nur alle
Bits die gelöscht werden sollen mit einer 1 zu beschreiben
wurde das nicht so implementiert.

Was garnicht funktionieren würde ist Auslesen, Ausmaskieren und 
Zurückschreiben (RMW).

Während so eines RMW Zyklus könnte nämlich ein weiterer Interrupt
kommen der ein bit setzt, und dann geht dieses verloren.

Beispielablauf:

Interrupt 1 passiert:
INT ist 0x01 // interrupt bit 0 ist gesetzt

Auslesen:
A = INT

Interrupt 2 passiert:
INT ist 0x03 // interrupt bit 0 und 1 ist gesetzt

Ausmaskieren
A &= ~0x01
=> A ist 0x00

Zurückschreiben:
INT = A

=> INT ist 0x00, oops wir haben aus versehen interrupt bit 1 gelöscht.



Löscht man dagegen Interrupts durch schreiben einer 1 ist alles ganz 
einfach:

Beispielablauf:

Interrupt 1 passiert:
INT ist 0x01 // interrupt bit 0 ist gesetzt

Interrupt 2 passiert (ob jetzt oder später ist egal):
INT ist 0x03 // interrupt bit 0 und 1 ist gesetzt

Schreiben einer 1 auf das bit das gelöscht werden soll (atomar)

INT = 0x01

=> INT ist 0x02 // interrupt bit 1 ist noch gesetzt, die Hardware hat 
genau das gewünschte bit gelöscht

von Sam P. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Es gibt dadurch auch unschöne Seiteneffekte. Wenn das Register noch
> andere Bits enthält, können Interrupts "versehentlich" gelöscht werden
> (OR-/AND-Instruktionen), z.B. Beim TWI oder ADC.

Genau deswegen macht Atmel es so. Das hat nichts mit Schalk oder 
"logisch richtig" zu tun, sondern damit, dass man die Bits, die man 
nicht verändern möchte, auf 0 belässt, was beim Zusammensetzen von 
Registerwerten über OR automatisch geschieht.

Klar, wer mit den Bit-Set/Bit-Clear-Assemblerbefehlen einzelne Bits 
anspricht, für den wirkt das unintuitiv, aber wenn man das gesamte 
Register beschreiben möchte, für den ist das ungemein bequem, diese Bits 
einfach ignorieren zu dürfen, die einen nicht interessieren.

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.