Code Aufräumen/Verbessern, Speicherplatz freigeben

Ich habe mir über die letzten Monate ein Sketch geschrieben, der WS2812b LEDs auf einem Würfel mit einem ATTiny85 steuert. Ein ADXL345b ist auch mit an Board.

Es funktioniert alles einwandfrei :slight_smile: Auch fehlen mir weitere Ideen für LED Muster bzw. Abläufe. Also eigentlich alles fertig

Aber da ich ja dennoch weiter lernen will, dachte ich mir, ich gehe mal ans verbessern des Codes. Mangels Kommentare, stehe ich selber an einigen Stellen davor, und frage mich, was hast du dir damals eigentlich dabei gedacht :sweat_smile:

Auch ist der Speicher des ATTiny85s aufgebraucht

Der Sketch verwendet 7954 Bytes (97%) des Programmspeicherplatzes. Das Maximum sind 8192 Bytes.
Globale Variablen verwenden 300 Bytes (58%) des dynamischen Speichers, 212 Bytes für lokale Variablen verbleiben. Das Maximum sind 512 Bytes.

Also wenn einer der Profis mir ein paar Schubser geben könnte, wäre ich dankbar. Kein muss. Nur bei eigenem Interesse oder langer Weile.

Im Moment werde ich erstmal versuchen die LED-Ablaufprogramme von einigen Delays zu befreien. Obwohl die Delays sich nicht spürbar auswirken, ist es dennoch eine Übung in zukünftigen Programmen ganz auf Delays zu verzichten.

Nicht erschrecken, ist etwas viel Quellcode

#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);

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  progmem = 0;                           // Programmspeicher welches vor Demo aktiv war
uint8_t  demo = 0;                              // Programspeicher für Demo
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
uint8_t  newred, newblue, newgreen;             // Farbvariablen zum Berechnen
uint64_t millis_merker;                         // Zwischenspeicher für Millis für Vergleiche
uint64_t demotime = 60000;                      // Zeitschwelle zum wechseln zum nächsten Programm im Demo-Modus (Millisekunden)

const uint8_t indexonrain[6][12][3] PROGMEM = { // Index der Pixel für Regenmuster
  {     // top=1
    {2,1,0},
    {5,4,3},
    {8,7,6},
    {18,19,20},
    {21,22,23},
    {24,25,26},
    {27,28,29},
    {30,31,32},
    {33,34,35},
    {51,48,45},
    {52,49,46},
    {53,50,47}
  },{   // top=2
    {0,3,6},
    {1,4,7},
    {2,5,8},
    {11,10,9},
    {14,13,12},
    {17,16,15},
    {27,30,33},
    {28,31,34},
    {29,32,35},
    {38,37,36},
    {41,40,39},
    {44,43,42}
  },{  // top=3
    {15,12,9},
    {16,13,10},
    {17,14,11},
    {24,21,18},
    {25,22,19},
    {26,23,20},
    {36,39,42},
    {37,40,43},
    {38,41,44},
    {45,46,47},
    {48,49,50},
    {51,52,53}
  },{  // top=4
    {0,1,2},
    {3,4,5},
    {6,7,8},
    {20,19,18},
    {23,22,21},
    {26,25,24},
    {29,28,27},
    {32,31,30},
    {35,34,33},
    {45,48,51},
    {46,49,52},
    {47,50,53}
  },{  // top=5
    {6,3,0},
    {7,4,1},
    {8,5,2},
    {9,10,11},
    {12,13,14},
    {15,16,17},
    {33,30,27},
    {34,31,28},
    {35,32,29},
    {36,37,38},
    {39,40,41},
    {42,43,44}
  },{  // top=6
    {9,12,15},
    {10,13,16},
    {11,14,17},
    {18,21,24},
    {19,22,25},
    {20,23,26},
    {42,39,36},
    {43,40,37},
    {44,41,38},
    {47,46,45},
    {50,49,48},
    {53,52,51}
  }
};

uint8_t raincolor[12][4]= {                      // Zwischenpeicher der Farbwerte für Regenmuster
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0},
  {0,0,0,0}
};

const uint8_t indexonsite[54][4] PROGMEM = {    // Index der Nachbarpixel, abgelegt im Flash
  {1,3,20,44},   //0
  {0,2,4,19},    //1
  {1,5,11,18},   //2
  {0,4,6,43},    //3
  {1,3,5,7},     //4
  {2,4,8,10},    //5
  {3,7,42,47},   //6
  {4,6,8,50},    //7
  {5,7,9,53},    //8
  {8,10,12,53},  //9
  {5,9,11,13},   //10
  {2,10,14,18},  //11
  {9,13,15,52},  //12
  {10,12,14,16}, //13
  {11,13,17,21}, //14
  {12,16,33,51}, //15
  {13,15,17,30}, //16
  {14,16,24,27}, //17
  {2,11,19,21},  //18
  {1,18,20,22},  //19
  {0,19,23,44},  //20
  {14,18,22,24}, //21
  {19,21,23,25}, //22
  {20,22,26,41}, //23
  {17,21,25,27}, //24
  {22,24,26,28}, //25
  {23,25,29,38}, //26
  {17,24,28,30}, //27
  {25,27,29,31}, //28
  {26,28,32,38}, //29
  {16,27,31,33}, //30
  {28,30,32,34}, //31
  {29,31,35,37}, //32
  {15,30,34,51}, //33
  {31,33,35,48}, //34
  {32,34,36,45}, //35
  {35,37,39,45}, //36
  {32,36,38,40}, //37
  {26,29,37,41}, //38
  {36,40,42,46}, //39
  {37,39,41,43}, //40
  {23,38,40,44}, //41
  {6,39,43,47},  //42
  {3,40,42,44},  //43
  {0,20,41,43},  //44
  {35,36,46,48}, //45
  {39,45,47,49}, //46
  {6,42,46,50},  //47
  {34,45,49,51}, //48
  {46,48,50,52}, //49
  {7,47,49,53},  //50
  {15,33,48,52}, //51
  {12,49,51,53}, //52
  {8,9,50,52}    //53
};

uint8_t snake[] = {4,54,54,54,54,54};           // Schlangen Position Array

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

uint64_t heartbeatpattern[] = {                 // Bitmuster für das unterschiedliche Ansprechen der LEDs für heartbeat()
  0b000010000000010000000010000000010000000010000000010000,
  0b010101010010101010010101010010101010010101010010101010,
  0b101000101101000101101000101101000101101000101101000101,
};

// 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(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(){
  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;                                        // µC-PCP zeigt 4
  if(y>200) top=2;                                        // µC-PCP zeigt 3
  if(z>200) top=3;                                        // µC-PCP zeigt 2
  if(x<-200) top=4;                                       // µC-PCP zeigt 1
  if(y<-200) top=5;                                       // µC-PCP zeigt 6
  if(z<-200) top=6;                                       // µC-PCP zeigt 5
  
  intdata = read8(ADXL345_INT_SOURCE);                    // Interups Auslesen und im ADXL leeren
  
  if(fadebrightness>brightness) fadebrightness=brightness;// Zwischenspeicher zum Helligkeitsfaden auf maximale Helligkeit begrenzen
  strip.setBrightness(fadebrightness);                    // Helligkeit setzen
  
  if(bitRead(intdata,3)){                                 // Wenn Inaktivität erkannt (keine Änderung über ADXL345_TIME_INACT eigestellte Sekunden)
    inaktiv = true;
    progmem = program;                                    // Aktives Program im ProgramMerker hinterlegen
  }
  if(bitRead(intdata,4)&&inaktiv){                        // Wenn Aktivität erkannt
    inaktiv = false;
    program = progmem;                                    // Letztes aktives Program aus dem ProgramMerker holen
  }

  if (inaktiv && program < 3){                            // Wenn Inaktiv, dann gehe in Demo Modus (Program 3 bis 7)
    program = 3;                                          
    millis_merker = millis();
  }
  else {
    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()
      if (program > 7) program = 0;                       // Wenn das höchste Program erreicht wird, beginne beim ersten Program
      else program++;                                     // Ansonsten nächstes Program ausführen
      millis_merker = millis();
    }
    switch (program) {
      case 0:
        cube(top);    // Sechs immer oben
        break;
      case 1:
        randomdice(); // WürfelModus
        break;
      case 2:
        fade();       // Farbwechsel nach Seite
        break;
      case 3:
        if(millis()-millis_merker > demotime && inaktiv){ // Wenn DemoZeit überschritten und der Würfel inaktiv erkannt hat
          fadebrightness--;                               // Langsam ausdimmen um angenehmeren Übergang zu gewährleisten
          if(fadebrightness==0){                          // Wenn Helligkeit auf 0 dann zum nächsten Program
            program++;                                    // dann zum nächsten Program
            millis_merker = millis();
          }
        }
        else if (fadebrightness<brightness) fadebrightness++; // Ansonsten wenn Helligkeit unter MaxHelligkeit, Helligkeit erhöhen (Aufdimmen)
        zufall();     // Disco ^^
        break;
      case 4:
        if(millis()-millis_merker > demotime && inaktiv){
          fadebrightness--;
          if(fadebrightness==0){
            program++;
            millis_merker = millis();
          }
        }
        else if (fadebrightness<brightness) fadebrightness++;
        rainbow();    // Farbwechsel nach Regenbogen
        break;
      case 5:
        if (fadebrightness<brightness) fadebrightness=brightness; // Mit voller Helligkeit starten
        if(millis()-millis_merker > demotime && inaktiv){
          program++;
          millis_merker = millis();
        }
        flash();      // Zufälliges Aufblitzen
        break;
      case 6:
        if (fadebrightness<brightness) fadebrightness=brightness;
        if(millis()-millis_merker > demotime && inaktiv){
          program++;
          millis_merker = millis();
        }
        viper();      // Schlange
        break;
      case 7:
        if (fadebrightness<brightness) fadebrightness=brightness;
        if(millis()-millis_merker > demotime && inaktiv){
          program++;
          millis_merker = millis();
        }
        rain(top);    // Simuliert Regen
        break;
      case 8:
        if (fadebrightness<brightness) fadebrightness=brightness;
        if(millis()-millis_merker > demotime && inaktiv){
          program = 3;
          millis_merker = millis();
          fadebrightness = 0;
        }
        heartbeat();  // Simuliert Herzklopfen
        break;
    }
  }
  delay(5);                                               // ganz kurze Pause um die Effekte etwas auszubremsen
}

/*ADXL345 Komunikation*/
int16_t read16(byte 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(byte 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(byte address, byte 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(int i=0; i<54; i++){                                    // LEDs nach Mustern beschreiben
    if(bitRead(heartbeatpattern[0], i)) strip.setPixelColor(i, red, 0, 0);               // Erstes Muster
    if(bitRead(heartbeatpattern[1], i) && red>=20) strip.setPixelColor(i, red-20, 0, 0); // Zweites Muster ist immer 20 Helligkeitswerte unter dem ersten Muster
    if(bitRead(heartbeatpattern[2], i) && red>=40) strip.setPixelColor(i, red-40, 0, 0); // Drittes Muster ist immer 40 Helligkeitswerte unter dem ersten Muster
  }
  strip.show();                                               // Zeigt die gesetzten Werte an den LEDs
}

void freefallprog() {
  for(int j=0; j<6; j++){
    strip.clear();
    for(int i=0; i<ledAnzahl; i+=2){
      strip.setPixelColor(i,255,0,0);
    }
    strip.show();
    delay(100);
    strip.clear();
    strip.show();
    delay(100);
  }
  freefall = 0;
}

void rain(byte site){
  switch (site){
    case 1: red=255; green=0; blue=0; break;
    case 2: red=0; green=255; blue=255; break;
    case 3: red=255; green=0; blue=255; break;
    case 4: red=255; green=255; blue=0; break;
    case 5: red=0; green=0; blue=255; break;
    case 6: red=0; green=255; blue=0; break;
  }
  strip.clear();
  mem=random(0,150);
  for(byte j=0; j<12; j++) {
    if (raincolor[j][3]>49){
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][2]),raincolor[j][0],raincolor[j][1],raincolor[j][2]);
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][1]),raincolor[j][0]/1.1,raincolor[j][1]/1.1,raincolor[j][2]/1.1);
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][0]),raincolor[j][0]/1.1/1.1,raincolor[j][1]/1.1/1.1,raincolor[j][2]/1.1/1.1);
      for(byte i=0; i<3; i++){
        raincolor[j][i] = raincolor[j][i]/1.1;
      }
      if(raincolor[j][0]<1&&raincolor[j][1]<1&&raincolor[j][2]<1){
        for(byte i=0; i<4; i++){
          raincolor[j][i] = 0;
        }
      }
    }
    if (raincolor[j][3]<50&&raincolor[j][3]>24){
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][1]),raincolor[j][0],raincolor[j][1],raincolor[j][2]);
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][0]),raincolor[j][0]/1.1,raincolor[j][1]/1.1,raincolor[j][2]/1.1);
      ++raincolor[j][3];
    }
    if (raincolor[j][3]<25&&raincolor[j][3]>0){
      strip.setPixelColor(pgm_read_byte_near(&indexonrain[site-1][j][0]),raincolor[j][0],raincolor[j][1],raincolor[j][2]);
      ++raincolor[j][3];
    }
    if (mem==j&&raincolor[j][3]==0) { 
      raincolor[j][0]=red; raincolor[j][1]=green; raincolor[j][2]=blue;
      ++raincolor[j][3];
    }
  }
  strip.show();
}

void viper() {
  byte nachbar[4];
  mem = 0;
  for(byte i=0; i<4; i++) {
    bool crash = 0;
    for(byte k=1; k<sizeof(snake); k++){
      if(pgm_read_byte_near(&indexonsite[snake[0]][i]) == snake[k]) {  // [4][0]==1;[4][1]==3;[4][2]==5;[4][3]==7;
        crash = 1;
      }
    }
    if (!crash) {
      nachbar[mem] = pgm_read_byte_near(&indexonsite[snake[0]][i]);
      mem++;
    }
  }
  for(byte j = sizeof(snake)-1; j>0; j--) {
    snake[j] = snake[j-1];
    strip.setPixelColor(snake[j],255-(j*40),0+(j*40),0);
  }
  snake[0] = nachbar[random(0,mem)];
  strip.setPixelColor(snake[0],255,0,0);
  strip.show();
  delay(200);
  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();
  delay(random(750));
}

void rainbow() {
  if(red > 250 || green > 250 || blue > 250) {
    red=250; blue=0; green=0;
  }
  newred = red;
  newgreen = green;
  newblue = blue;
  for(int 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);
  }
  delay(30);
  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 zufall() {
  for(int i=0; i<=ledAnzahl; i++) {
    strip.setPixelColor(i,random(255),random(255),random(255));
  }
  delay(50);
  strip.show();
}

void fade() {
  if (x < 0) x=x-2*x;
  if (y < 0) y=y-2*y;
  if (z < 0) z=z-2*z;
  newred = map(x, 0, 280, 0, 255);
  newgreen = map(y, 0, 280, 0, 255);
  newblue = map(z, 0, 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(int i=0; i<=ledAnzahl; i++) {
    strip.setPixelColor(i,red,green,blue);
  }
  strip.show();
}

void randomdice(){
  if (bitRead(intdata,6)) mem=2;                             // Wenn Erschütterung erkannt
  if (mem < 520){
    cube(random(1,7));
    delay(mem);
    mem = (mem * random(10,21)) / 10;
  }
}

void cube(byte site){
/* 
* Seite 1 01 02 03 04 05 06 07 08 09 <> Seite 6 28 29 30 31 32 33 34 35 36 
* Seite 2 10 11 12 13 14 15 16 17 18 <> Seite 5 37 38 39 40 41 42 43 44 45 
* Seite 3 19 20 21 22 23 24 25 26 27 <> Seite 4 46 47 48 49 50 51 52 53 54  
*/
  delay(50);
  switch (site) {
    case 1:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break; 
    case 2:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break; 
    case 3:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break; 
    case 4:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break; 
    case 5:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break; 
    case 6:
      for(byte i=0; i<54; i++){
        if(bitRead(Sequenz[site-1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break;  
    default:
      strip.clear();
      strip.setPixelColor(0, 0, 0, 0);
      strip.setPixelColor(1, 255, 255, 255);
      strip.setPixelColor(2, 0, 0, 0);
      strip.setPixelColor(3, 255, 255, 255);
      strip.setPixelColor(4, 0, 0, 0);
      strip.setPixelColor(5, 255, 255, 255);
      strip.setPixelColor(6, 0, 0, 0);
      strip.setPixelColor(7, 255, 255, 255);
      strip.setPixelColor(8, 0, 0, 0);
      strip.show();
      break;
  }
}

#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

Die Arduino Erweiterung ist von hier http://drazzy.com/package_drazzy.com_index.json
Und ATTinyCore von Spence Konde 1.5.0 wird genutzt

Aktuell werde ich versuchen mal das folgende zu verschlimmbessern (Zeile 420-436)

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(int i=0; i<54; i++){                                    // LEDs nach Mustern beschreiben
    if(bitRead(heartbeatpattern[0], i)) strip.setPixelColor(i, red, 0, 0);               // Erstes Muster
    if(bitRead(heartbeatpattern[1], i) && red>=20) strip.setPixelColor(i, red-20, 0, 0); // Zweites Muster ist immer 20 Helligkeitswerte unter dem ersten Muster
    if(bitRead(heartbeatpattern[2], i) && red>=40) strip.setPixelColor(i, red-40, 0, 0); // Drittes Muster ist immer 40 Helligkeitswerte unter dem ersten Muster
  }
  strip.show();                                               // Zeigt die gesetzten Werte an den LEDs
}

Gruß Plumps (N1d45)

ich würde äugisch ähnliche Zeilen analysieren, ob diese nicht mit Funktionen oder in For-schleifen generalisiert werden könnten.

zwei Beispiele

case 2:
      for (byte i = 0; i < 54; i++) {
        if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
      break;
    case 3:
      for (byte i = 0; i < 54; i++) {
        if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();

das ist ja sogar für einige Cases komplett gleich

da definierst du am besten mehrere Einsprungmarken:
case 1:
case 2:
case 3:

oder auch:

strip.setPixelColor(0, 0, 0, 0);
      strip.setPixelColor(1, 255, 255, 255);
      strip.setPixelColor(2, 0, 0, 0);
      strip.setPixelColor(3, 255, 255, 255);
      strip.setPixelColor(4, 0, 0, 0);
      strip.setPixelColor(5, 255, 255, 255);
      strip.setPixelColor(6, 0, 0, 0);
      strip.setPixelColor(7, 255, 255, 255);
      strip.setPixelColor(8, 0, 0, 0);

entweder zwei Forschleifen im zweier Schritt, oder eine Schleife mit gerade/ungerade Erkennung,

weiters dein indexonsite ... wenn das dein Pixel-Grid ist ... das geht doch vermutlich auch mit einer Funktion.

nicht näher analysiert aber verdächtig:

uint64_t millis_merker;                         // Zwischenspeicher für Millis für Vergleiche
uint64_t demotime = 60000;                      // Zeitschwelle zum wechseln zum nächsten Programm im Demo-Modus (Millisekunden)

64bit Zeitstempel? Echt?

Da ich weder Profi noch wsxxxx noch adxl ...

Ich sehe Handlungsmöglichkeit 1 in

void cube(byte site)

Nimmst Du aus den cases das strip.show() raus und packst es als letztes einmal vor die Funktion abschliessende Klammer.

      break;
  }
  strip.show();
}

Was mir noch nicht klar ist, was in den cases passiert.
Denn alle cases haben das Gleiche inhaltlich, ausser das default.
Wenn das wirklich so gedacht ist, kannst Du die cases überladen:
ungefähr so:

    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
      for (byte i = 0; i < 54; i++)
      {
        if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      break;

Besser so:

    case 1 ... 6:
      for (byte i = 0; i < 54; i++)
      {
        if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      break;

Dann sieht die Funktion so aus:


void cube(byte site)
{
  /*
    Seite 1 01 02 03 04 05 06 07 08 09 <> Seite 6 28 29 30 31 32 33 34 35 36
    Seite 2 10 11 12 13 14 15 16 17 18 <> Seite 5 37 38 39 40 41 42 43 44 45
    Seite 3 19 20 21 22 23 24 25 26 27 <> Seite 4 46 47 48 49 50 51 52 53 54
  */
  delay(50);
  switch (site)
  {
    case 1 ... 6:
      for (byte i = 0; i < 54; i++)
      {
        if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
        else strip.setPixelColor(i, 0, 0, 0);
      }
      break;
    default:
      strip.clear();
      strip.setPixelColor(0, 0, 0, 0);
      strip.setPixelColor(1, 255, 255, 255);
      strip.setPixelColor(2, 0, 0, 0);
      strip.setPixelColor(3, 255, 255, 255);
      strip.setPixelColor(4, 0, 0, 0);
      strip.setPixelColor(5, 255, 255, 255);
      strip.setPixelColor(6, 0, 0, 0);
      strip.setPixelColor(7, 255, 255, 255);
      strip.setPixelColor(8, 0, 0, 0);
      break;
  }
  strip.show();
}

Hab ich was übersehen?

Da habt ihr völlig Recht. Das mit dem Switch Case bei der Funktion cube() ist noch ein Überbleibsel vom Anfang. Da hatte ich noch jede Seite ein PixelMuster gegeben ala

      strip.clear();
      strip.setPixelColor(0, 0, 0, 0);
      strip.setPixelColor(1, 255, 255, 255);
      strip.setPixelColor(2, 0, 0, 0);
      strip.setPixelColor(3, 255, 255, 255);
      strip.setPixelColor(4, 0, 0, 0);
      strip.setPixelColor(5, 255, 255, 255);
      strip.setPixelColor(6, 0, 0, 0);
      strip.setPixelColor(7, 255, 255, 255);
      strip.setPixelColor(8, 0, 0, 0);

Eigentlich brauche ich da gar keine Switch Case abfrage mehr. Default wahr eigentlich am Anfang nur zum debugen, um zu erkennen das da was falsch läuft. Und die Würfelseiten sind inzwischen im Bitmuster Array hinterlegt und werden mit site angesprochen.

void cube(byte site) {
  /*
    Seite 1 01 02 03 04 05 06 07 08 09 <> Seite 6 28 29 30 31 32 33 34 35 36
    Seite 2 10 11 12 13 14 15 16 17 18 <> Seite 5 37 38 39 40 41 42 43 44 45
    Seite 3 19 20 21 22 23 24 25 26 27 <> Seite 4 46 47 48 49 50 51 52 53 54
  */
  delay(50);
  for (byte i = 0; i < 54; i++) {
    if (bitRead(Sequenz[site - 1], i)) strip.setPixelColor(i, red, green, blue);
    else strip.setPixelColor(i, 0, 0, 0);
  }
  strip.show();

Reicht völlig, da es entsprechend der erkannten Seite, die richtigen LEDs An bzw. Aus schaltet. Ich geh mal das mal testen. Aber sollte rein gedanklich funktionieren. Danke

uint64_t statt uint32_t ist einFehler. Hatte da einen falschen Wertebereich im Kopf. Danke

Funktioniert auch praktisch :slight_smile:

Und

Der Sketch verwendet 7198 Bytes (87%) des Programmspeicherplatzes. Das Maximum sind 8192 Bytes.
Globale Variablen verwenden 344 Bytes (67%) des dynamischen Speichers, 168 Bytes für lokale Variablen verbleiben. Das Maximum sind 512 Bytes.

Der Programmspeicher hat sich verringert. :slight_smile: Aber die Globalen Variablen haben sich erhöht? :thinking: Um ganze 48 Byte.

indexonsite hat zu jeder der 54 WS2812b die auf dem Würfel verbaut sind, den Index (Nummer der WS2812b zum ansprechen) der 4 Nachbar WS2812b hinterlegt. Da das ganze als Würfel aufgebaut ist, lässt sich das, für mich nicht ersichtlich, vereinfachen. Mal ein Bild wo die IndexNummern hinterlegt sind


Das wird benötigt für die viper() Funktion. Auf dem Würfel "bewegt" sich eine Schlange. Damit sie nicht in sich selber rennt, prüfe ich die benachbarten WS2812b, ob dort sich die Schlange befindet.

Andere Ideen dazu gern gesehen.

innhalb einer Würfelfläche ist die Reihenfolge gleich.
die Übergänge von einer Seitenkante zur anderen haben 90 Grad Drehungen.
Bisserl Hirnschmalz wird es brauchen. Aber imho lösbar.

du schreibst im code
{0,2,4,19}, //1

auf deiner Würfelzeichnung gibt es aber keinen Pixel 0.
Die Nachbarn von 1 müssten lt Zeichnung eigentlich 4, 2, 21 und 45 sein oder?

Möchtest Du mal das andere swiztch case austauschen mit dem folgendem:

switch (program)
{
case 0:
  cube(top);    // Sechs immer oben
  break;
case 1:
  randomdice(); // WürfelModus
  break;
case 2:
  fade();       // Farbwechsel nach Seite
  break;
case 3:
  fader();
  zufall();     // Disco ^^
  break;
case 4:
  fader();
  rainbow();    // Farbwechsel nach Regenbogen
  break;
case 5:
  full();
  flash();      // Zufälliges Aufblitzen
  break;
case 6:
  full();
  viper();      // Schlange
  break;
case 7:
  full();
  rain(top);    // Simuliert Regen
  break;
case 8:
  if (fadebrightness < brightness) fadebrightness = brightness;
  if (millis() - millis_merker > demotime && inaktiv)
  {
    program = 3;
    millis_merker = millis();
    fadebrightness = 0;
  }
  heartbeat();  // Simuliert Herzklopfen
  break;
}

void fader()
{
  if (millis() - millis_merker > demotime && inaktiv) // Wenn DemoZeit überschritten und der Würfel inaktiv erkannt hat
  {
    fadebrightness--;                               // Langsam ausdimmen um angenehmeren Übergang zu gewährleisten
    if (fadebrightness == 0)                        // Wenn Helligkeit auf 0 dann zum nächsten Program
    {
      program++;                                    // dann zum nächsten Program
      millis_merker = millis();
    }
  }
  else if (fadebrightness < brightness) fadebrightness++; // Ansonsten wenn Helligkeit unter MaxHelligkeit, Helligkeit erhöhen (Aufdimmen)
}

void full()
{
  if (fadebrightness < brightness) fadebrightness = brightness; // Mit voller Helligkeit starten
  if (millis() - millis_merker > demotime && inaktiv)
  {
    program++;
    millis_merker = millis();
  }
}

ungetestet und ohne Garantie, das das geht. - ich musste nebenbei kochen :wink:

Nachfrage:
ist das millis_merker hier richtig?

    if (fadebrightness == 0)                        // Wenn Helligkeit auf 0 dann zum nächsten Program
    {
      program++;                                    // dann zum nächsten Program
      millis_merker = millis();
    }

Sorry, im Bild hatte ich die WS2812b durchnummeriert bei 1 beginnend bis 54. Die Indexnummern sind aber von 0 beginnend bis 53.

Wenn du jetzt zu {0,2,4,19}, //1 jeweils 1 hinzufügst bist du bei {1,3,5,20}, //2 was dem Bild entspricht. Werde das mal in Incscape ändern. (Dachte das ich das eigentlich schonmal gemacht hatte, vermutlich noch nicht als png exportiert und dadurch das falsche hochgeladen).

Durch die Leiterplattenlage, die sich durch die Datenleitung ergibt, sind es leider nicht immer

Der ganze Würfel besteht nur aus 2 verschiedenen Leiterplatten (µC und POW). Ich finde da keine wirkliche Formel. Des weiteren gibt es Indexnummern, die an zwei verschiedene Leiterplatten angrenzen (z.B. 6). Bzw. Indexnummer die nur an eine Leiterplatte angrenzen (z.B. 7) oder sogar an keine angrenzen (z.B. 4).

Nochmal das Bild, jetzt mit Indexnummer, und nicht LEDs durchnummeriert. Sorry

Ja. Denn wenn das Programm gewechselt wird, wird das nächste Programm wieder in der eingestellten DemoTime angezeigt. Der Würfel geht, wenn Inaktivität erkannt wurde, nach 255 Sekunden in den Demo Modus. Dort wechselt er die Programme durch, und zeigt sie für 60 Sekunden. Die ersten Programme überspringe ich im Demo Modus, da sie statisch sind und nur auf äußere Aktion ihre Erscheinung ändern, was bei Inaktivität ja nicht gegeben ist. Damit ich prüfen kann, ob die DemoZeit abgelaufen ist, muss ich mir bei jeden Programmwechsel die millis() merken. Und speichere sie in millis_merker. (Und ja, bei dem FadeOut bleibt das Programm etwas länger aktiv, da erst nach 50 Veringerungen mal 5 Millisekunden Delay im Loop, also 250 Millisekunden später, der Wechsel ins nächste Programm erfolgt.)

Ok, dann ist das klar.

Ich würd trotzdem mal hören wollen, was das neue switch/case bringt, denn aus den 5 Wiederholungen sind es jetzt 2 geworden...

Bin noch am Testen. Hab es auch noch bissl geändert.

    switch (program) {
      case 0:
        full();
        cube(top);    // Sechs immer oben
        break;
      case 1:
        full();
        randomdice(); // WürfelModus
        break;
      case 2:
        full();       // Farbwechsel nach Seite
        break;
      case 3:
        fader();
        zufall();     // Disco ^^
        break;
      case 4:
        fader();
        rainbow();    // Farbwechsel nach Regenbogen
        break;
      case 5:
        full();
        flash();      // Zufälliges Aufblitzen
        break;
      case 6:
        full();
        viper();      // Schlange
        break;
      case 7:
        full();
        rain(top);    // Simuliert Regen
        break;
      case 8:
        full();
        heartbeat();  // Simuliert Herzklopfen
        break;
    }
  }
  delay(5);                                               // ganz kurze Pause um die Effekte etwas auszubremsen
}

void fader(){
  if (millis() - millis_merker > demotime && inaktiv){ 
    fadebrightness--;                               
    if (fadebrightness == 0){
      if (program == 8) program = 3;
      else program++;                                    
      millis_merker = millis();
    }
  }
  else if (fadebrightness < brightness) fadebrightness++;
}

void full(){
  if (fadebrightness < brightness) fadebrightness = brightness;
  if (millis() - millis_merker > demotime && inaktiv){
    if (program == 8) program = 3;
    else program++;                                    
    millis_merker = millis();
  }
}

Es haben auch die ersten drei Programme die Funktion mit der vollen Helligkeit bekommen. Denn wenn der Würfel aus dem Demo Modus zurück zu diesem statischen Programmen wechselt, wären diese dann mit geringerer Helligkeit. Hatte ich gar nicht bedacht.
Der Übersichtlichkeit habe ich auch dem letzten Programm das full() gegeben. Und den unterschiedlichen Wechsel mit in die full() und fader() gepackt. somit ist es universeller auf andere neue Programme anwendbar.

Was mir natürlich nicht gefällt, das dort versteckt Zahlen hinterlegt sind, sogar mehrfach, die das verantworten. Wahrscheinlich währe das irgendwie in eine Variable hinterlegt (oder Array zum Größe erkennen? (Vielleicht gleich ein Array mit den Programmen die im Demo Modus abgespielt werden? (Sorry, ich denke laut))) besser für spätere Anpassung programmiert.

Und während des Schreibens sind die Programme fehlerfrei durchlaufen, mit und ohne Faden :slight_smile: Danke

Edit: Der Wechsel zu dem Programm was vor dem starten des DemoModus aktiv war, wenn Aktivität erkannt wird, funktioniert nicht mehr. Kann, bzw. wird wahrscheinlich schon eher kaputt gewesen sein, da dieser Codeteil darauf eigentlich nicht zugreift. ich geh mal auf die Suche.

Edit 2: Gefunden, war schon vorher kaputt, bzw. hat noch nie richtig funktioniert :sweat_smile:
Der ADXL liefert nachdem er das erstmal Inaktivität nach 255 Sekunden ausspuckt, wieder nach 255 Sekunden den Interrupt für Inaktivität. Nunja, da ich jedes mal wenn da Inaktivität geliefert wird, das aktuelle Programm im ProgrammSpeicher ablege, wird also im Demo Modus immer aller 255 Sekunden das aktuelle Programm im ProgrammSpeicher abgelegt. Fiel beim testen nicht gleich auf, da ich dort nach kurzen verweilen im DemoModus Aktivität auf den Würfel brachte.
Ein Abfrage ob die Variable inaktiv schon vorher wahr ist, behebt das ganze. Hätte ich ohne die Umbauversuche wahrscheinlich erst viel später erkannt und dann wahrscheinlich auch sehr lange Gegrübelt warum. Danke

Ich würd das nicht mit einem else machen.

program++;                                        
if (program >= 9) program = 3;
    

Ich würde mit einem enum arbeiten.

sähe dann ungefähr aus:

enum Program {Six, Cube, Change, Disco, Rainbow, Flash, Snake,  Rain, Heart};

Program program;

switch (program)
// ab hier wie Dein Code war

switch (program)
{
case Six:
  full();
  cube(top);    // Sechs immer oben
  break;
case Cube:
  full();
  randomdice(); // WürfelModus
  break;
case Change:
  full();       // Farbwechsel nach Seite
  break;
case Disco:
  fader();
  zufall();     // Disco ^^
  break;
case Rainbow:
  fader();
  rainbow();    // Farbwechsel nach Regenbogen
  break;
case Flash:
  full();
  flash();      // Zufälliges Aufblitzen
  break;
case Snake:
  full();
  viper();      // Schlange
  break;
case Rain:
  full();
  rain(top);    // Simuliert Regen
  break;
case Heart:
  full();
  heartbeat();  // Simuliert Herzklopfen
  break;
}
}
delay(5);                                               // ganz kurze Pause um die Effekte etwas auszubremsen
}

void fader()
{
  if (millis() - millis_merker > demotime && inaktiv)
  {
    fadebrightness--;
    if (fadebrightness == 0)
    {
      nextProgramm();
    }
  }
  else if (fadebrightness < brightness) fadebrightness++;
}

void full()
{
  if (fadebrightness < brightness) fadebrightness = brightness;
  if (millis() - millis_merker > demotime && inaktiv)
  {
    nextProgramm();
  }
}

void nextProgramm()
{
  program++;
  if (program > Heart) program = Disco;
  millis_merker = millis();
}

Naja mach mal was draus :wink:
Speicher ist ja frei geworden...

Nicht wirklich :frowning:

Der Sketch verwendet 7544 Bytes (92%) des Programmspeicherplatzes. Das Maximum sind 8192 Bytes.
Globale Variablen verwenden 300 Bytes (58%) des dynamischen Speichers, 212 Bytes für lokale Variablen verbleiben. Das Maximum sind 512 Bytes.

Geht da eigentlich auch: (Edit: Ja geht auch :slight_smile: )

if (++program >= 9) program = 3;

Ok, statt zu fragen könnt ich einfach selber testen.

Habe ich noch nie, Ich nehme mir mal die Zeit mich da einzulesen.

Edit:
Wenn ich das richtig verstehe, werden Zahlen Worte zugewiesen. Mit diesen Worten kann man dann rechnen, als währen sie Zahlen. Die Worte bekommen den Zahlwert wie durchnummeriert. Man kann auch den Startwert bestimmen.
Aber ich erkenne den Vorteil nicht. Ich muss immer noch unten in den Funktionen angeben, welche das letzte Programm ist. Und auch dort beim erreichen eines bestimmten Programms zu einem anderen springen.
Am liebsten wäre es mir oben die Anzahl der Programme anzugeben. Dann ala SizeOf oder ähnlichen zu prüfen ob das höchste Programm erreicht ist. Vielleicht auch oben hinterlegen, welche Programme im DemoModus sind, und diese zu durchlaufen wenn man sich in diesem befindet. So das alle Änderungen an oben im Code stattfinden.

Hi,

Genau so wie Du nicht mit D1, D2, ... A0, A1... arbeiten möchtest, und lieber Bezeichnungen zuweist, mit denen Du auch am nächsten Tag beim programmieren noch was anfangen kannst, sind es hier dann eben enum {Schell, Herz, Blatt, Eichel}; anstatt 1,2,3,4

Gruß André

Kann man. Sollte man aber nicht. Jedenfalls wenn man "rechnen" wörtlich nimmt und wirklich Arithmetik meint. Man sollte sein Programm so schreiben dass es egal ist welcher Wert wirklich dahinter steckt.
Für Vergleiche - gerade bei Zuständen - ist es aber sehr praktisch

Dann die Frage nach dem Speicher. Habe bei enum etwas von int gelesen. Belegt dann jeder dieser Wörter ein Speicher von 2 Byte? Ich vermute aber eher das alles 2 Byte groß ist. Konnte dazu nicht wirklich etwas finden.
Was passiert beim „Überlauf“, also wenn ich um eins erhöhe? Kommt dann die nächst höhere Zahl wo noch kein Wort zugewiesen ist oder springt es zurück zum ersten Wort? Kann man bei enum auch mit siteOf arbeiten? Also die Anzahl der Wörter die hinterlegt sind Abfragen?
Ich werde wohl erst ein bissl experimentieren in einem extra Sketch, und diesen bei Seite legen.

Datentypen:
https://spacehal.github.io/docs/arduino/variable/
(wobei double auf 8 Prozessoren das gleiche wie float ist und nicht 64 Bit hat)

Nach dem höchsten Wert geht es beim niedrigsten weiter

Es ging um enum. Ist dies dort genauso? Bin gerade unterwegs.

Das C++ Buch!

Zudem kann man enum mittlerweile auch strenger typisieren. So dass man insgesamt auf ein Byte kommt.

Das wird überhaupt nicht geschehen.