Code Aufräumen/Verbessern, Speicherplatz freigeben

lastprogramm brauchst nur in readADXL.
dort machst die statisch - allerdings hatte ioch vorhin schon angefangen aufzuteilen, ich weiss noch nicht, wie sich das insgesamt ausgewirkt hat.

Musste das leider beiseite legen. Aber es wird.

[edit]
Du wertest die Seite nur an zwei Stellen im control aus.

Wenn ich das vorhin nicht ganz verkackt habe, war das der letzte Stand:

Der Sketch verwendet 7068 Bytes (92%)
Globale Variablen verwenden 314 Bytes (61%)
//            +----------+                                   +---------+
//    Pixel   | 51 52 53 |                           Fläche  |    ^    |
//            | 48 49 50 |                                   |    5    |
//            | 45 46 47 |                                   |         |
// +----------+----------+----------+----------+   +---------+---------+---------+---------+
// | 33 34 35 | 36 39 42 | 06 07 08 | 09 12 15 |   |    ^    |         |    ^    |         |
// | 30 31 32 | 37 40 43 | 03 04 05 | 10 13 16 |   |    3    |    4  > |    0    |    1  > |
// | 27 28 29 | 38 41 44 | 00 01 02 | 11 14 17 |   |         |         |         |         |
// +----------+----------+----------+----------+   +---------+---------+---------+---------+
//                                  | 18 21 24 |                                 |         |
//                                  | 19 22 25 |                                 |    2  > |
//                                  | 20 23 26 |                                 |         |
//                                  +----------+                                 +---------+


#if (F_CPU>7370000) //neopixel library required 7.37MHz minimum clock speed; this line is used to skip this sketch in internal testing. It is not needed in your sketches.

#include <tinyNeoPixel_Static.h>                // ATTiny WS2812b Bibliothek
#include <TinyWireM.h>                          // ATTiny I2C Bibliothek
#include <avr/power.h>

// ATTiny WS2812b Initialisierung
const uint8_t datenPin = 4;                     // WS2812b DatenPin
const uint8_t ledAnzahl = 54;                   // WS2812b LED Anzahl
uint8_t pixels[ledAnzahl * 3];                  // Array für jede LED und dessen Farbe
tinyNeoPixel strip = tinyNeoPixel(ledAnzahl, datenPin, NEO_GRB, pixels);

enum : uint8_t                                  // Programme in der Reihenfolge Nummeriert, gleichzeitig die Reihenfolge der Programme
{
  Cube,
  Dice,
  FadeOnSite,
  Disco,
  Rainbow,
  Flash,
  Snake,
  Rain,
  HeartBeat
};

struct Control                                  // Struktur zum kontrolliern der Programme
{
  bool fadeinout;
  bool demoaktiv;
};

const Control controlArray[] =                  // Eigenschaften der Programme (faden, demoaktiv)
{
  //{FadeInOut, Demoaktiv}
  {false,     false}, //Cube
  {false,     false}, //Dice
  {false,     false}, //FadeOnSite
  {true,      true},  //Disco
  {true,      true},  //Rainbow
  {false,     true},  //Flash
  {false,     true},  //Snake
  {false,     true},  //Rain
  {false,     true}   //HeartBeat
};

uint8_t  brightness = 50;                       // Variable für die Helligkeit; 0 bis 50, Aus bis Volle Heligkeit
uint8_t  fadebrightness;                        // Zwischenspeicher der Helligkeit bei Szenenwechsel
uint8_t  intdata;                               // Variable für Interupts vom ADXL345b
uint16_t mem = 0;                               // Zwischenspeicher
uint8_t  program = 0;                           // Welches Programm ist aktiv
// # uint8_t  last_program = 0;                      // Programmspeicher welches vor Demo aktiv war
//bool     tap;                                 // Klopfen erkannt
//bool     doppletap;                           // Doppelklopfen erkannt
//bool     freefall;                            // Freier Fall erkannt
bool     inaktiv = false;                       // Inaktivität erkannt
// # uint8_t  top;                                   // Welche Seite ist oben
int16_t  x, y, z;                               // Achsen Variablen
uint8_t  red = 255, green = 255, blue = 255;    // Farbvariablen für den Strip
uint32_t millis_merker_demo;                    // Zwischenspeicher für Millis zum Programmwechsel im Demomodus
uint32_t millis_merker_prog;                    // Zwischenspeicher für Millis um die Programme etwas zu bremsen
// # uint32_t demotime = 100000;                     // Zeitschwelle zum wechseln zum nächsten Programm im Demo-Modus (Millisekunden)

uint8_t viper[] = {4, 54, 54, 54, 54, 54};      // Schlangen Position Array
uint8_t raincolor[12][4];                       // Zwischenpeicher der Farbwerte für Regenmuster

const uint64_t Sequenz[] PROGMEM                // Bitmuster der Zahlen die gezeigt werden entsprechend wie der Würfel sich dreht, verwendung im Programm cube() //bitRead von rechts nach links^^
{
  0b101010101101000101000010000100000001100010001111000111, // µC-PCP zeigt 6 //top=0
  0b101000101000010000100000001100010001111000111101010101, // µC-PCP zeigt 5 //top=1
  0b000010000100000001100010001111000111101010101101000101, // µC-PCP zeigt 4 //top=2
  0b100000001100010001111000111101010101101000101000010000, // µC-PCP zeigt 1 //top=3
  0b100010001111000111101010101101000101000010000100000001, // µC-PCP zeigt 2 //top=4
  0b111000111101010101101000101000010000100000001100010001, // µC-PCP zeigt 3 //top=5
};

enum : uint8_t                                  // Oben, Rechts, Links, Unten durchnummeriert
{
  Oben,           // = 0b00
  Rechts,         // = 0b01
  Links,          // = 0b10
  Unten           // = 0b11
};
const uint8_t partner[6][4] PROGMEM             // Erstellt ein FlächenArray (0-5) wo von jede anliegende Fläche (oben, rechts, links, unten) (0-3) die Fläche und welche Kante (oben, rechts, links, unten) anliegt Bitweise (0bKKFFF) hinterlegt ist
{
  // Oben liegt      // Rechts liegt    // Links liegt     // Unten liegt
  {5 + (Rechts << 3), 1 + (Unten << 3),  4 + (Oben << 3),   2 + (Unten << 3)},   // Fläche 0   // Bsp: An Fläche 0 liegt oben Fläche 5 an mit seiner rechten Kante
  {3 + (Links << 3),  2 + (Links << 3),  5 + (Oben << 3),   0 + (Rechts << 3)},  // Fläche 1   // Bsp: An Fläche 1 liegt rechts Fläche 2 an mit seiner linken Kante
  {3 + (Unten << 3),  4 + (Rechts << 3), 1 + (Rechts << 3), 0 + (Unten << 3)},   // Fläche 2
  {5 + (Links << 3),  4 + (Unten << 3),  1 + (Oben << 3),   2 + (Oben << 3)},    // Fläche 3
  {0 + (Links << 3),  2 + (Rechts << 3), 5 + (Unten << 3),  3 + (Rechts << 3)},  // Fläche 4
  {1 + (Links << 3),  0 + (Oben << 3),   3 + (Oben << 3),   4 + (Links << 3)}    // Fläche 5
};

// I²C Register am ADXL
/* registers */
#define ADXL345_ADDRESS          0x53
#define ADXL345_DEVID            0x00
#define ADXL345_THRESH_TAP       0x1D
#define ADXL345_OFSX             0x1E
#define ADXL345_OFSY             0x1F
#define ADXL345_OFSZ             0x20
#define ADXL345_DUR              0x21
#define ADXL345_LATENT           0x22
#define ADXL345_WINDOW           0x23
#define ADXL345_THRESH_ACT       0x24
#define ADXL345_THRESH_INACT     0x25
#define ADXL345_TIME_INACT       0x26
#define ADXL345_ACT_INACT_CTL    0x27
#define ADXL345_THRESH_FF        0x28
#define ADXL345_TIME_FF          0x29
#define ADXL345_TAP_AXES         0x2A
#define ADXL345_ACT_TAP_STATUS   0x2B
#define ADXL345_BW_RATE          0x2C
#define ADXL345_POWER_CTL        0x2D
#define ADXL345_INT_ENABLE       0x2E
#define ADXL345_INT_MAP          0x2F
#define ADXL345_INT_SOURCE       0x30
#define ADXL345_DATA_FORMAT      0x31
#define ADXL345_DATAX0           0x32
#define ADXL345_DATAX1           0x33
#define ADXL345_DATAY0           0x34
#define ADXL345_DATAY1           0x35
#define ADXL345_DATAZ0           0x36
#define ADXL345_DATAZ1           0x37
#define ADXL345_FIFO_CTL         0x38
#define ADXL345_FIFO_STATUS      0x39
/* Register bits */
#define ADXL345_FULL_RES         0x03
#define ADXL345_SUPPRESS         0x03
#define ADXL345_LOW_POWER        0x04


void setup()
{
  pinMode(datenPin, OUTPUT);
  pinMode(A3, INPUT);
  randomSeed(analogRead(A3));
  TinyWireM.begin();                                      // Beginnt eine I²C Verbindung als Master
  if (brightness > 50) brightness = 50;                   // Helligkeit auf 50 begrenzen, Hardwarebedingt, sonnst zu großer Strom
  fadebrightness = brightness;                            // Helligkeit dem Zwischenspeicher übergeben
  strip.setBrightness(brightness);                        // Helligkeit setzen
  strip.clear();                                          // Alle LEDs auschalten
  strip.show();                                           // geänderte Werte der LEDs anzeigen
  /* Register setzen. Mehr information im Datenblatt*/
  writeTo(ADXL345_DATA_FORMAT,   B00001000);              // B3 == Volle Auflösung = 1, 10-Bit Auflösung = 0 | B1B0 == Sensibilität, siehe Datenblatt
  writeTo(ADXL345_BW_RATE,       B00001101);              // Setzt 800Hz Ausgangs Datenrate (nicht I²C), B4B3B2B1, siehe Datenblatt Tabelle 7 und 8, Seite 14
  writeTo(ADXL345_POWER_CTL,     0);                      // Always be sure to zero out register, don't asume it's zero
  writeTo(ADXL345_POWER_CTL,     B00001000);              // 0 | 0 | Verknüpfen von In-/Aktivität | Automatisch schlafen | Messen Aktiv | Sleep | Wake Up | Wake Up
  writeTo(ADXL345_INT_ENABLE,    B01111100);              // Interupts aktivieren DATA_READY | SINGLE_TAP | DOUBLE_TAP | Activity | Inactivity | FREE_FALL | Watermark | Overrun
  writeTo(ADXL345_THRESH_TAP,    50);                     // Klopf Schwelle (guter Wert ist 200)
  writeTo(ADXL345_DUR,           0x30);                   // Klopf Dauer einstellen, 0 = Klopfen deaktiviert
  writeTo(ADXL345_LATENT,        0x30);                   // Latenz - Zeit bis zum erwarten des zweiten Klopfens, davor wird ignoriert, 0 = Doppelklopfen deaktiviert
  writeTo(ADXL345_WINDOW,        0xFF);                   // Zeit Spanne wo ein zweites Klopfen passieren muss, damit es ein Doppelklopfen wird, 0 = Doppelklopfen deaktiviert
  writeTo(ADXL345_TAP_AXES,      B00001111);              // Achsen zum (Klopfen) aktivieren: 0 | 0 | 0 | 0 | Unterdrückung bei Bewegung An/Aus | X-Achse Tap An/Aus | Y-Achse Tap An/Aus | Z-Achse Tap An/Aus
  /* Freier Fall wird erkannt wenn Z, X und Y gleichzeitig den Wert nahe 0 haben, dazu müssen X, Y und Z im ADXL ein Offset haben damit der Free Fall Detektor das korrekt an den Interupt gibt */
  writeTo(ADXL345_THRESH_FF,     4);                      // Freier Fall Schwelle (0-255), 5-9 wird empfohlen laut Datenblatt
  writeTo(ADXL345_TIME_FF,       50);                     // Freier Fall Mindestzeit (0-255), 20 für 100mSec - 70 für 350mSec wird empfohlen laut Datenblatt
  writeTo(ADXL345_OFSX,          255);                    // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
  writeTo(ADXL345_OFSY,          42);                     // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
  writeTo(ADXL345_OFSZ,          187);                    // internen Offset setzen, 0 Aus, 1-123 = +, 255-124 = - // im 2g Modus ~4Einheiten pro Bit
  writeTo(ADXL345_THRESH_ACT,    30);                     // Schwellwert zum erkennen einer Aktivität
  writeTo(ADXL345_THRESH_INACT,  30);                     // Schwellwert zum erkennen einer Inaktivität
  writeTo(ADXL345_TIME_INACT,    255);                    // Zeit die der Schwellwert der Inaktivität überschritten werden muss 0-255 Sekunden
  writeTo(ADXL345_ACT_INACT_CTL, B11111111);              // Einstellungen ACT 0=DC 1=AC | ACT (erkennen) X 0=Aus 1=An | ACT Y | ACT Z | INACT 0=DC 1=AC | INACT (erkennen) X 0=Aus 1=An | INACT Y | INACT Z
}

void loop()
{
  readADXL();                                                                          // Funktion zum Daten auslesen
  if (fadebrightness > brightness) fadebrightness = brightness;                        // Zwischenspeicher zum Helligkeitsfaden auf maximale Helligkeit begrenzen
  strip.setBrightness(fadebrightness);                                                 // Helligkeit setzen
  control();                                                                           // Funktion zum Programmablauf steuern
}


void control()
{
  if (bitRead(intdata, 2))
  {
    freefallprog();                                                                     // Wenn Freier Fall erkannt, LED Muster für Freien Fall starten
    intdata = read8(ADXL345_INT_SOURCE);                                                // ADXL Interupt Speicher auslesen und damit leeren, verhindert doppeltes ausführen von freefallprog()
    nextProgram();                                                                      // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
  }
  if (inaktiv && !controlArray[program].demoaktiv)                                      // Wenn inaktiv und aktuelles Programm nicht für DemoModus
  {
    nextProgram();                                                                      // Erhöhe den Programzähler oder setzt auf Null Wenn Programmanzahl überschritten
  }
  else
  {
    switch (program)                                                                    // Programm nach Programmzähler wählen
    {
      case Cube:          // Sechs immer oben
        if (millis() - millis_merker_prog > 55)
        {
          cube(seiteADXL());
          millis_merker_prog = millis();
        }
        break;
      case Dice:          // WürfelModus
        dice();
        break;
      case FadeOnSite:    // Farbwechsel abhängig der oben liegenden Seite
        fadeonsite();
        break;
      case Disco:         // Disco, zufällige Farbwiedergabe
        if (millis() - millis_merker_prog > 55)
        {
          disco();
          millis_merker_prog = millis();
        }
        break;
      case Rainbow:       // Farbwechsel nach Regenbogen
        if (millis() - millis_merker_prog > 35)
        {
          rainbow();
          millis_merker_prog = millis();
        }
        break;
      case Flash:         // Zufälliges Aufblitzen
        if (millis() - millis_merker_prog > mem)
        {
          flash();
          mem = random(750);
          millis_merker_prog = millis();
        }
        break;
      case Snake:         // Schlange
        if (millis() - millis_merker_prog > 250)
        {
          snake();
          millis_merker_prog = millis();
        }
        break;
      case Rain:          // Simuliert Regen, Farbe abhängig der oben liegenden Seite
        if (millis() - millis_merker_prog > 7)
        {
          rain(seiteADXL());
          millis_merker_prog = millis();
        }
        break;
      case HeartBeat:     // Simuliert Herzklopfen
        heartbeat();
        break;
      default:
        break;
    }
    fadeInOut();                                                                    // Funktion zum gemütlichen Übergang, wenn eingestellt
  }
}

void fadeInOut()
{
  const uint32_t demotime = 100000;                     // Zeitschwelle zum wechseln zum nächsten Programm im Demo-Modus (Millisekunden)
  if (controlArray[program].fadeinout)
  {
    if (millis() - millis_merker_demo > demotime && inaktiv)
    {
      if (--fadebrightness == 0)
      {
        millis_merker_demo = millis();
        nextProgram();
      }
    }
    else if (fadebrightness < brightness) fadebrightness++;
  }
  else
  {
    fadebrightness = brightness;
    if (millis() - millis_merker_demo > demotime && inaktiv)
    {
      millis_merker_demo = millis();
      nextProgram();
      fadebrightness = 0;
    }
  }
}

void nextProgram()
{
  if (++program >= (sizeof(controlArray) / sizeof(controlArray[0]))) program = 0;
}

uint8_t readNachbarPixel(uint8_t pixel, uint8_t orientation)
{
  uint8_t side  = pixel / 9;                    // vom übergebenen Pixel die Flächennummer 0-5
  uint8_t index = pixel % 9;                    // vom übergebenen Pixel die Indexnummer auf seiner Fläche 0-8
  uint8_t result = 0;                           // Rückgabewertvariable
  switch (orientation)                          // an welcher Kante liegt die abfragende Seite
  {
    case Oben: // 0
      switch (index)                            // welches obere Pixel auf der Fläche sucht den oberen Nachbar
      {
        case 6: // Ecke oben links
          result = callPixel(side, Oben, 0);    // callPixel(Fläche des Fragenden Pixels, Kannte des Fragenden Pixels, Position im Bezug zur Kante wenn man von der Mitte schaut (0=Rechts, 1=Mitte, 2=Links));
          break;
        case 7: // Seite oben mitte
          result = callPixel(side, Oben, 1);
          break;
        case 8: // Ecke oben rechts
          result = callPixel(side, Oben, 2);
          break;
        default:
          result = pixel + 3;
          break;
      }
      break;
    case Rechts: // 1
      switch (index)
      {
        case 8: // Ecke oben rechts
          result = callPixel(side, Rechts, 0);
          break;
        case 5: // Seite rechts mitte
          result = callPixel(side, Rechts, 1);
          break;
        case 2: // Ecke unten rechts
          result = callPixel(side, Rechts, 2);
          break;
        default:
          result = pixel + 1;
          break;
      }
      break;
    case Links: // 2
      switch (index)
      {
        case 0: // Ecke unten links
          result = callPixel(side, Links, 0);
          break;
        case 3: // Seite links mitte
          result = callPixel(side, Links, 1);
          break;
        case 6: // Ecke oben links
          result = callPixel(side, Links, 2);
          break;
        default:
          result = pixel - 1;
          break;
      }
      break;
    case Unten: // 3
      switch (index)
      {
        case 2: // Ecke unten rechts
          result = callPixel(side, Unten, 0);
          break;
        case 1: // Seite unten mitte
          result = callPixel(side, Unten, 1);
          break;
        case 0: // Ecke unten links
          result = callPixel(side, Unten, 2);
          break;
        default:
          result = pixel - 3;
          break;
      }
      break;
  }
  return result;
}

uint8_t callPixel(uint8_t aufruferFlaeche, uint8_t aufruferKante, uint8_t index)
{
  uint8_t pgm = pgm_read_byte(&partner[aufruferFlaeche][aufruferKante]);  // Holt Daten über anliegende Fläche mit ihrer anliegenden Kante aus dem PROGMEM
  uint8_t flaeche = pgm & 0b111;                                          // Beispiel [0][1] (Fläche rechts von 0) // 0b00001 + 0b11000 = 0b11001 // 0b11001 & 0b111 = 0b1 = 1 // Fläche 1
  uint8_t kante = pgm >> 3;                                               // schiebt Bits des Arrays partner [Fläche] [Kante] um 3 Bits nach rechts, Es bleibt die anliegende Kante übrig // 0b11001 >> 3 = 0b11 = 3 = Unten
  uint8_t result = 0;                                                     // Rückgabewertvariable
  switch (kante)                                                          // abhängig davon, welche Kante an der Aufruferfläche liegt
  {
    case Oben:   //0
      result = 8 - index;                                                 // errechnet anhand des index, das Pixel auf der Fläche. Möglich 6, 7 oder 8
      break;
    case Unten:  //3
      result = 0 + index;                                                 // errechnet anhand des index, das Pixel auf der Fläche. Möglich 0, 1 oder 2
      break;
    case Rechts: //1
      result = 2 + index * 3;                                             // errechnet anhand des index, das Pixel auf der Fläche. Möglich 2, 5 oder 8
      break;
    case Links:  //2
      result = 6 - index * 3;                                             // errechnet anhand des index, das Pixel auf der Fläche. Möglich 0, 3 oder 6
      break;
  }
  result = result + flaeche * 9;                                          // errechnet nahand der Fläche die Pixelnummer
  return result;
}

/*ADXL345 Komunikation*/
uint8_t seiteADXL()
{
  uint8_t top;
  x = read16(ADXL345_DATAX0);                             // X Achsenwert auslesen und x übergeben
  y = read16(ADXL345_DATAY0);                             // Y Achsenwert auslesen und y übergeben
  z = read16(ADXL345_DATAZ0);                             // Z Achsenwert auslesen und z übergeben
  /* Würfelseitenerkennung*/
  if (x > 200) top = 1; //Fläche 1 oben                       // µC-PCP zeigt 4
  if (y > 200) top = 2; //Fläche 2 oben                       // µC-PCP zeigt 1
  if (z > 200) top = 3; //Fläche 3 oben                       // µC-PCP zeigt 2
  if (x < -200) top = 4; //Fläche 4 oben                       // µC-PCP zeigt 3
  if (y < -200) top = 5; //Fläche 5 oben                       // µC-PCP zeigt 6
  if (z < -200) top = 0; //Fläche 0 oben                       // µC-PCP zeigt 5
  return top;
}
// Hier teilen?
void readADXL()
{
  static uint8_t  lastProgram = 0;                      // Programmspeicher welches vor Demo aktiv war
  intdata = read8(ADXL345_INT_SOURCE);                    // Interups Auslesen und im ADXL leeren
  if (bitRead(intdata, 3) && !inaktiv)                    // Wenn Inaktivität erkannt (keine Änderung über ADXL345_TIME_INACT eigestellte Sekunden)
  {
    inaktiv = true;
    millis_merker_demo = millis();
    lastProgram = program;                               // Aktives Program im ProgramMerker hinterlegen
  }
  if (bitRead(intdata, 4) && inaktiv)                     // Wenn Aktivität erkannt
  {
    inaktiv = false;
    program = lastProgram;                               // Letztes aktives Program aus dem ProgramMerker holen
  }
}

uint16_t read16(uint8_t address)
{
  uint8_t MSByte = 0, LSByte = 0;
  int16_t regValue = 0;
  TinyWireM.beginTransmission(ADXL345_ADDRESS);
  TinyWireM.write(address);
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(ADXL345_ADDRESS, 2);
  if (TinyWireM.available())
  {
    LSByte = TinyWireM.read();
    MSByte = TinyWireM.read();
  }
  regValue = (MSByte << 8) + LSByte;
  return regValue;
}

uint8_t read8(uint8_t address)
{
  uint8_t regValue = 0;
  TinyWireM.beginTransmission(ADXL345_ADDRESS);
  TinyWireM.write(address);
  TinyWireM.endTransmission();
  TinyWireM.requestFrom(ADXL345_ADDRESS, 1);
  if (TinyWireM.available())
  {
    regValue = TinyWireM.read();
  }
  return regValue;
}

void writeTo(uint8_t address, uint8_t val)
{
  TinyWireM.beginTransmission(ADXL345_ADDRESS);
  TinyWireM.write(address);
  TinyWireM.write(val);
  TinyWireM.endTransmission();
}

/*LED Programme*/
void heartbeat()
{
  if (red > 55) red = 0;                                      // Wenn der RotWert über 55 dann RotWert auf 0 setzen
  if (red == 55) mem++;                                       // Wenn RotWert 55 erreicht hat, Merker um eins erhöhen (damit später Rot reduziert wird bei mem gleich 1 oder 3)
  if (red == 0) mem++;                                        // Wenn RotWert 0  erreicht hat, Merker um eins erhöhen (damit später Rot erhöht wird bei mem gleich 0 oder 2) und damit der Merker für die Pause erhöht wird
  if (mem >= 4) delay(100);                                   // Wenn Merker über 4, eine Pause einlegen (Also 50-4= 46mal 0,1s Pause)
  if (mem >= 50) mem = 0;                                     // Wenn Merker über 50, dann Merker wieder auf 0, was die Pause beendet, und Rot wieder erhöht
  if (mem == 0 || mem == 2) red++;                            // Wenn Merker 0 oder 2 Rot erhöhen
  else if (mem == 1 || mem == 3) red--;                       // Wenn Merker 1 oder 3 Rot verringern
  else red = 0;                                               // Sicherstellen das Rot 0 ist wenn Merker einen anderen Wert hat (Kann durch andere Funktionen (LED-Programme) geändert werden
  strip.clear();                                              // Alle LEDs ausschalten
  for (uint8_t side = 0; side < 6; side++)                    // Auf jeder Würfelseite ausführen
  {
    if (red >= 40) for (uint8_t i = 0; i < 9; i += 2) strip.setPixelColor(i + 9 * side, red - 40, 0, 0); // Wenn rot größer 40 (verspäteter start) schreibe jedes gerade pixel auf der Würfelseite (Ecken und Mitte (Mitte wird später überschrieben)
    if (red >= 20) for (uint8_t i = 1; i < 8; i += 2) strip.setPixelColor(i + 9 * side, red - 20, 0, 0); // Wenn rot größer 20 (verspäteter start) schreibe jedes ungerade pixel auf der Würfelseite (oben, unten, links, rechts)
    strip.setPixelColor(4 + 9 * side, red, 0, 0);                                             // schreibe auf die mitte (Pixel 4) der Seite
  }
  strip.show();                                               // Zeigt die gesetzten Werte an den LEDs
}

void freefallprog()                             // lässt jedes zweite Pixel 6mal rot blinken
{
  for (uint8_t j = 0; j < 6; j++)
  {
    strip.clear();
    for (uint8_t i = 0; i < ledAnzahl; i += 2)
    {
      strip.setPixelColor(i, 255, 0, 0);
    }
    strip.show();
    delay(100);
    strip.clear();
    strip.show();
    delay(100);
  }
}

void rain(uint8_t side)
{
  uint8_t rainPixel[12];                                // Speichert die 12 obenliegenden Regenpixel
  int8_t changer[4];                                    // Speichert die Verechenoberratoren für die nach unten folgenden Pixel
  for (uint8_t i = 0; i < 4; i++)                       // Für alle 4 anliegenden Seiten (oben = 0, rechts = 1, links = 2, unten = 3)
  {
    for (uint8_t j = 0; j < 3; j++)                     // Für alle 3 anliegenden Pixel der Seite (Index 0, 1, 2)
    {
      rainPixel[i * 3 + j] = callPixel(side, i, j);     // Übergebe die 12 Pixel in das rainPixelArray // i*3+j ergibt die Nummerierung für das Array(0-11)
    }
    uint8_t upsite = pgm_read_byte(&partner[side][i]);  // Liest die Information von der anliegenden Fläche (BitArray)
    upsite = upsite >> 3;                               // gibt von der anliegenden Fläche die obere Kante wieder (schiebt die FlächenInfo Bits raus)
    changer[i] = upsite * 2 - 3;                        // Seite 5, index 852 -1 // Seite 1, 012 +3 // Seite 4, 678 -3 // Seite 2, 012 +3  // gibt gibt anhand der oben liegenden Kante, den verrechen operator für die darunter folgenden Pixel aus (0*2-3=-3, 1*2-3=-1, 2*2-3=1, 3*2-3=3)
  }                                                     // bei "oben" liegenden Pixel darunter liegende Pixel 3 kleiner, bei "rechts" liegenden Pixel, darunter liegende 1 kleiner, etc
  switch (side)                                         // Farbwahl nach Seite
  {
    case 0: red = 255; green = 0; blue = 0; break;
    case 1: red = 0; green = 255; blue = 255; break;
    case 2: red = 255; green = 0; blue = 255; break;
    case 3: red = 255; green = 255; blue = 0; break;
    case 4: red = 0; green = 0; blue = 255; break;
    case 5: red = 0; green = 255; blue = 0; break;
  }
  strip.clear();
  mem = random(0, 150);                                                                                                                             // erstellt merker zum zufälligen Starten
  for (uint8_t row = 0; row < 12; row++)                                                                                                            // row steht für eine der 12 möglichen senkrechten Reihen
  {
    if (raincolor[row][3] > 49)                                                                                                                     // wenn Zähler über 49
    {
      strip.setPixelColor(rainPixel[row] + changer[row / 3] + changer[row / 3], raincolor[row][0], raincolor[row][1], raincolor[row][2]);           // setze Farbe aufs untere pixel
      strip.setPixelColor(rainPixel[row] + changer[row / 3], raincolor[row][0] / 1.1, raincolor[row][1] / 1.1, raincolor[row][2] / 1.1);            // setze Farbe aufs zweite Pixel von oben mit 90% Leuchtkraft
      strip.setPixelColor(rainPixel[row], raincolor[row][0] / 1.1 / 1.1, raincolor[row][1] / 1.1 / 1.1, raincolor[row][2] / 1.1 / 1.1);             // setze Farbe aufs obere Pixel mit 90% von 90% Leuichtkraft
      for (uint8_t i = 0; i < 3; i++)
      {
        raincolor[row][i] = raincolor[row][i] / 1.1;                                                                                                // reduziere die Leuchtkraft um 90%
      }
      if (raincolor[row][0] < 1 && raincolor[row][1] < 1 && raincolor[row][2] < 1)                                                                  // wenn alle Farbwerte unter 1
      {
        for (uint8_t i = 0; i < 4; i++)
        {
          raincolor[row][i] = 0;                                                                                                                    // Zähler zurücksetzen und sicherstellen das Farbwerte gleich 0
        }
      }
    }
    if (raincolor[row][3] < 50 && raincolor[row][3] > 24)                                                                                           // wenn Zähler 25 bis 49
    {
      strip.setPixelColor(rainPixel[row] + changer[row / 3], raincolor[row][0], raincolor[row][1], raincolor[row][2]);                              // setze Farbe aufs zweite pixel von oben
      strip.setPixelColor(rainPixel[row], raincolor[row][0] / 1.1, raincolor[row][1] / 1.1, raincolor[row][2] / 1.1);                               // setzt Farbe aufs obere pixel mit 90% Leuichtkraft
      ++raincolor[row][3];
    }
    if (raincolor[row][3] < 25 && raincolor[row][3] > 0)                                                                                            // wenn Zähler 1 bis 24
    {
      strip.setPixelColor(rainPixel[row], raincolor[row][0], raincolor[row][1], raincolor[row][2]);                                                 // setze Farbe aufs obere Pixel der Reihe
      ++raincolor[row][3];                                                                                                                          // Zähler um 1 erhöhen
    }
    if (mem == row && raincolor[row][3] == 0)                                                                                                       // wenn Zufalsmerker gleich j, und Zähler der Reihe gleich 0
    {
      raincolor[row][0] = red; raincolor[row][1] = green; raincolor[row][2] = blue;                                                                 // setze übergebe Farbewerte, gesetzt nach Seite die oben liegt
      ++raincolor[row][3];                                                                                                                          // Zähler für Reihe auf 1 setzen (Zählen ist füpr Zeitverzögerung zuständig)
    }
  }
  strip.show();
}

void snake()
{
  uint8_t nachbarPixel[4];
  mem = 0;
  for (uint8_t i = 0; i < 4; i++)                         // für alle 4 Nachbarpixel überprüfen
  {
    bool crash = false;
    for (uint8_t k = 1; k < sizeof(viper); k++)           // für alle Pixel die die Schlange belegt überprüfen
    {
      if (readNachbarPixel(viper[0], i) == viper[k])      // wenn das Nachbarpixel gleich eines Pixels der Schlange
      {
        crash = true;
      }
    }
    if (!crash)                                           // wenn das Nachbarpixel keine besetzte Position ist
    {
      nachbarPixel[mem] = readNachbarPixel(viper[0], i);  // dann schiebe den PixelIndex über eventuelle mögliche Pixel
      mem++;                                              // Zähler für mögliche Pixel erhöhen
    }
  }
  for (uint8_t j = sizeof(viper) - 1; j > 0; j--)         // Über die Länge der Schlange
  {
    viper[j] = viper[j - 1];                              // Übergib das gespeicherte Pixel im Viper Array eine Position Richtung Ende, das letzte fällt weg
    strip.setPixelColor(viper[j], 255 - (j * 40), 0 + (j * 40), 0); // setze Farbewerte ändernd Richtung Schanzende (Von Rot Kopf, über gelb Richtung grün
  }
  viper[0] = nachbarPixel[random(0, mem)];                // übergibt dem Kopf, eine zufällige auswahl aus den möglichen Nachbarpixeln
  strip.setPixelColor(viper[0], 255, 0, 0);               // Farbwert Kopf
  strip.show();
  strip.clear();
}

void flash()
{
  strip.clear();
  strip.setPixelColor(random(ledAnzahl - 1), random(255), random(255), random(255));
  strip.show();
  delay(7);
  strip.clear();
  strip.show();
}

void rainbow()
{
  if (red > 250 || green > 250 || blue > 250)
  {
    red = 250; blue = 0; green = 0;
  }
  uint8_t newred = red;
  uint8_t newgreen = green;
  uint8_t newblue = blue;
  for (uint8_t i = 0; i < ledAnzahl; i++)
  {
    if (newred == 250 && newblue == 0 && newgreen < 250) newgreen += 10;
    else if (newred > 0 && newblue == 0 && newgreen == 250) newred -= 10;
    else if (newred == 0 && newblue < 250 && newgreen == 250) newblue += 10;
    else if (newred == 0 && newblue == 250 && newgreen > 0) newgreen -= 10;
    else if (newred < 250 && newblue == 250 && newgreen == 0) newred += 10;
    else if (newred == 250 && newblue > 0 && newgreen == 0) newblue -= 10;
    strip.setPixelColor(i, newred, newgreen, newblue);
  }
  strip.show();
  if (red == 250 && blue == 0 && green < 250) green += 10;
  else if (red > 0 && blue == 0 && green == 250) red -= 10;
  else if (red == 0 && blue < 250 && green == 250) blue += 10;
  else if (red == 0 && blue == 250 && green > 0) green -= 10;
  else if (red < 250 && blue == 250 && green == 0) red += 10;
  else if (red == 250 && blue > 0 && green == 0) blue -= 10;
  else
  {
    red = 250; blue = 0; green = 0;
  }
}

void disco()
{
  for (uint8_t i = 0; i <= ledAnzahl; i++)
  {
    strip.setPixelColor(i, random(255), random(255), random(255));
  }
  strip.show();
}

void fadeonsite()
{
  uint8_t newred = map(x, -280, 280, 0, 255);
  uint8_t newgreen = map(y, -280, 280, 0, 255);
  uint8_t newblue = map(z, -280, 280, 0, 255);
  if (newred + 10 < red) red -= 2;
  if (newred - 10 > red) red += 2;
  if (newgreen + 10 < green) green -= 2;
  if (newgreen - 10 > green) green += 2;
  if (newblue + 10 < blue) blue -= 2;
  if (newblue - 10 > blue) blue += 2;
  for (uint8_t i = 0; i <= ledAnzahl; i++)
  {
    strip.setPixelColor(i, red, green, blue);
  }
  strip.show();
}

void dice()
{
  if (bitRead(intdata, 6)) mem = 2;                           // Wenn Erschütterung erkannt
  if (mem < 520)                                              // Solange Zeitspanne unter 520 mS
  {
    cube(random(0, 6));                                       // Wähle eine zufällige Seite oben
    delay(mem);                                               // Warte die zwischengespeicherte Zeit
    mem = (mem * random(10, 21)) / 10;                        // Erhöhe die wartezeit etwas im zufälligen Bereich (simuliert ein langsames auslaufen der Zeit
  }
}

void cube(byte side)
{
  uint64_t pgm = 0;                                           // Zwischenspeicher für das aus dem PROGMEM geholten Bitmuster
  memcpy_P(&pgm, &Sequenz[side], sizeof(pgm));                // memcpy_P holt aus dem PROGMEM Daten (Ziel, Quelle, Größe in Byte von Quelle und Ziel)
  for (uint8_t index = 0; index < 54; index++)
  {
    if (bitRead(pgm, index)) strip.setPixelColor(index, red, green, blue);
    else strip.setPixelColor(index, 0, 0, 0);
  }
  strip.show();
}

#else //neopixel library required 7.37MHz minimum clock speed; these and following lines are used to skip this sketch in internal testing. It is not needed in your sketches.
#warning "Neopixel control requires F_CPU > 7.37MHz"
void setup() {}
void loop() {}
#endif