Interrupt

Hallo,

ich würde gerne mehr über das Thema Interrupt erfahren, bin aber offensichtlich trotz Google zu doof hilfreiche Seiten zu finden.

Es geht mir nicht um von außerhalb eingeleitete Interrupts (Interrupt Pin), sondern um Interrupts, welche innerhalb des geschriebenen Codes ausgeführt werden sollen (sprich softwareseitig).

Hoffe, ich hab mich halbwegs verständlich ausgedrückt.

Gruß Chris

Der AVR kennt keine Softwareinterrupts. Die Idee kannst also vollständig knicken.

Hallo,

ich würde gerne mehr über das Thema Interrupt erfahren, bin aber offensichtlich trotz Google zu doof hilfreiche Seiten zu finden.

Kann ich mir nicht vorstellen. Muss Google wohl schon wieder im Wartungsmodus sein :D

Schon einmal angefangen, dass Datenblatt zu studieren? Da sollte alles drinstehen, was man wissen muss.

Es geht mir nicht um von außerhalb eingeleitete Interrupts (Interrupt Pin), sondern um Interrupts, welche innerhalb des geschriebenen Codes ausgeführt werden sollen (sprich softwareseitig).

Steht alles im Datenblatt. @Combie: Ich glaube er meint hier die Timerinterrupts.

Danke. Das Stichwort "Timerinterrupt" fehlte mir.

Gruß Chris

@Combie: Ich glaube er meint hier die Timerinterrupts.

Kann sein...

Die werden aber nicht von einer Software ausgelöst.

Man kann die externen Interrupts via Software triggern, auch mit pinMode(2/3, OUTPUT) sind diese aktiv.

The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins.
Observe that, if enabled, the interrupts will trigger even if the INT0 and INT1
or PCINT23...0 pins are configured as outputs.
This feature provides a way of generating a software interrupt.

Page 70 External Interrupts, ATMEL Datasheet ATmega48A/PA/88A/PA/168A/PA/328/P
Rev.: Atmel-8271I-AVR-ATmega48A/48PA/88A/88PA/168A/168PA/328/328P-Datasheet_10/2014.

Das musste ich kurz verifizieren, hier also ein Beispielsketch:

const byte Pin = 2;
volatile byte incMe;
void incIt() {
  incMe++;
}
void state() {
  Serial.print("IncMe "); Serial.println(incMe);
}
void setup() {
  Serial.begin(115200);
  pinMode(Pin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(Pin), incIt, CHANGE);
  state();
  digitalWrite(Pin, HIGH);
  state();
  digitalWrite(Pin, !digitalRead(Pin));
  digitalWrite(Pin, !digitalRead(Pin));
  state();
  digitalWrite(Pin, !digitalRead(Pin));
  digitalWrite(Pin, !digitalRead(Pin));
  digitalWrite(Pin, !digitalRead(Pin));
  state();
}
void loop() {}
IncMe 0
IncMe 1
IncMe 3
IncMe 6

An dieser Stelle sollte noch expliziert erwähnt werden, das globale Variablen die im Interrupt verwendet werden volatile definiert sein sollten.
So wie Whandall es gezeigt hat.

Was passiert aber wenn eine globale Variable die größer als ein Byte ist von außen verändert/zugegriffen wird ?
Im Forum wurde dies so beschrieben das man die Interrupts in diesem Zeitraum stoppen sollte.

Ich habe sowas schon ohne sei() /cli() gemacht, funktioniert auch so.
Kann natürlich auch Zufall sein … Meinungen dazu ?

rudirabbit: Was passiert aber wenn eine globale Variable die größer als ein Byte ist von außen verändert/zugegriffen wird ?

Ja, das ist Zufall. Wenn du Glück hast geht es gut. Wenn du Pech hast wird ein Byte gelesen und vor dem nächsten Byte kommt ein Interrupt und ändert das Byte das als nächstes gelesen werden soll. Das ist vielleicht unwahrscheinlich und meistens geht es gut, aber es kann passieren.

Im Forum wurde dies so beschrieben das man die Interrupts in diesem Zeitraum stoppen sollte.

Korrekt.

Auf dem AVR noch ein paar Makros dazu: http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html Manchmal sieht man auch dass das SREG Register per Hand gesichert und danach zurück geschrieben wird. Dabei geht es auch um das Interrupt Enable Bit

Aber cli()/sei() bzw. noInterrupts()/interrupts() tut es auch wenn man genau weiß dass die Interrupts vorher aktiviert waren. Was meistens der Fall ist

So kann man die Funktion unabhängig vom aktuellen Interrupt-Enable-Zustand benutzen.

volatile int iISRValue;

int getISRValue() {
  byte sreg;
  int val;

  sreg = SREG;
  cli();
  val = iISRValue;
  SREG = sreg;

  return val;
}

Beispiel für 16 Bit Register Zugriff http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_16bitio.html