Benutzer-Werkzeuge

Webseiten-Werkzeuge


silentbase_neopixel:programmversion_0.9

NeoPixel-Beleuchtung für SilentBase 800 Programmversion 0.9

Der Glitzereffekt in Programmversion 0.7 war für mich bereits eine Herausforderung. (Der Feuereffekt Nr. 2 (Programmmodus 5) aus Programmversion 0.8 ist ein Kind des Zufalls.) Den bekannten Fire 2012-Effekt aus der FastLED-Bibliothek nachzubauen war eine Herausforderung für mich. Sehr hilfreich war der Code von Tweaking4all, der allerdings fehlerbehaftet ist. Aber letzendlich habe ich es geschafft.

Eine gute Beschreibung der Auswirkung der Parameter „Cooling“ und „Sparkling“ (inklusive Videos) gibt es hier.

Hilfreiche Links:

ToDos:

  • Bei dem Fire2012-Effekt müsste die Temperatur eines Pixels die Bewegungsgeschwindigkeit beeinflussen.
  • Die Variable „buttonpressed“ könnte auch als boolean definiert werden.
  • Das array „byte invert“ könnte man sich mit dem Befehl map sparen.

Der Sketch enthält Code von Baldengineer, Scynd, http://www.walltech.cc und http://www.tweaking4all.com.

// Dieser Sketch enthält Code von
// Baldengineer (https://www.baldengineer.com),
// Scynd (http://www.scynd.de) und
// Hans Luijten (http://www.tweaking4all.com).


// Bibliotheken einbinden
#include <EEPROM.h>
#include <ResponsiveAnalogRead.h>
#include <Adafruit_NeoPixel.h>


// Definiert die Pins
#define buttonPin 7           // Taster
#define loadPin A0            // analoge Spannungsmessung
#define neoPin1 11            // Neopixel-Strip rechte Seite
#define neoPin2 12            // Neopixel-Strip linke Seite


// Definiert eine Adresse im EEPROM
int addr = 0;                 // An dieser Adresse wird später der ausgewählte Programmmodus gespeichert


// Definiert ein ResponsiveAnalogRead Objekt
ResponsiveAnalogRead rload(loadPin, true);


// Definiert die Variablen
int numPixels = 64;           // Anzahl der NeoPixel
int load;                     // Variable repäsentiert später die Differenz zwischen minimaler und maximaler Netzteillast in Prozent

int buttonstate = HIGH;       // aktuelles Signal vom Tasterpin
int buttonpressed = 0;        // abfragen ob Taster gedrückt war
int debouncetime = 50;        // Zeit für Entprellung ggf. anpassen

float rloadmin = 350;         // Messwert am loadPin bei minimaler Netzteillast (muss abgelesen werden)
float rloadmax = 650;         // Messwert am loadPin bei maximaler Netzteillast (muss abgelesen werden)

float x = 0;                  // Zählwert für verschiedene Beleuchtungseffekte 
boolean sw1 = true;           // Schaltvariable für verschiedene Beleuchtungseffekte
boolean sw2 = true;           // Schaltvariable für verschiedene Beleuchtungseffekte
int i;                        // Zählwert für verschiedene Beleuchtungseffekte
int j;                        // Zählwert für verschiedene Beleuchtungseffekte
int k;                        // Zählwert für verschiedene Beleuchtungseffekte
int l;                        // Zählwert für verschiedene Beleuchtungseffekte

int cooling;                  // Variable für Beleuchtungseffekt Flammen
int sparkling;                // Variable für Beleuchtungseffekt Flammen
int cooldown;
static byte heat[64];         // Ein Array für die Temperaturwerte

byte invert[] = {63, 62, 61, 60, 59, 58, 57, 56, 55, 54,  // Ein Array zur Umrechnung
  53, 52, 51, 50, 49, 48, 47, 46, 45, 44,
  43, 42, 41, 40, 39, 38, 37, 36, 35, 34,
  33, 32, 31, 30, 29, 28, 27, 26, 25, 24,
  23, 22, 21, 20, 19, 18, 17, 16, 15, 14,
  13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
  };

byte programmode = 0;         // Programmmodus


// Definiert die NeoPixel-Strips
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(numPixels, neoPin1, NEO_GRBW + NEO_KHZ800);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(numPixels, neoPin2, NEO_GRBW + NEO_KHZ800);


// Definiert die globalen RGBW-Werte
byte r = 0;
byte g = 0;
byte b = 0;
byte w = 0;


// Definiert die Tracking-Variablen für die IF-Abfragen
unsigned long previousMillisCalcLoad = 0;
unsigned long previousMillisFPS20 = 0;
unsigned long previousMillisFPS60 = 0;
unsigned long previousMillisSerialPrint = 0;
unsigned long buttontime = 0;
unsigned long sparkle1on = 0;
unsigned long sparkle1off = 0;
unsigned long sparkle1ondelay = 100;
unsigned long sparkle1offdelay = 500;
unsigned long sparkle2on = 0;
unsigned long sparkle2off = 0;
unsigned long sparkle2ondelay = 100;
unsigned long sparkle2offdelay = 500;


// Definiert die Intervalle für die IF-Abfragen
int intervalCalcLoad = 500;      // Delay für Berechnung der Last
int intervalFPS20 = 50;          // Delay für Effekte mit 20 FPS
int intervalFPS60 = 16;          // Delay für Effekte mit 60 FPS
int intervalSerialPrint = 1000;  // Delay für serielle Ausgabe


void setup() {
  // Initialisiere den Button-Pin
  pinMode(buttonPin, INPUT_PULLUP);

  // Initialisiere die NeoPixel-Pins
  pinMode(neoPin1, OUTPUT);
  pinMode(neoPin2, OUTPUT);

  // Initialisiere den analogen Pin 
  pinMode(loadPin, INPUT);

  // Initialisiere die NeoPixel-Strips
  strip1.begin(); // Initialisiert das Neopixel
  strip1.show();  // Macht das NeoPixel sichtbar
  //strip1.clear(); // Macht das NeoPixel aus
  
  strip2.begin(); // Initialisiert das Neopixel
  strip2.show();  // Macht das NeoPixel sichtbar
  //strip2.clear(); // Macht das NeoPixel aus

  // Lese den abgespeicherten Wert für den Programmmodus aus dem EEPROM
  programmode = EEPROM.read(addr);

  // Initialisiere die serialle Schnittstelle
  Serial.begin(57600);

delay (2000);
}



void loop() {
// Lesen und entprellen des Tasters
  buttonstate = digitalRead(buttonPin);
 
  // Wenn der Taster gedrückt ist...
  if (buttonstate == LOW)
  {
    buttontime = millis();                      // aktualisiere tasterZeit
    buttonpressed = 1;                          // speichert, dass Taster gedrückt wurde
  }
 
  // Wenn die gewählte entprellZeit vergangen ist und der Taster gedrückt war...
  if ((millis() - buttontime > debouncetime) && buttonpressed == 1)
    {
      buttonpressed = 0;                        // setzt gedrückten Taster zurück
      programmode++;                            // Programmmodus wird um +1 erhöht
      EEPROM.write(addr, programmode);          // Schreibt den Programmmodus ins EEPROM
      r = 0;                                    // setzt den globalen Farbwert zurück
      g = 0;                                    // setzt den globalen Farbwert zurück
      b = 0;                                    // setzt den globalen Farbwert zurück
      w = 0;                                    // setzt den globalen Farbwert zurück
      strip1.clear();                           // setzt die NeoPixel zurück
      strip2.clear();                           // setzt die NeoPixel zurück
    }


// Aktuelle Zeit abfragen
  unsigned long currentMillis = millis();


// Messen der Spannung am analogen Eingangspin loadPin (A0) und Berechnen einiger Variablen zur Beeinflussung verschiedener Effekte
  if ((unsigned long)(currentMillis - previousMillisCalcLoad) >= intervalCalcLoad) {
  
     // Auslesen des analogen Eingangs (Last Netzteil)
     rload.update();

     // Berechnung der Netzteillast in Prozent: Bei ruhendem Desktop soll der Wert 0 sein, bei maximaler Auslastung 100
     load = 100 - ((rloadmax - rload.getValue()) / (rloadmax - rloadmin)) * 100;

     // Berechnung von Cooling für den Effekt Fire 2012: Legt fest, wie stark die aufsteigenden Flammen abkühlen
     // Werte zwischen 20 und 100 sollen am hübschesten sein, ein guter Standard ist 50
     cooling = 100 - (load / 0.8);

     // Berechnung von Sparkling für den Effekt Fire2012: Legt fest, wie oft ein Funke auflohdert
     //Werte zwischen 50 und 200 sollen am hübschesten sein, ein guter Standard ist 120
     sparkling = 50 + (load * 1.5);
    
  //Speichere die aktuelle Zeit in die zughörige Variable
  previousMillisCalcLoad = currentMillis;
  }


// Steuerung der NeoPixel-Strips
  // Beleuchtungseffekt für Programmmodus 0 (Atmen rot)
  if (programmode == 0) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

     if(load < 10) {       // Variable soll für diesen Effekt nicht kleiner als 10 werden
        load = 10;
        }
        
      // Ansteuerung der NeoPixel-Strips
      x = x + (0.05 * (load/10));
      if (x >= 6.28) {
        x = 0;
      }
        // fade led mit x
        r = ((exp(sin(x)) - 0.36787944) * 108.492061351);
        
      for (int i = 0; i < numPixels; i++) {
        strip1.setPixelColor(i, r, g, b, w);
        strip2.setPixelColor(i, r, g, b, w);
      }
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }

  //Beleuchtungseffekt für Programmmodus 1 (Atmen weiß)
  else if (programmode == 1) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

     if(load < 10) {       // Variable soll für diesen Effekt nicht kleiner als 10 werden
        load = 10;
        }
        
      // Ansteuerung der NeoPixel-Strips
      x = x + (0.05 * (load/10));
      if (x >= 6.28) {
        x = 0;
      }
        // fade led mit x
        w = ((exp(sin(x)) - 0.36787944) * 108.492061351);
        
      for (int i = 0; i < numPixels; i++) {
        strip1.setPixelColor(i, r, g, b, w);
        strip2.setPixelColor(i, r, g, b, w);
      }
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }


  //Beleuchtungseffekt für Programmmodus 2 (Stabthermometer)
  else if (programmode == 2) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

      if(load >= numPixels) {       // Variable soll für diesen Effekt nicht größer als NeoPixel vorhanden
        load = 63;
        }
      // Weißer Bereich
      for (int i = 0; i < numPixels; i++) {
      strip1.setPixelColor(i, r, g, b, 127);
      strip2.setPixelColor(i, r, g, b, 127);
      }
      // Roter Bereich      
      for (int i = 63; i > (63 - load); i--) {
        strip1.setPixelColor(i, 127, g, b, w);
        strip2.setPixelColor(i, 127, g, b, w);
      }
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }


  //Beleuchtungseffekt für Programmmodus 3 (Stabthermometer mit Glitzer)
  else if (programmode == 3) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

      if(load >= numPixels) {       // Variable soll für diesen Effekt nicht größer als NeoPixel vorhanden
        load = 63;
        }
      // Blauer Bereich
      for (int i = 0; i < numPixels; i++) {
      strip1.setPixelColor(i, r, g, 127, w);
      strip2.setPixelColor(i, r, g, 127, w);
      }
      // Roter Bereich     
      for (int i = 63; i > (63 - load); i--) {
        strip1.setPixelColor(i, 127, g, b, w);
        strip2.setPixelColor(i, 127, g, b, w);
      }

      // Sparkle NeoPixel-Strip 1
      if(sw1)
        {
          strip1.setPixelColor(j, r, g, b, 255);
          if(millis() - sparkle1on >= sparkle1ondelay)
          {
          sparkle1offdelay = random (100, 1000);
          sparkle1off = millis();
          sw1 = !sw1;
          }
        }
        if(!sw1)
          {
          if(millis() - sparkle1off >= sparkle1offdelay)
              {
                j = random(0, (numPixels -1));
                sparkle1on = millis();
                sw1 = !sw1;       
              }
        } 
      // Sparkle NeoPixel-Strip 2
      if(sw2)
        {
          strip2.setPixelColor(k, r, g, b, 255);
          if(millis() - sparkle2on >= sparkle2ondelay)
          {
          sparkle2offdelay = random (100, 1000);
          sparkle2off = millis();
          sw2 = !sw2;
          }
        }
        if(!sw2)
          {
          if(millis() - sparkle2off >= sparkle2offdelay)
              {
                k = random(0, (numPixels - 1));
                sparkle2on = millis();
                sw2 = !sw2;       
              }
        } 
      // Sende die Daten an die Neopixel
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }


    //Beleuchtungseffekt für Programmmodus 4 (Feuer 1)
  else if (programmode == 4) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

      for (int i = 0; i < numPixels; i++) {
        int flicker = random (0, 150);
        int r = 255;
        int g = r-100;
        int b = 30;
        
        r = r - flicker;
        g = g - flicker;
        b = b - flicker;

        if(r < 0) r = 0;
        if(g < 0) g = 0;
        if(b < 0) b = 0;
        
      strip1.setPixelColor(i, r, g, b, 0);
      strip2.setPixelColor(i, r, g, b, 0);
      }
      // Sende die Daten an die Neopixel
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }


    //Beleuchtungseffekt für Programmmodus 5 (Feuer 2)
  else if (programmode == 5) {
    if ((unsigned long)(currentMillis - previousMillisFPS20) >= intervalFPS20) {

      if(load >= numPixels) {       // Variable soll für diesen Effekt nicht größer als NeiPoxel vorhanden
        load = 63;
        }
        int r = 255;
        int g = 130;
        int b = 30;
        int w = 63;

      for (int i = (numPixels -1); i > 0; i--) {
        int flicker = random (0, (42 - (load/2)));

        r = r - flicker;
        g = g - flicker;
        b = b - flicker;
        w = w - (flicker * 3);
        
        if(r < 0) r = 0;
        if(g < 0) g = 0;
        if(b < 0) b = 0;
        if(w < 0) w = 0;
        
      strip1.setPixelColor(i, r, g, b, w);
      strip2.setPixelColor(i, r, g, b, w);
      }
      // Sende die Daten an die Neopixel
      strip1.show();
      strip2.show();
   
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS20 = currentMillis;
    }
  }


    //Beleuchtungseffekt für Programmmodus 6 (Fire2012))
  else if (programmode == 6) {
    if ((unsigned long)(currentMillis - previousMillisFPS60) >= intervalFPS60) {

      // Step 1.  Cool down every cell a little
      for(int i = 0; i < numPixels; i++) {    
        cooldown = random(0, ((cooling * 10) / numPixels) + 2);
    
        if(cooldown > heat[i]) {
          heat[i] = 0;
            } else {
            heat[i] = heat[i] - cooldown;
            }
          }

      // Step 2.  Heat from each cell drifts 'up' and diffuses a little
      for(int k = numPixels - 1; k >= 2; k--) {
        heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
        }
    
    // Step 3.  Randomly ignite new 'sparks' near the bottom
      if(random(255) < sparkling) {
        l = random(7);
        heat[l] = heat[l] + random(160,255);
        //heat[l] = random(160,255);
        }

    // Step 4.  Convert heat to LED colors
      for(int j = numPixels -1; j >= 0; j--) {        
        // Scale 'heat' down from 0-255 to 0-191
        byte t192 = round((heat[j]  /255.0) * 191);
 
        // calculate ramp up from
        byte heatramp = t192 & 0x3F; // 0..63
        heatramp <<= 2; // scale up to 0..252

        // figure out which third of the spectrum we're in:
        if( t192 > 0x80) {                       // hottest
          strip1.setPixelColor(invert[j], 255, 255, heatramp, 0);
          strip2.setPixelColor(invert[j], 255, 255, heatramp, 0);
          } else if( t192 > 0x40 ) {             // middle
          strip1.setPixelColor(invert[j], 255, heatramp, 0, 0);
          strip2.setPixelColor(invert[j], 255, heatramp, 0, 0);
          } else {                               // coolest
          strip1.setPixelColor(invert[j], heatramp, 0, 0, 0);
          strip2.setPixelColor(invert[j], heatramp, 0, 0, 0);  
          }
        }
      strip1.show();
      strip2.show();
      
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisFPS60 = currentMillis;
    }
  }


  // Wenn der Programmodus auf einen höheren Wert sprngt, wird er zurück auf 0 gesetzt und beginnt von vorne
  else {
    programmode = 0;
  }


// Ausgabe an die serielle Schnittstelle
  if ((unsigned long)(currentMillis - previousMillisSerialPrint) >= intervalSerialPrint) {

     //Ausgabe der berechneten Netzteillast an die sereille Schnittstelle
     Serial.print("Last (berechnet): "); Serial.print(load); Serial.println(" %");
     Serial.print("Cooling: "); Serial.println(cooling);
     Serial.print("Sparkling: "); Serial.println(sparkling);
     //Ausgabe der Werte von ResponsiveAnalogRead
     Serial.print("Last (geglaettet): "); Serial.println(rload.getValue());
  
     // if the repsonsive value has change, print out 'changed'
     if(rload.hasChanged()) {
     Serial.println("\tchanged");
     }

     // Ausgabe Programmzähler
     Serial.print("Programm Nr.: "); Serial.println(programmode);

   //Speichere die aktuelle Zeit in die zughörige Variable
   previousMillisSerialPrint = currentMillis;
   }

}

Der Sketch verwendet 10.912 Bytes (33%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes. Globale Variablen verwenden 567 Bytes (27%) des dynamischen Speichers, 1.481 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Tags: #Arduino #NeoPixel

silentbase_neopixel/programmversion_0.9.txt · Zuletzt geändert: 18.05.2023 12:16 von 127.0.0.1