Interrupt für mehr als LED blinken

Hallo,
habe das Problem eine Interrupt Schleife aufzurufen :~
Leider finde ich im Netz nur Beispiel Sketche mit der
Blinkenden LED. Bei diesem Sketch wird ja der Zustand der
LED über eine eigene Variable geändert, die über die Interrupt
Schleife auf HIGH oder LOW gesetzt wird.

Ich lege an Interrupt 0 (Digitaler Pin 2) 5V Spannung an und
möchte dass dann die Interrupt-Schleife so lange durchlaufen
wird, bis die 5V wider weg genommen werden.
void loop und interrupt loop unterscheiden sich nur durch
Unterschiedliche Potentiometer Signale.

Rufe ich den Interrupt Befehl so richtig auf?
Muss doch mit einer “volatile int” Variablen gearbeitet werden?
In wie weit spielt der Pull-Up Resistor an Pin 2 eine Rolle?
Gibt es eine ganz andere Lösung ohne Interrupt?

Vielen Dank im Vorraus für jegliche Hilfe!

int
  PWM_A = 8,
  DIR_A = 9,
  signal_soll,
  signal_ist,
  signal_soll_skaliert,
  signal_ist_skaliert,
  signal_soll_berechnet,
  regelabweichung;

float
  potenz6,
  potenz5,
  potenz4,
  potenz3,
  potenz2,
  summand6,
  summand5,
  summand4,
  summand3,
  summand2,
  summand1;
 
 const float FACTOR6 = 3.2445916909115E-14;
 const float FACTOR5 = 6.26984473115432E-11;
 const float FACTOR4 = 4.14486340076514E-08;
 const float FACTOR3 = 8.05562633887646E-06;
 const float FACTOR2 = 0.00229807982179864;
 const float FACTOR1 = 1.35441912656097;


void setup() {
   pinMode(PWM_A, OUTPUT); 
   pinMode(DIR_A, OUTPUT);    // Direction pin on channel A
   pinMode(signal_soll,INPUT);    // Soll-Signal
   pinMode(signal_ist,INPUT);    // Potenziometer Ist-Signal
   
   // Interrupt0 am Digital Pin 2 Ausführen
   attachInterrupt (0, interrupt, RISING);
 }

void loop() {
  
   signal_soll = analogRead(A2);    // liest Soll-Signal ein (160 - 760 = 0.8 - 3.7V)
   signal_ist = analogRead(A4);     // liest Ist-Signal ein (60 - 936 = 0.30 - 4.55V)
         
   // Signale auf gleichen Wertebereich (0 - 900) skalieren
   signal_soll_skaliert = map (signal_soll, 165, 758, 0, 900); 
   signal_ist_skaliert = map (signal_ist, 60, 930, 0, 900);
   
      potenz6 = pow(signal_soll_skaliert,6);
      potenz5 = pow(signal_soll_skaliert,5);
      potenz4 = pow(signal_soll_skaliert,4);
      potenz3 = pow(signal_soll_skaliert,3);
      potenz2 = pow(signal_soll_skaliert,2);
      
      summand6 = FACTOR6 * potenz6;
      summand5 = FACTOR5 * potenz5;
      summand4 = FACTOR4 * potenz4;
      summand3 = FACTOR3 * potenz3;
      summand2 = FACTOR2 * potenz2;
      summand1 = FACTOR1 * signal_soll_skaliert;

      signal_soll_berechnet = summand6 - summand5 + summand4 - summand3 - summand2 + summand1;

       //Regelabweichung aus Potistellungen berechnen
       regelabweichung = signal_soll_berechnet - signal_ist_skaliert; 
     

      if ( regelabweichung < 0 )
        {
         if ( regelabweichung < -30 ) {  
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 60); //120
         }
         if ( regelabweichung >= -30 && regelabweichung < -20) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 50); //100
         }
         if ( regelabweichung >= -20 && regelabweichung < -10) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 40); //80
         }
         if ( regelabweichung >= -10  && regelabweichung < -5) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 35); //60
         }
         if ( regelabweichung >= -5 && regelabweichung < 0 ) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 30); //45
         }
     }  
  
     else
     { 
         if ( regelabweichung > 30 ) {  
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 100); 
         }
         if ( regelabweichung <= 30 && regelabweichung > 20) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 70); 
         }
         if ( regelabweichung <= 20 && regelabweichung > 10) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 50); 
         }
         if ( regelabweichung <= 10 && regelabweichung > 5) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 35); 
         }
         if ( regelabweichung <= 5 && regelabweichung >= 0 ) {
          digitalWrite(DIR_A, HIGH);    
          analogWrite(PWM_A, 30);
         }
     }
 }
 
 
 void interrupt(){
     
   signal_soll = analogRead(A2);    // liest Soll-Signal ein (160 - 760 = 0.8 - 3.7V)
   signal_ist = analogRead(A4);     // liest Ist-Signal ein (96 - 936)
         
   // Signale auf gleichen Wertebereich (0 - 900) skalieren
   signal_soll_skaliert = map (signal_soll, 165, 758, 0, 900); 
   signal_ist_skaliert = map (signal_ist, 96, 930, 0, 900);
      
      potenz6 = pow(signal_soll_skaliert,6);
      potenz5 = pow(signal_soll_skaliert,5);
      potenz4 = pow(signal_soll_skaliert,4);
      potenz3 = pow(signal_soll_skaliert,3);
      potenz2 = pow(signal_soll_skaliert,2);
      
      summand6 = FACTOR6 * potenz6;
      summand5 = FACTOR5 * potenz5;
      summand4 = FACTOR4 * potenz4;
      summand3 = FACTOR3 * potenz3;
      summand2 = FACTOR2 * potenz2;
      summand1 = FACTOR1 * signal_soll_skaliert;

      signal_soll_berechnet = summand6 - summand5 + summand4 - summand3 - summand2 + summand1;
      
       //Regelabweichung aus Potistellungen berechnen
       regelabweichung = signal_soll_berechnet - signal_ist_skaliert; 
     

      if ( regelabweichung < 0 )
       {
         if ( regelabweichung < -30 ) {  
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 60); //120
         }
         if ( regelabweichung >= -30 && regelabweichung < -20) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 50); //100
         }
         if ( regelabweichung >= -20 && regelabweichung < -10) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 40); //80
         }
         if ( regelabweichung >= -10  && regelabweichung < -5) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 35); //60
         }
         if ( regelabweichung >= -5 && regelabweichung < 0 ) {
             digitalWrite(DIR_A, LOW);    
             analogWrite(PWM_A, 30); //45
         }
     }  
  
     else
     { 
         if ( regelabweichung > 30 ) {  
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 100); 
         }
         if ( regelabweichung <= 30 && regelabweichung > 20) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 70); 
         }
         if ( regelabweichung <= 20 && regelabweichung > 10) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 50); 
         }
         if ( regelabweichung <= 10 && regelabweichung > 5) {
           digitalWrite(DIR_A, HIGH);    
           analogWrite(PWM_A, 35); 
         }
         if ( regelabweichung <= 5 && regelabweichung >= 0 ) {
          digitalWrite(DIR_A, HIGH);    
          analogWrite(PWM_A, 30);
         }
     }
 }

Verstehe den Sinn nicht, warum du hier einen Interupt nutzen möchtest? Sehe doch gar keine Delays, die hier etwas blockieren können. Des weiteren scheint es ja so, dass die 5V Spannung nicht nur kurzzeitig anlieg (~ µs).

Was jedoch nicht so ganz optimiert ist, sind deine if Abfragen. Jeder if-Abfrage wird im Programm in jedem Zyklus abgerufen. Dabei kann man diese kompakter ausdrücken.
Sobald eine Anweisung erfolgreich ist, werden die anderen nicht mehr beachtet (erst wieder im nächsten loop)

if ( regelabweichung < 0 )
{
	if(regelabweichung >= -5) {
		digitalWrite(DIR_A, LOW);
		analogWrite(PWM_A, 30); //45
	}
	else if(regelabweichung >= -10) {
		digitalWrite(DIR_A, LOW);
		analogWrite(PWM_A, 35); //60
	}
	else if ( regelabweichung >= -20) {
		digitalWrite(DIR_A, LOW);
		analogWrite(PWM_A, 40); //80
	}
	else if ( regelabweichung >= -30) {
		digitalWrite(DIR_A, LOW);
		analogWrite(PWM_A, 50); //100
	}
	else {
		digitalWrite(DIR_A, LOW);
		analogWrite(PWM_A, 60); //120
	}
}
else
{
	if ( regelabweichung <= 5) {
		digitalWrite(DIR_A, HIGH);
		analogWrite(PWM_A, 30);
	}
	else if ( regelabweichung <= 10) {
		digitalWrite(DIR_A, HIGH);
		analogWrite(PWM_A, 35);
	}
	else if ( regelabweichung <= 20) {
		digitalWrite(DIR_A, HIGH);
		analogWrite(PWM_A, 50);
	}
	else if ( regelabweichung <= 30) {
		digitalWrite(DIR_A, HIGH);
		analogWrite(PWM_A, 70);
	}
	else {
		digitalWrite(DIR_A, HIGH);
		analogWrite(PWM_A, 100);
	}
}

Beispiel:

Erster Zyklus (deine Lösung)
i = 1;
if(i == 0) // falsch
if(i == 1) // wahr
if(i == 2) // falsch
if(i == 3 ) // falsch
if(i == 4) // falsch
if(i == 5) // falsch

Zweiter Zyklus (deine Lösung)
i = 5;
if(i == 0) // falsch
if(i == 1) // falsch
if(i == 2) // falsch
if(i == 3 ) // falsch
if(i == 4) // falsch
if(i == 5) // wahr

Wie du siehtst, fragt er, auch wenn bereits eine Bedingung war ist, die anderen Anweisungen ab.

Erster Zyklus (meine Lösung)
i = 1;
if(i == 0) // falsch
else if(i == 1) // wahr
else if(i == 2) // falsch wird nicht abgefragt
else if(i == 3 ) // falsch wird nicht abgefragt
else if(i == 4) // falsch wird nicht abgefragt
else if(i == 5) // falsch wird nicht abgefragt

Zweiter Zyklus (meine Lösung)
i = 5;
if(i == 0) // falsch
else if(i == 1) // falsch
else if(i == 2) // falsch
else if(i == 3 ) // falsch
else if(i == 4) // falsch
else if(i == 5) // wahr

Hallo, richtig, die 5V stehen entweder dauerhaft an oder garnicht. Habe das ganze auch schon mit einer If-Abfrage ganz zu Beginn gelöst, allerdings ist dann der ganze Regelkreis deutlich langsamer bzw. kommt dann nicht mehr hinterher. Dachte ein Interrupt würde da helfen!? Was wäre eine Alternative?

Ok Danke für den Tip mit den If Abfragen, werde ich gleich testen :)

Was heißt, der kommt dann nicht mehr hinterher?

Ein Interupt hat da garnichts mit zu tun. Welche Zykluszeiten hast du? Die meiste Zeit wird bei der Berechnung der Potenz mit deinem float Zahlen verbraten.

Max_G: Gibt es eine ganz andere Lösung ohne Interrupt?

Du möchtest zwei Regelschleifen verwenden, je nach Stand eines Umschaltpins.

Wenn das komplett unterschiedliche Regelschleifen sind, machst Du zwei komplett unterschiedliche Regelschleifen, die Du aus der loop heraus aufrufst:

void loop()
{
  if (digitalRead(UMSCHALTPIN)==HIGH) eineRegelschleife();
  else andereRegelschleife();
}

Und wenn sich die Regelschleifen nur minimal unterscheiden, machst Du eine einzige Regelschleifenfunktion mit einem Parameter, und übergibst den Zustand des Schalters als Parameter an die Funktion, die dann mit einer if-Abfrage unterscheiden kann, was zu tun ist. Dann sähe die loop-Funktion so aus:

void loop()
{
  regelschleife(digitalRead(UMSCHALTPIN));
}

Mit einer If-Abfrage, war die Regelung so, dass der Motor mit dem PWM Signal auf Position gehalten wird gut. Sobald aber die 5V angelegt wurden und dann das Programm in der "else-Schleife" war, hat der Motor sich aufgewungen. Wurde also nicht mehr an seiner Position gehalten. Zur Info, der Motor Fährt immer gegen eine Spiralfeder, die ihn wieder in Grundpositon bringt.

Zykluszeiten sind eigentlich vernachlässigbar, ich gebe eine Spannung vor und dann soll sich das einregeln, also sehr sehr langsam! Die Berechnung mit den Potenzen brauche ich leider.

Warum hat ein Interrupt hier nichts verloren??? Ein Interrupt hat doch nicht zwingend etwas mit delays zu tun oder? Ich will doch nur einfach nicht, dass der Prozessor die ganze Zeit damit beschäfftigt ist 5V abzufragen...

Ich habe nichts gesagt, dass der Interupts nichts da verloren hat. Es wird hier aber nicht gebraucht. Deine MCU ist nicht dauerhaft beschäftigt, weil es den Digital Input ausliest.

Max_G: Warum hat ein Interrupt hier nichts verloren??? Ein Interrupt hat doch nicht zwingend etwas mit delays zu tun oder? Ich will doch nur einfach nicht, dass der Prozessor die ganze Zeit damit beschäfftigt ist 5V abzufragen...

Du hast irgendwie ein ganz schlechtes Gefühl dafür, was wieviel Zeit kostet.

Um die 0V/5V abzufragen, braucht der Controller ca. 4µs, wenn Du den Arduino-Komfortbefehl digitalRead verwendest.

Wenn Deine Regelschleife 1 ms benötigt (was sie bei Deiner Art der Programmierung locker übertreffen dürfte), dann macht es den Unterschied, dass Regelschleife statt 1,000ms plus Abfrage dann 1,004 ms dauert.

Macht es wirklich einen Unterschied, ob Deine Regelschleife (mal angenommen) 1000/1,000 = 1000 mal pro Sekunde oder nur 1000/1,004 = 996 mal pro Sekunde durchläuft?

Wenn Deine Regelschleife zu langsam ist, beschleunige die Regelschleife! Oder wenn 4µs für ein digitalRead zu langsam sind, verwende direkte Zugriffe auf die Controller-Register!

Du hast irgendwie ein ganz schlechtes Gefühl dafür, was wieviel Zeit kostet.

Ich habe kein schlechtes Gefühl was wie viel Zeit kostet, ich habe überhaupt kein Gefühl dafür wie lange welche Schleife braucht! :stuck_out_tongue_closed_eyes:

Wie schon gesagt, die Geschwindigkeit ist mir eigentlich egal. Wichtig ist mir nur, dass der Motor seine vorgebenen Position hält und genau das hat er eben nunmal nicht getan mit der If-Abfrage! Deshalb hatte ich die Idee mit dem Interrupt... Allerdings habe ich die If-Abfrage über einen Analogen Pin laufen lassen, werde es mal über den digitalRead Befehl Probieren.

Wenn Deine Regelschleife zu langsam ist, beschleunige die Regelschleife!

Wie kann ich das machen?

Bin für jeden Ratschlag dankbar um "die Art meiner Programmierung" zu verbessern, da das mein erstes Projekt ist, ist da mit Sicherheit noch Luft nach oben!

Was mir gerade aufgefallen ist, was schein nicht weiter tragisch ist, da anscheinden die IDE das zurecht biegt.

Analoge Eingänge müssen in der setup nicht mit pinMode(x, INPUT) gesetzt werden. Ich denke dein Problem ist lediglich, dass dir Regelstrecken nicht ausreichend bekannt sind!

http://de.wikipedia.org/wiki/Regelstrecke

Dein Sketch sieht etwas stark nach I-Regler aus. Sicherlich nicht der beste für die Anwendung! Hier muss du schaun, mit welchen du in deinem Prozess am besten auskommst. Würde schon fast sagen, der PID Regler dürfte eine gute Wahl sein. Schnelles Regeln, welches mit der Zeit immer näher an Soll sich heranpendelt!

Max_G: Ich habe kein schlechtes Gefühl was wie viel Zeit kostet, ich habe überhaupt kein Gefühl dafür wie lange welche Schleife braucht! :stuck_out_tongue_closed_eyes:

Du kannst über den Stand des micros()-Zählers und Debug-Ausgaben auf Serial durchaus messen, wie lange Dein Code läuft.

Testcode beispielsweise:

int 
  signal_soll,
  signal_ist,
  signal_soll_skaliert,
  signal_ist_skaliert,
  signal_soll_berechnet,
  regelabweichung;
  
float
  potenz6,
  potenz5,
  potenz4,
  potenz3,
  potenz2,
  summand6,
  summand5,
  summand4,
  summand3,
  summand2,
  summand1;

 const float FACTOR6 = 3.2445916909115E-14;
 const float FACTOR5 = 6.26984473115432E-11;
 const float FACTOR4 = 4.14486340076514E-08;
 const float FACTOR3 = 8.05562633887646E-06;
 const float FACTOR2 = 0.00229807982179864;
 const float FACTOR1 = 1.35441912656097;

void setup()
{
  Serial.begin(9600);
}

void loop() {
   unsigned long zeitmessen=micros(); // Zeitmessung starten
   signal_soll = analogRead(A2);    // liest Soll-Signal ein (160 - 760 = 0.8 - 3.7V)
   signal_ist = analogRead(A4);     // liest Ist-Signal ein (60 - 936 = 0.30 - 4.55V)
   
   // Signale auf gleichen Wertebereich (0 - 900) skalieren
   signal_soll_skaliert = map (signal_soll, 165, 758, 0, 900); 
   signal_ist_skaliert = map (signal_ist, 60, 930, 0, 900);
   
      potenz6 = pow(signal_soll_skaliert,6);
      potenz5 = pow(signal_soll_skaliert,5);
      potenz4 = pow(signal_soll_skaliert,4);
      potenz3 = pow(signal_soll_skaliert,3);
      potenz2 = pow(signal_soll_skaliert,2);
      
      summand6 = FACTOR6 * potenz6;
      summand5 = FACTOR5 * potenz5;
      summand4 = FACTOR4 * potenz4;
      summand3 = FACTOR3 * potenz3;
      summand2 = FACTOR2 * potenz2;
      summand1 = FACTOR1 * signal_soll_skaliert;

      signal_soll_berechnet = summand6 - summand5 + summand4 - summand3 - summand2 + summand1;

       //Regelabweichung aus Potistellungen berechnen
       regelabweichung = signal_soll_berechnet - signal_ist_skaliert; 
   zeitmessen=micros()-zeitmessen; // Zeitmessung Ergebnis als Differenz zum Startwert bilden
   Serial.println();
   Serial.print("Regelabweichung: ");Serial.println(regelabweichung);
   Serial.println();
   Serial.println("Zeitmessung gestoppt: ");
   Serial.print(zeitmessen); Serial.println(" Mikrosekunden");
   Serial.print(zeitmessen/1000.0,3); Serial.println(" Millisekunden");
   Serial.print(zeitmessen/1000000.0,6); Serial.println(" Sekunden");
   while(1); // Endlosschleife (Programmende)
}

Damit messe ich auf einem UNO, dass das Ermitteln der Regelabweichung mit Deinem Code z.B. 1864 µs dauert (hängt ein bisschen auch von den Messwerten ab).

Wenn Du für ein digitalRead(PIN) nun 4 µs extra verbrauchst, verlangsamt sich die Ausführung um Faktor 4/1864=0,0021 bzw. um 0,21%.

Wenn es für Deine Regelung ausreicht, dass diese um die 500 mal pro Sekunde nachregelt, macht das den Kohl nicht fett.