Interrupt über serielle Schnittstelle

Hallo!

Ich brauche mal euer Schwarmwissen.

Ich hab mir einen Neopixel Ring besorgt und möchte diesen in meiner Fotobox verbauen.

Wenn die Fotobox in Bereitschaft ist, soll eine Regenbogenanimation am Ring laufen.
Sobald über die serielle Schnittstelle ein bestimmter Befehl kommt, soll diese Animation sofort abgebrochen werden, und eine (je nach Befehl) andere Animation aufgerufen werden. Danach soll wider die Regenbogenanimation laufen.

Wenn ich jetzt aber über die serielle Schnittstelle einen Befehl sende, läuft die Regenbogenanimation aber noch bis zum Schluss durch und dann wird erst die andere Animation aufgerufen.

Hier mal der Code:

#include <Adafruit_NeoPixel.h>

#define PIN 2
#define PIXELRINGSIZE 24

Adafruit_NeoPixel PixelRing = Adafruit_NeoPixel(PIXELRINGSIZE, PIN, NEO_GRB + NEO_KHZ800);
unsigned long previousMillis = 0;
int bufferCount;    // Anzahl der eingelesenen Zeichen
char buffer[80];    // Serial Input-Buffer

void setup() {
  Serial.begin(9600);
  PixelRing.begin();
  PixelRing.setBrightness(25);  // Lower brightness and save eyeballs!
  PixelRing.show(); // Initialize all pixels to 'off'
}


void loop() {
  rainbowCycle(15);
}

void serialEvent(){
  char ch = Serial.read();
  buffer[bufferCount] = ch;
  bufferCount++;
  if(ch == 13){
    evalSerialData();
  }
}


void evalSerialData()
{
  Serial.println(buffer);
  if ((buffer[0] == '>') && (buffer[bufferCount - 2] == '<')) {
    switch (buffer[1]) {
      case 'b':
        // blinktime = (buffer[2] - 48) * 1000 + (buffer[3] - 48) * 100 + (buffer[4] - 48) * 10 + (buffer[5] - 48);
        colorWipe(PixelRing.Color(64, 0, 0), 100); // Red
        colorWipe(PixelRing.Color(0,0,0), 25); // Black
        break;
      case 'w':
        break;
    }
  }
  bufferCount = 0;
}


// delay funktion
void delayTime(uint8_t wait) {
   previousMillis = millis();
   while (millis() - previousMillis <= wait) {}
}


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<PixelRing.numPixels(); i++) {
      PixelRing.setPixelColor(i, c);
      PixelRing.show();
      delayTime(wait);
  }
}


// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< PixelRing.numPixels(); i++) {
      PixelRing.setPixelColor(i, Wheel(((i * 256 / PixelRing.numPixels()) + j) & 255));
    }
    PixelRing.show();
    delayTime(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
   return PixelRing.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return PixelRing.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return PixelRing.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

Wo liegt hier mein Denkfehler?
Warum wird bei Interrupt im loop rainbowCycle nicht sofort abgebrochen und colorWipe aufgerufen?

Danke schon mal für eure Hilfe.

Weil die Schleife noch bis zu ihrem Ende durchläuft.
Das machen Schleifen so.
Immer.
Dafür wurden sie erfunden.

Zwei Möglichkeiten, du hast:

  1. du rollst die Schleife aus. Klarer: Weg mit der Schleife
  2. du baust da einen Seitenausstieg ein.

Wobei deine Wortwahl etwas verwirrend ist...
z.B. serialEvent() ist kein Interrupt
Von einem Interrupt ist in deinem Programm nichts zu sehen.
serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.

Hy! Danke für die schnelle Antwort

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.

Das war mir nicht klar. in anderen Beiträgen wurde das so beschrieben, als wäre das ein Interrupt.

Wie kann ich dann mittels serialEvent() einen Interrupt auslösen?

Hi

Die delayTime()-Funktion erscheint mir äußerst sinnlos.
Woher hast Du Die und was soll Diese bewirken?

MfG

ich weiß, dass man es auch mit delay(time) lösen könnte. aber anscheinend gibts da dann auch probleme mit interrupts.

in anderen Beiträgen wurde das so beschrieben, als wäre das ein Interrupt.

Tja...

Selber kundig machen, macht selber schlau.

Wie kann ich dann mittels serialEvent() einen Interrupt auslösen?

Gar nicht!
Das wäre sogar eine echt dumme Idee.

Wie schon gesagt, ich kann es auch gerne ein paar mal wiederholen...

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.
Es ist also unmöglich, dass serialEvent() innerhalb einer Schleife zum tragen kommt.

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.
Es ist also unmöglich, dass serialEvent() innerhalb einer Schleife zum tragen kommt.

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.
Es ist also unmöglich, dass serialEvent() innerhalb einer Schleife zum tragen kommt.

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.
Es ist also unmöglich, dass serialEvent() innerhalb einer Schleife zum tragen kommt.

serialEvent() kommt erst nach Ablauf aller Schleifen ins Spiel.
Es ist also unmöglich, dass serialEvent() innerhalb einer Schleife zum tragen kommt.

ich weiß, dass man es auch mit delay(time) lösen könnte. aber anscheinend gibts da dann auch probleme mit interrupts.

Du hast eine rege Fantasie....

Natürlich funktionieren Interrupts perfekt, auch wenn gerade ein delay() aktiv ist.
Das ist beweisbar

Auch benötigt delay() einen funktionierenden Timerinterrupt
Damit ist es in sich selber bewiesen.

Sei es wie es sei.

Sieht keiner eine Möglichkeit, wie ich mein Problem lösen kann?

Das wurde auch schon gesagt. Du musst die Schleife auflösen. z.B. diese innerhalb von loop() mit if-Abfragen nachbilden. Oder du setzt ein Flag wenn serielle Daten ankommen, fragst dass in der Schleife ab und beendest diese mit break

Danke!

hat funktioniert

Serial.available() hies das Zauberwort. jetzt funktionierts so, wie ich es haben will - auch mit klassischem delay() :smiley:

for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    if(Serial.available() > 0) {
      break;
    }
    for(i=0; i< PixelRing.numPixels(); i++) {
      PixelRing.setPixelColor(i, Wheel(((i * 256 / PixelRing.numPixels()) + j) & 255));
    }
    PixelRing.show();
    delay(wait);
  }

Hi

Je nachdem, wie groß 'wait' ist, wird erst verspätet auf die ankommenden Daten reagiert.
Besser wäre Es hier, das delay() nachzubilden (while-Schleife, wie Du Das zuvor schon gemacht hast) und DORT das Serial-Event abzufragen.
Allerdings kannst Du Dort nur ein Flag setzen und musst damit auch schon die Schleife abbrechen (break; ).
Unterhalb der delay-While-Schleife musst Du das Flag abfragen um die FOR abzubrechen (ebenfalls break; ).
Wenn break als Argument eine Ebenenanzahl entgegen nimmt, kannst Du Dir den Umweg über das separate Flag sparen und via break 2; (oder ähnlich) die FOR-Schleide und die WHILE-Schleife gemeinsam beenden.

MfG

@postmaster-ino: Hast Du für die Behauptung "break 2" auch eine Quelle?

Gruß Tommy

Nimm goto // duck und weg

ElEspanol:
Nimm goto // duck und weg

Das ist in diesem Fall (um aus verschachtelten for-Schleifen zu entkommen) eine legitime Verwendung

Aus gibt auch Alternativen. z.B. die Schleifen-Bedingung per Hand ändern, oder ein Flag setzten und in der Schleife zusätzlich abfragen, aber die sind nicht gut lesbar

Tommy56:
Hast Du für die Behauptung "break 2" auch eine Quelle?

Hier ist eine Antwort auf deine Respektlosigkeit.

Serenifly:
Das ist in diesem Fall (um aus verschachtelten for-Schleifen zu entkommen) eine legitime Verwendung

Sehe ich auch so!
Aber ich bin in solchen Dingen sowieso recht schmerzfrei/schamlos.

Hi

Tommy56:
@postmaster-ino: Hast Du für die Behauptung "break 2" auch eine Quelle?

Gruß Tommy

... done ... siehe #15
(wobei mir nicht mehr bewusst war, daß Das auch in PHP ging, hatte eher an einen Basic-Dialekt gedacht)

combie:
Hier ist eine Antwort auf deine Respektlosigkeit.

Soweit ich weiß befassen wir uns hier aber mit C++ und nicht mit PHP. Also würde mich eine C++-Quelle interessieren.
Seit wann ist es respektlos, nach einem Beleg für eine Aussage zu fragen? Schließlich sind wir doch hier, um etwas zu lernen und "break 2" ist mir in C/C++ noch nicht begegnet.

Gruß Tommy

Hi

postmaster-ino:
...
Wenn break als Argument eine Ebenenanzahl entgegen nimmt, kannst Du Dir den Umweg über das separate Flag sparen und via break 2; (oder ähnlich) die FOR-Schleide und die WHILE-Schleife gemeinsam beenden.

MfG

Auf C++ wäre Das wohl ungefähr so:

if (break hat zusätzliches Argument){
   kannst Du Dir das externe Break schenken;
}else{
   wirst Du Da nicht drum herum kommen;
}

Wer möchte, darf auch gerne das 'Wenn' im Zitag durch Google in ... z.B. Englisch :slight_smile: übersetzen lassen.

MfG

Was soll diese sinnlose Antwort bedeuten?

Hast Du nun einen Beleg, dass es in C++ möglich ist oder nicht? Das würde mich echt interessieren, denn ich habe nichts dazu gefunden.

Die Pseudo-Antwort von combie aus PHP war ja wohl eher ein (schlechter) Witz.

Gruß Tommy