loop() neustart durch Interupt

Hallo :slight_smile:

Ich habe mich etwas mit dem Arduino beschäftigt und auch gleich eine Frage mitgebracht.

Ich möchte durch einen Button realisieren, dass die delayzeit geändert wird. Das funktioniert auch super. Leider wird dies allerdings erst aktiv wenn der aktuelle Vorgang durchgelaufen ist. D.h. wenn die LED0 brennt und ich den Button drücke, brennt die LED0 trotzdem weiter weil die 10 Sekunden noch nicht vorbei sind. Erst bei der nächsten LED wird der neue Wert beachtet. Was auch logisch ist bei der iterativen Ausführung. Allerdings dauert mir das zulange. Bei einem delay von bsp. 100000000 will ich nicht warten :wink: Ich möchte das die Änderung sofort eintritt und ich nicht erst warten muss bis die aktuelle Zeit durchgelaufen ist. Da dachte ich es wäre praktisch wenn die loop Funktion einfach neu startet bzw. so etwas wie GOTO verwendet wird.

Gibts da simple Lösungen für das Problem?

#define LED0 P1_0
#define LED6 P1_6
#define LED4 P1_4
#define LED5 P1_5

const int buttonPin = P1_3; //Standard value is HIGH
int buttonState = 0; 
int blink = 0;
int delaytime = 10000;

void setup()
{    
  pinMode(LED0, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  
  digitalWrite(LED0, LOW);
  digitalWrite(LED4, LOW);
  digitalWrite(LED5, LOW);
  digitalWrite(LED6, LOW);
  
  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(buttonPin, cancel, FALLING); // Interrupt is fired whenever button is pressed
}

void loop()
{
  if(blink == 0) //0 = ON, 1 = OFF
  {
      LowToHigh();
  } 
  else
  {
    digitalWrite(LED0, LOW);
    digitalWrite(LED4, LOW);
    digitalWrite(LED5, LOW);
    digitalWrite(LED6, LOW);
  } 
}

void LowToHigh()
{   
      digitalWrite(LED0, HIGH);
      delay(delaytime); 
 
      digitalWrite(LED0, LOW); 
      digitalWrite(LED4, HIGH); 
      delay(delaytime);
      
      digitalWrite(LED4, LOW);
      digitalWrite(LED5, HIGH);
      delay(delaytime);
      
      digitalWrite(LED5, LOW);
      digitalWrite(LED6, HIGH);
      delay(delaytime);
      
      digitalWrite(LED6, LOW);
}

void cancel()
{
  if(blink == 0)
  {
    blink = 1;
    delaytime = 200;
  }
  else
  {
    blink = 0;
    delaytime = 10000;
  }
}

Finger weg vom goto. Des weiteren solltest du lernen, für solche Zeiten kein delay zu nutzten. Für kurzes Tasterentprellen (20 - 50ms) manchmal ganz okay. Aber für solche Sachen wie in deinem Beispiel nicht. -> blinkWithoutDelay

Dann brauchst du auch keine Interrupts mehr.

Variablen die innerhalb und außerhalb von ISRs verwendet werden müssen als "volatile" deklariert werden! Sonst kann der Compiler nicht wissen wie diese aufgerufen werden und optimiert sie eventuell weg. Außerdem werden sie dadurch immer neu aus dem RAM ausgelesen und nicht u.U. aus Registern, wodurch sichergestellt wird dass der Zustand konsistent ist.

http://arduino.cc/en/Reference/Volatile

Ansonsten sind Interrupts hier keine gute Wahl. Der Controller ist schnell genug, dass man das durch ständiges abfragen erledigen kann. In deinem Fall willst du wahrscheinlich Interrupts verwenden um während des Delays noch den Zustand ändern zu können. Aber da verwendet man besser millis(). Dann blockiert das Programm nicht und man kann mehrere Dinge quasi-gleichzeitig tun.

sschultewolter:
Finger weg vom goto. Des weiteren solltest du lernen, für solche Zeiten kein delay zu nutzten. Für kurzes Tasterentprellen (20 - 50ms) manchmal ganz okay. Aber für solche Sachen wie in deinem Beispiel nicht. -> blinkWithoutDelay

Dann brauchst du auch keine Interrupts mehr.

Wenn man kein delay für blinken benutzen soll, warum wird das immer in den ganzen Tutorials gezeigt? ^^

Weil blinken das erste Programm ist, was man mit dem Arduino meist realisiert. Und was passiert, wenn man delays nutzt, hast du doch gemerkt. delay lässt den Controller an der Stelle im Code einfach nur doof warten.

Tutorials dienen nicht zwingend dazu, den Nutzer die gute Programmiertechnik beizubringen. Nur Tutorials ist auch nicht die Lösung. Sinnvoller wären neben irgendwelchen Online Tutorials mindestens ein C oder Arduino-C Buch. (z.B. Kochbuch aus dem OReiley Verlag)

Alles klar. Da werd ich mir das oben genannte mal ansehen und dann melde ich mich wieder. Vielen Dank erst einmal :slight_smile:

Habe soeben das Beispiel mal ausporbiert, aber es macht doch keinen Unterschied wie ich das löse. Außer vllt. das es sinnvoller ist diese Methode zu nutzen. Warten muss ich trotzdem bis die LED einmal durch ist und der neue Wert bei der nächsten Ausführung greift. Wenn der interval auf 1000000 kann ich zwar die variablen ändern, leider geht die LED deshalb trotzdem nicht schneller aus.

Oder peil ich irgendetwas nicht?

Neuer Sketch?

Irgendwas machst du falsch.

Also in dem ersten Bereich wird doch die Wartezeit berechnet oder nicht?

Angenommen die LED steht für 10 Minuten auf HIGH (variable entsprechend groß), wie unterbreche ich das denn deiner Meinung nach damit sie sofort ausgeht bzw. den neuen variablen Wert sofort annimmt?

if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   //Wartebereich
    
    
    
    //LED an / aus nach dem Wartebereich
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
      
    digitalWrite(ledPin, ledState);
    
  }

peak als einmaliger Impuls

if(currentMillis - previousMillis > interval || peak == 1)
{
/...
}

Ich habs jetzt hinbekommen, allerdings etwas anders.

int peak = 0;
int blink[] = {200, 500, 10000}; 

void loop()
{
  unsigned long currentMillis = millis();
  
  buttonState = digitalRead(buttonPin);

  if(buttonState == LOW)
  {
    interval = blink[peak];
    peak++;
    delay(300);
    if(peak > 2)
    {
      peak = 0;  
    }
  }
  
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
      
    digitalWrite(ledPin, ledState); 
  }
}

Allerdings habe ich da wieder ein delay drin, aber dies nutze ich nur für die Buttonabfrage falls man zulange drückt und da das Array zu weit durchlaufen wird. Hoffe das ist ok?

Wird besser.

Mit dem Button solltest du das anders einlesen

In diesem Teil

if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }

könntest du die VariablePushCounter nutzen.

Dazu dann noch eine kleine Abfrage

static bool last_pushcount;
if(buttonPushCounter != last_pushcount)
{
last_pushcount = buttonPushCount;
peak = 1;
}
else peak = 0;

Vielen Dank! Funktioniert wie gewünscht und ohne delay :slight_smile: