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?
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:
du rollst die Schleife aus. Klarer: Weg mit der Schleife
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.
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
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.
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
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.
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 übersetzen lassen.