Laufende Aktion im loop beenden

Hallo guten Abend zusammen,

anhand eines erneuten Tastendrucks soll die laufende Ausführung beendet und die Schleife verlassen werden.

Anhand von anderen Beiträgen hier habe ich eigentlich gedacht die Lösung gefunden zu haben, aber leider funktioniert es nicht.

Im Grunde gibt bereits die Verify/Upload Funktion in der Arduino IDE schon einen Fehler aus, dieser lautet:

exit status 1
Compilation error: 'digitalPinToInterrupt' was not declared in this scope

Bei dem Code handelt es sich um das Beispiel aus der Dokumentation zu attachInterrupt()

const byte ledPin = 1;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  state = !state;
}

Die nicht empfohlene Variante nur mit attachInterrupt(interruptPin, blink, CHANGE) gibt zwar keinen Fehler mehr aus, scheint aber überhaupt nicht zu klappen, hier tut sich bei Tastendruck überhaupt nichts. Auch die Modis low, rising und falling machen keinen Unterschied.

Verwendet wird das Digispark Rev.3 (ATTiny85) und die Arduino IDE v2.3.2

Das eigentliche Ziel bezieht sich natürlich nicht auf den Beispielcode oben, sondern auf folgendes Muster gekürzt mit Beispielroutinen.

Per Taster sollen die Schleifen durchgesprungen werden. Während eine Case-Schleife läuft, soll mittels erneutem drücken der laufende Code beendet werden. Das Problem ist dass erst nachdem der Fade abgeschlossen ist überhaupt ein erneutes drücken wahrgenommen wird und nicht schon während die Funktion noch läuft.

int buttonPin   = 2; // PB2
int led_red     = 0; // PB0
int led_green   = 1; // PB1 (pb1 also builtin_led)
int led_blue    = 4; // PB4

int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;    // previous state of the button

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(led_red, OUTPUT);
  pinMode(led_green, OUTPUT);
  pinMode(led_blue, OUTPUT);
}

void loop() {

  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {

    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      
      led_off_all();
      blink(led_green, buttonPushCounter);

      switch (buttonPushCounter) {
        case 1:
          fadein(led_red);
          break;
        case 2:
          fadein(led_green);
          break;
        case 3:
          fadein(led_blue);
          break;
        default:
          buttonPushCounter = 0;
          break;
      }

    } 
    delay(50);
  }

  lastButtonState = buttonState;

}

void blink(int LEDNAME, int amount) {
  for (int i = 1; i <= amount; i++) {
    digitalWrite(LEDNAME, HIGH);
    delay(100);
    digitalWrite(LEDNAME, LOW);
    delay(100);
  }
}

void fadein(int PIN) {
  for (int brightness = 0; brightness <= 255; brightness += 5) {
    analogWrite(PIN, brightness);
    delay(30);
  }
}
...

Gibt es noch eine andere Möglichkeit zeitgleich abzufragen ob der Taster erneut gedrückt wurde während noch eine Routine läuft? oder ist hier der Interrupt schon genau das richtige und das Einzige?

Besten Dank im Voraus für jegliche Hilfe

Für etwas mechanisches ist ein Interrupt immer eine schlechte Wahl.

Dein Problem sind deine blockierenden For-Schleifen. Wenn du diese Abläufe nicht blockierend umbaust, kannst du jederzeit auf Tastendrücke reagieren.

Schau dir mal „Blink without delay“ an.

Und noch was syntaktisches: Es gibt keine case Schleife. Es gibt eine Case Anweisung und eine for oder while Schleife.

Bei mir nicht!

Der Sketch verwendet 1028 Bytes (3%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 14 Bytes (0%) des dynamischen Speichers, 2034 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Verstümmelt, bis zur untestbarkeit.

E:\Programme\arduino\portable\sketchbook\sketch_feb26h\sketch_feb26h.ino: In function 'void loop()':
sketch_feb26h:30:7: error: 'led_off_all' was not declared in this scope
   30 |       led_off_all();
      |       ^~~~~~~~~~~
E:\Programme\arduino\portable\sketchbook\sketch_feb26h\sketch_feb26h.ino: At global scope:
sketch_feb26h:71:1: error: expected unqualified-id before '...' token
   71 | ...
      | ^~~
exit status 1
'led_off_all' was not declared in this scope

Du hast jetzt nicht gegen den ATTiny85 compiliert oder?

Oh, du hast Wahr!

attachInterrupt(0, blink, CHANGE);

Hier ist code für den INT0:

Man müsste auch was mit PCINTn basteln können

Mag so sein...
Eine Test Hardware habe ich leider gerade nicht da.

Das war falsch.

Wer will findet Wege!
(und auch mal einen Digispark)

Getestet:
Natürlich funktioniert mein Vorschlag aus #6 mit PB2 als Input

PS: an @Rintin
Die Aussage in #3 in diesem Thread ATtiny85 Interrupt code - #3 by santoshgurral ist definitiv false

Hallo,
ich denke Du verfolgst die falsche Strategie. Sowas macht man mit millis()
Du solltest Dir auch über die Begriffe "Schleife" und "Verzweigung" im Klaren sein.
Ich habe vor einer Weile mal etwas zusammen geschrieben. Das dort verwendete Beispiel kommt Deinem ziemlich nahe.

oder auch hier

von Delay bis zur Methode

Heinz

Danke für den Schpps in die richtige Richtung und schade dass es nicht so simpel sein kann :slight_smile:

Danke fürs testen, der Code war natürlich nicht vollständig mit allen Funktionen.
Ich kompiliere gegen ein Preset welches von Stigistump für dieses Board bereitgestellt wird.

Deine Idee mit dem Pin0 (INT0) funktioniert auf dem Pin PB2 :+1:

Das ist perfekt für den Einstieg, vielen Dank :+1:

Goole sagt dazu:
image

Ich weiß!

Und ich soll den reparieren um den testen zu können?
Sowas tue ich nicht!
Wende mich eher genervt ab.

Wenn @Rintin nicht den berechtigten Einwand gebracht hätte, wäre ich dauerhaft stumm geblieben.

Digistump war gemeint, habe ich falsch im Kopf gehabt (https://raw.githubusercontent.com/digistump/arduino-boards-index/master/package_digistump_index.json).

Eine Erklärung zum INT0 wäre hilfreicher gewesen als sich darüber zu beschweren dass der code mit ... endet weil er nur den Zweck veranschaulichen sollte dass eine Case-Anweisung vorzeitig beendet werden soll. Also danke für den Tipp

Wenn du die Sprache (die du verwendest) lernen/kennen würdest, dann wüsstest du, dass ein Interrupt kein case Statement beenden kann!
Dass können nur break, return, goto und abort()

Ich weiß nicht ob dir das schmeckt:
Programmieren bedeutet ein Mindestmaß an Sorgfalt und Disziplin.

Ich verstehe: Wie immer ist der Bote schuld an allem.

Du, alles gut - die Kritik nehme ich gerne an schließlich mach ich das nicht beruflich.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.