Interrupt in einer Interrupt Dienstroutine sperren ?

Programmierung und Hardwaredesign mit Arduino, AVR, PIC und Konsorten.

Moderatoren: MaxZ, ebastler, SeriousD

Antworten
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

Hallo zusammen

Arduino UNO: wenn z.Bsp. ein Interrupt ausgelöst wurde, durch eine Pegeländerung an einem Eingang, verzweigt das Programm ja in die Interrupt Dienstroutine.

Muss nun in dieser Interrupt Dienstroutine der Interrupt gesperrt werden, damit eine Pegeländerung an einem Eingang, wenn sich das Programm noch in dieser Interrupt Dienstroutine befindet , nicht erneut einen Interrupt auslöst ?
Oder ist das von vornherein ausgeschlossen ?

Gruss
LBS
Benutzeravatar

Thunderbolt
Beiträge: 2869
Registriert: Fr 7. Apr 2006, 14:05
Spezialgebiet: Physik,Elektronik,Blender
Schule/Uni/Arbeit: M.Sc ET, Hardwareentwickler
Wohnort: 65366 Geisenheim (Hessen)
Hat sich bedankt: 1 Mal
Danksagung erhalten: 70 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Thunderbolt »

Ich glaube wenn du in 'n ISR bist und 'n interrupt reinkommt, wird 'n flag gesetzt, und die laufende ISR erst fertig ausgeführt, und sich dann um den nächsten interrupt gekümmert
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

EDIT:

Kurze Google Suche gibt die Antwort für AVR:
https://stackoverflow.com/questions/241 ... pt-happens

Thunder hat Recht, beim Aufruf der ISR werden interrupts deaktiviert und dann beim Return wieder aktiviert.

---
Original:


Ansonsten kannst du die entsprechenden Befehle dazu nutzen.

noInterrupts und interrupts:
https://www.arduino.cc/reference/en/lan ... nterrupts/
https://www.arduino.cc/reference/en/lan ... nterrupts/

lg,
count-doku
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

@Thunderbolt
genau, das meinte ich damit, war mir aber nicht sicher

@Count-Doku
noInterrupts und interrupts werden zum Ein- bzw. Absschalten des Interrupt in der Loop-Schleife verwendet, wenn ich das richtig verstanden habe

Nochmal ne Frage zu den Interrupt Pinbelegungen am MEGA:
Pinbelegung.jpg
Pinbelegung.jpg (48.53 KiB) 4821 mal betrachtet
Interrupt 0 ist z.Bsp. auf dem linken Bild auf Pin 21. Rechts ist Interrupt 0 auf Pin 2.
Was ist nun richtig ?
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

noInterrupts und interrupts, kannst du benutzen wo immer du möchtest,
die Befehle sind nur macros, die dann das entsprechende Flag setzen / löschen.

(Aus Arduino.h)

Code: Alles auswählen

#define interrupts() sei()
#define noInterrupts() cli()
Außerdem möchte ich noch anmerken, dass ich nicht sicher bin (und auch nicht davon ausgehen würde), dass interrupts auf einer Warteschlange landen.
Ich glaube nicht, dass während ISR A abgearbeitet wird und noch andere Interrupts ankommen, diese nach ISR A ausgeführt werden.
Das mag bei unterschiedlichen Interrupts funktionieren (weil es verschiedene Flags gibt) aber wenn gerade noch die ISR für Pin falling abgearbeitet wird und der Pin erneut auf low geht, wird die nicht nochmal (weder sofort noch später) ausgeführt werden.

---

Zu deiner Pin Frage, im Zweifelsfall benutzt du die digitalPinToInterrupt Methode :) Da steckst du eine Pin Nummer rein, und kriegst eine Interrupt Nummer raus.
Unabhängig vom verwendeten Arduino.

Aus der Mega\Pins_arduino.h

Code: Alles auswählen

#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : ((p) >= 18 && (p) <= 21 ? 23 - (p) : NOT_AN_INTERRUPT)))
Also ist Interrupt 0 -> Pin 2.

lg,
count-doku
Zuletzt geändert von Heisath am Mi 20. Feb 2019, 08:51, insgesamt 1-mal geändert.
Benutzeravatar

MaxZ
Beiträge: 1163
Registriert: So 28. Jun 2015, 10:20
Schule/Uni/Arbeit: Mechatronik, Karlsruher Institut für Technologie
Wohnort: Luxemburg / Karlsruhe
Hat sich bedankt: 258 Mal
Danksagung erhalten: 157 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von MaxZ »

Außerdem möchte ich noch anmerken, dass ich nicht sicher bin (und auch nicht davon ausgehen würde), dass interrupts auf einer Warteschlange landen.
Ich glaube nicht, dass während ISR A abgearbeitet wird und noch andere Interrupts ankommen, diese nach ISR A ausgeführt werden.
Das mag bei unterschiedlichen Interrupts funktionieren (weil es verschiedene Flags gibt) aber wenn gerade noch die ISR für Pin falling abgearbeitet
wird und der Pin erneut auf low geht, wird die nicht nochmal (weder sofort noch später) ausgeführt werden.
I.d.R. ist das Rücksetzen der Flag die allererste Aktion in einer ISR. Somit kann zumindest noch ein weiterer gleicher Interrupt erkannt werden, während die ISR noch abgearbeitet wird. Allerdings weiß ich nicht, wie genau das bei Arduino gehandhabt wird. Könnte man austesten, indem man das entsprechende Register innerhalb der ISR ausliest.


Liebe Grüße,
Max
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

Das Prog (Grundgerüst) dient zur Abfrage einer 4x4 Tastatur:

Code: Alles auswählen

int button = 0;        
volatile int T_Code = 0;  // Variable die den Tastencode enthält

void setup() {
  
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  pinMode( 8, INPUT_PULLUP);
  pinMode( 9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  
  
  pinMode(2, INPUT_PULLUP);            // interrupt 0 auf Pin 2 am UNO
  attachInterrupt(0, Taste, FALLING);  // Wechsel von H nach L am Pin 2 löst Interrupt 0 aus
}

void loop()
{
  button = T_Code;
  noInterrupts();    // Interrupt sperren
  delay(50);         // Entprellzeit
  interrupts();      // Interrupt freigeben
}


//
void Taste() 
     { 
     T_Code = 0;  
     digitalWrite(4, HIGH);  
     digitalWrite(5, HIGH);
     digitalWrite(6, HIGH);   
     digitalWrite(7, HIGH);
         
     //----------Eingang E1---------------------------  
     digitalWrite(4, LOW);   // Eingang E1 auf LOW
      if (digitalRead( 8) == LOW) {T_Code = 0x01;} 
      if (digitalRead( 9) == LOW) {T_Code = 0x02;} 
      if (digitalRead(10) == LOW) {T_Code = 0x03;}      
      if (digitalRead(11) == LOW) {T_Code = 0x0A;} 
     digitalWrite(2, HIGH);  
    
     //----------Eingang E2----------------------------    
     digitalWrite(5, LOW);   // Eingang E1 auf LOW
      if (digitalRead( 8) == LOW) {T_Code = 0x04;} 
      if (digitalRead( 9) == LOW) {T_Code = 0x05;} 
      if (digitalRead(10) == LOW) {T_Code = 0x06;}      
      if (digitalRead(11) == LOW) {T_Code = 0x0B;}       
     digitalWrite(3, HIGH);  
    
     //----------Eingang E3----------------------------  
     digitalWrite(6, LOW);   // Eingang E1 auf LOW
      if (digitalRead( 8) == LOW) {T_Code = 0x07;} 
      if (digitalRead( 9) == LOW) {T_Code = 0x08;} 
      if (digitalRead(10) == LOW) {T_Code = 0x09;}      
      if (digitalRead(11) == LOW) {T_Code = 0x0C;} 
     digitalWrite(4, HIGH);  
     
     //----------Eingang E4----------------------------    
     digitalWrite(7, LOW);   // Eingang E1 auf LOW
      if (digitalRead( 8) == LOW) {T_Code = 0x0E;} 
      if (digitalRead( 9) == LOW) {T_Code = 0x00;} 
      if (digitalRead(10) == LOW) {T_Code = 0x0F;}      
      if (digitalRead(11) == LOW) {T_Code = 0x0D;}       
     digitalWrite(5, HIGH);  
     }
Sobald eine Taste betätigt wird, wird hardwaremässig ein Interrupt ausgelöst (Pin 2 wechselt von High auf Low)
Wollte nur sichergehen , dass durch Tastenprellen nicht innerhalb der ISR nochmals ein Interrupt ausgelöst wird.
Es ist eigentlich egal , ob die ISR dann mehrmals durchlaufen wird bis die Taste aufhört zu prellen. Wird sich zeigen.
Hätte gern die Entprellzeit (delay) in die ISR gelegt, aber das funktioniert ja so nicht.

Gruss LBS
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

Könnte schon so hinhauen.

Aber, momentan hat E4 Pin 9 den Wert 0x00 was dem Wert von keiner Taste gedrückt (=0) entspricht. Ich bin nicht sicher ob das so soll.

---

Außerdem, nur als Hinweis, es gibt elegantere Möglichkeiten eine 4x4 Tastatur abzufragen. Du könntest z.B. mittels Timer Interrupt immer einen Eingang nach dem nächsten durchschalten und dann mit PinChange Interrupts auf eine ganze Pin Bank schauen, ob eine Taste gedrückt wurde.

Siehe dazu:
http://playground.arduino.cc/Main/PinChangeInterrupt
und / oder google mal wie man beim Atmel (ist ja im Arduino drin) entsprechend ganze Port Interrupts abfragt.

lg,
count-doku
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

muss mich korrigieren. So funktioniert die Sache programmmässig nicht. Muss den Code nochmal überarbeiten
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

Wenn du willst kann ich dazu heute Abend einen Beispielcode und Schaltung machen.
Vielleicht würde es auch helfen, wenn du mal deinen Schaltplan dazupackst.
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

@Count-Doku
Danke für dein Angebot. Ich habe es schon mal überarbeitet. Das ist die Schaltung
Grundschaltung Tastenfeld_4x4 über Interrupt_4.PNG
Grundschaltung Tastenfeld_4x4 über Interrupt_4.PNG (7.94 KiB) 4708 mal betrachtet
Der Code

Code: Alles auswählen

/*
  E1 bis E4  an Pin 4 - 7
  A1 bis A4  an Pin 8 - 11 mit Pull-Down Widerstand
  X an Pin 2  (interrupt 0) mit Pull-Down Widerstand
 */

int button = 0;        
volatile int T_Code = 0;  // Variable die den Tastencode enthält

void setup() {
  
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  pinMode( 8, INPUT);
  pinMode( 9, INPUT);
  pinMode(10, INPUT);
  pinMode(11, INPUT);

  digitalWrite(4, HIGH);  
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);   
  digitalWrite(7, HIGH);
  
  
  pinMode(2, INPUT);            // interrupt 0 auf Pin 2 am UNO
  attachInterrupt(0, Taste, RISING);  // Wechsel von LOW nach HIGH am Pin 2 löst Interrupt aus
}

void loop()
{
  // in T_Code ist der letzte Tastaturcode abgelegt
}


//
void Taste() 
     { 
     int T_Code = 0xFF;
     digitalWrite(4, LOW);  
     digitalWrite(5, LOW);
     digitalWrite(6, LOW);   
     digitalWrite(7, LOW);
        
     //-Eingang E1 auf HIGH setzen und A1 - A4 prüfen--
     digitalWrite(4, HIGH);
      if (digitalRead( 8) == HIGH) {T_Code = 0x01;} 
      if (digitalRead( 9) == HIGH) {T_Code = 0x02;} 
      if (digitalRead(10) == HIGH) {T_Code = 0x03;}      
      if (digitalRead(11) == HIGH) {T_Code = 0x0A;} 
     digitalWrite(2, LOW);  
    
     //-Eingang E2 auf HIGH setzen und A1 - A4 prüfen--    
     digitalWrite(5, HIGH);
      if (digitalRead( 8) == HIGH) {T_Code = 0x04;} 
      if (digitalRead( 9) == HIGH) {T_Code = 0x05;} 
      if (digitalRead(10) == HIGH) {T_Code = 0x06;}      
      if (digitalRead(11) == HIGH) {T_Code = 0x0B;}       
     digitalWrite(5, LOW);  
    
     //-Eingang E3 auf HIGH setzen und A1 - A4 prüfen--
     digitalWrite(6, HIGH);
      if (digitalRead( 8) == HIGH) {T_Code = 0x07;} 
      if (digitalRead( 9) == HIGH) {T_Code = 0x08;} 
      if (digitalRead(10) == HIGH) {T_Code = 0x09;}      
      if (digitalRead(11) == HIGH) {T_Code = 0x0C;} 
     digitalWrite(6, LOW);  
     
     //-Eingang E4 auf HIGH setzen und A1 - A4 prüfen-- 
     digitalWrite(7, HIGH); 
      if (digitalRead( 8) == HIGH) {T_Code = 0x0E;} 
      if (digitalRead( 9) == HIGH) {T_Code = 0x00;} 
      if (digitalRead(10) == HIGH) {T_Code = 0x0F;}      
      if (digitalRead(11) == HIGH) {T_Code = 0x0D;}       
     digitalWrite(7, LOW);  

     digitalWrite(4, HIGH);  
     digitalWrite(5, HIGH);
     digitalWrite(6, HIGH);   
     digitalWrite(7, HIGH);
     }
also: an E1 bis E4 (Pin 4 bis 7) liegt inerhalb der Loop-Schleife immer HIGH an. Pin 8 bis 11 ( A1....A4) werden durch Pull-Down Widerstände auf LOW gehalten.
Nur wenn eine Taste gedrückt wird , geht der entsprechende Pin ( A1....A4) auf HIGH und zugleich erfolgt auf "X" (Pin 2 [= Interrupt 0] am Arduino) einen Wechsel von LOW auf HIGH und ein Interrupt wird ausgelöst.
Da das recht schnell geht, ist die Taste noch gedrückt wenn das Prog in die ISR verzweigt. Dort wird dann geprüft, welche Taste gedrückt ist indem nacheinander an E1 bis E4 HIGH angelegt wird und dann getestet wird, an welchen Pin (A1 bis A4) HIGH ankommt
In der Variablen "T_Code" wird der entsprechende Wert abgelegt.
Die Schaltung und der Quellcde ist recht klein im Vergleich zu <Keypad.h>, hat allerdings den Nachteil, dass wenn 2 Tasten gedrückt werden, falsche Werde ausgegeben werden. Wenn das kritisch ist, kann man das so nicht anwenden.
Kannst ja nochmal drüber schauen, ob event. noch Fehler drin sind.

Gruss
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

Jo sieht gut aus.

Mir ist noch eine interessante andere Möglichkeit eingefallen. Wie wäre es wenn du statt den 4 Ausgängen einfach eine Widerstandskette nimmst?
Dazu dann noch als die 4 Eingänge Analoge Eingänge.

Dann musst du nicht schauen, welcher Taster es war, sondern weißt es vom Spannungslevel her sofort. und es spart Pins. Du müsstest nur schauen, welche Spannung mindestens nötig ist, um den Interrupt zu triggern. Theoretisch könnten dann sogar alle 16 Tasten an einem Pin hängen. 5V durch 17 Spannungslevel sind immer noch ~0.3V das müsste man noch gut auseinander halten können.


lg,
count-doku
Benutzeravatar

Thread-Ersteller
L_B_S
Beiträge: 531
Registriert: Fr 24. Jul 2015, 10:13
Schule/Uni/Arbeit: KFZ-Elktr.
Hat sich bedankt: 19 Mal
Danksagung erhalten: 23 Mal

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von L_B_S »

Count-Doku hat geschrieben:....Mir ist noch eine interessante andere Möglichkeit eingefallen. Wie wäre es wenn du statt den 4 Ausgängen einfach eine Widerstandskette nimmst?
Dazu dann noch als die 4 Eingänge Analoge Eingänge....
Moin erst einmal,
Diese Überlegung hatte ich auch schon. Könnte man mal in dieser Form aufbauen:
Tastenfeld_4x4 mit R und Interrupt.PNG
Tastenfeld_4x4 mit R und Interrupt.PNG (6.55 KiB) 4602 mal betrachtet
...und das Signal für den Interrupt durch einen Transistor auf den richtigen Pegel bringen. Eventuell wäre es auch noch möglich A1 bis A4 mit Widerständen so zu beschalten, dass neben dem Interrupteingang nur noch ein einziger analoger Eingang benötigt wird. Wenn alle Tasteranschlüsse frei zugänglich wären, wäre das recht einfach. Aber diese fertigen Tastenfelder sind nunmal in der Form verschaltet.

lg
Zuletzt geändert von L_B_S am Fr 22. Feb 2019, 14:50, insgesamt 2-mal geändert.
Benutzeravatar

Heisath
Beiträge: 539
Registriert: Mi 26. Jun 2013, 15:44
Hat sich bedankt: 33 Mal
Danksagung erhalten: 81 Mal
Kontaktdaten:

Re: Interrupt in einer Interrupt Dienstroutine sperren ?

Beitrag von Heisath »

Ja genau so habe ich mir das vorgestellt - und gestern Abend noch mitm ESP32 aufgebaut -> ging problemlos.
Antworten