Angeregt durch ein anderes Thema und @noiasca "Also das Aufleuchten eines kleinen Punktes als Funke von der Zündkerze und dann das verzögerte Ausbreiten der Flamme im Brennraum." wollte ich das mal ausprobieren, wie es aussieht. Die weißen LED von RGBW machen sich als Zündfunke ganz gut, finde ich. Aber auch wenn das meine Motivation war, so geht es mir in diesem Thema um "richtiges" Programmieren.
Mangels Hardware habe ich jedem Zylinder nur einen Lichtpunkt (nach Adafruit "Pixel" genannt) zugeordnet. Die einzelnen Schritte:
- Blau von 0 nach 255 faden
- weißer Blitz
- Rot von 255 nach 0 faden
- kurze Pause alle Farben aus
Das Programm tut, was es soll.
Frage 1: Hat das Programm Fehler?
Frage 2: Ich habe das Gefühl, irgendwas zu kompliziert gemacht zu haben. Ist das so?
#include <Adafruit_NeoPixel.h>
#define NEOPIN 6
#define ANZAHLDERPIXEL 7 // hier müßte 42 stehen
#define PIXELPROZYL 1 // hier müßte 7 stehen
#define BRIGHTNESS 255
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
Adafruit_NeoPixel strip = Adafruit_NeoPixel(ANZAHLDERPIXEL, NEOPIN, NEO_GRBW + NEO_KHZ800);
const unsigned long intervalle[] = {10, 50, 10, 500};
unsigned long aktMillis;
void setup() {
strip.setBrightness(BRIGHTNESS);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
struct Fade // Für jede Farbe wird ein Startwert (0-255, 0=dunkel, 255=hell) angegeben, der mit dem Fadewert jedes Intervall (in ms) verändert wird.
// start() setzt die Startwerte, run() macht das Faden.
// Der Rückgabewert ist true, wenn alle Farben so nahe an 0 oder 255 sind, daß sie nicht mehr verändert werden können.
{
Fade(byte rot, int8_t rotfade, byte gruen, int8_t gruenfade, byte blau, int8_t blaufade, byte weiss, int8_t weissfade, uint32_t intervall):
rot(rot), rotfade(rotfade), gruen(gruen), gruenfade(gruenfade), blau(blau), blaufade(blaufade), weiss(weiss), weissfade(weissfade), intervall(intervall), ablaufMillis(0) {}
void start(byte ersterpixel)
{
ep = ersterpixel;
r = rot;
rf = rotfade;
g = gruen;
gf = gruenfade;
b = blau;
bf = blaufade;
w = weiss;
wf = weissfade;
i = intervall;
ablaufMillis = aktMillis;
for (byte pixel = ep; pixel < ep + PIXELPROZYL; pixel++)
{
strip.setPixelColor(pixel, strip.Color(r, g, b, w));
}
strip.show();
}
bool run()
{
bool rueckgabe = false;
if (aktMillis - ablaufMillis >= i)
{
ablaufMillis = aktMillis;
if (r >= -rf) r += rf;
if (g >= -gf) g += gf;
if (b >= -bf) b += bf;
if (w >= -wf) w += wf;
for (byte pixel = ep; pixel < ep + PIXELPROZYL; pixel++)
{
strip.setPixelColor(pixel, strip.Color(r, g, b, w));
}
strip.show();
if ((r <= -rf || r > 255 - rf) && (g <= -gf || g > 255 - gf) && (b <= -bf || b > 255 - bf) && (w <= -wf || w > 255 - wf))
{
rueckgabe = true;
}
}
return rueckgabe;
}
byte rot; int8_t rotfade; byte gruen; int8_t gruenfade; byte blau; int8_t blaufade; byte weiss; int8_t weissfade; uint32_t intervall;
byte ep;
byte r;
int8_t rf;
byte g;
int8_t gf;
byte b;
int8_t bf;
byte w;
int8_t wf;
byte i;
unsigned long ablaufMillis;
};
Fade fade[]
{ // rot, rotfade, gruen, gruenfade, blau, blaufade, weiss, weissfade, intervall
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
{0, 0, 0, 0, 0, 1, 0, 0, intervalle[0]},
{255, -1, 0, 0, 0, 0, 0, 0, intervalle[2]},
};
struct Zyl // Durchläuft die Schritte einer Schrittkette, wobei jeder Schritt dem Takt eines 4-Takt-Otto-Motors entsprechen könnte,
// was hier aber eher künstlerisch zu betrachten ist.
// startphase: Bei welchem Schritt (Takt) die Animation beginnt.
// startpixel: Erstes Pixel für den Zylinder. Bei 42 Pixeln 0, 7, 14 ...
// fadetyp: Notwendig, damit sich die Fadephasen nicht in die Quere kommen.
{
Zyl(const byte startphase, const byte startpixel, const byte fadetyp): schritt(startphase), startpixel(startpixel), fadetyp(fadetyp), einmal(true), ablaufMillis(0) {}
void run()
{
switch (schritt) { // schritt würde dem Takt eines 4-Takt-Otto-Motors entsprechen.
case 0: // Blau von 0 nach 255 faden
if (einmal) {
einmal = false;
fade[fadetyp].start(startpixel);
} else {
if (fade[fadetyp].run()) {
schritt++;
einmal = true;
}
break;
case 1: // zusätzlich zu Blau ein weißer Blitz
if (einmal) {
einmal = false;
for (byte pixel = startpixel; pixel < startpixel + PIXELPROZYL; pixel++) {
strip.setPixelColor(pixel, strip.Color(0, 0, 255, 255));
}
strip.show();
ablaufMillis = aktMillis;
}
if (aktMillis - ablaufMillis >= intervalle[schritt]) {
schritt++;
einmal = true;
}
break;
case 2: // Rot von 255 nach 0 faden
if (einmal) {
einmal = false;
fade[fadetyp+1].start(startpixel);
} else {
if (fade[fadetyp+1].run()) {
schritt++;
einmal = true;
}
}
break;
case 3: // kurz alle Farben aus
if (einmal) {
einmal = false;
for (byte pixel = startpixel; pixel < startpixel + PIXELPROZYL; pixel++) {
strip.setPixelColor(pixel, strip.Color(0, 0, 0, 0));
}
strip.show();
ablaufMillis = aktMillis;
}
if (aktMillis - ablaufMillis >= intervalle[schritt]) {
schritt++;
einmal = true;
}
break;
default:
schritt = 0;
break;
}
}
}
byte schritt;
const byte startpixel;
const byte fadetyp;
bool einmal;
unsigned long ablaufMillis;
};
Zyl zylinder[]
{ // startphase, startpixel, fadetyp
{0, 1, 0},
{2, 2, 2},
{3, 3, 4},
{0, 4, 6},
{2, 5, 8},
{3, 6, 10}
};
void loop() {
aktMillis = millis();
for (Zyl &z : zylinder) z.run();
}
PS: Was ich hier programmiert habe, beruht unverkennbar auf dem süßen Honig fleißiger Bienchen und anderer freundlicher Menschen.
EDIT 20180727 10:45: Kommentare ergänzt.