Sternenhimmel funktioniert nicht - Speicherprobleme?

Hallo erstmal,

also ich habe gestern Abend meine Mammutprojekt "fast" fertiggestellt.
Es handelt sich dabei um einen Sternenhimmel mit ca. 300m Glasfaser die als Sterne leuchten sollen.
Angestrahlt wird jede Glasfaser von einer WS2811er LED.
Somit sind in 7 Tagen harter Arbeit (die letzten 3 Tage mit jeweils nur 4 Stunden Schlaf) etwa 520 Sterne entstanden mit einer Deckenkonstruktion die etwa 70kg wiegt.
Das Ganze war als Überraschung meiner im Urlaub gewesenen Freundin gedacht.

Leider hat es jedoch nicht geklappt:
Zum Einen, weil die Schrauben die das Teil halten sollen in der Eile wohl etwas schief in die Decke gebohrt wurden und die Konstruktion nicht gepasst hat.
Zum Anderen, weil das Arduino nichts tut.

Alles nicht so das gelbe vom Ei, weil es leider aus Zeitmangel die letzten 3 Tage schnell gehen musste.
Das kam daher, weil die Glasfaser 11 Tage ab Zahlungseingang bis zu mir brauchten.
Als Lieferzeit wurden 1-3 Werktage angegeben -.-
Zum anderen hat mich mein Schreiner entgegen unserer Absprache hängen lassen und am Tag 1 doch schon pünktlich Feierabend gemacht, bevor er mir die 12 Zuschnitte, davon 2 unterschiedliche Längen, gemacht hat. (ich kam um 16:10 an und er meinte er würde bis 16:30 auf mich warten).
Am Tag 2 hat er dann das Holz nach 5 Stunden versägt und ich musste neues kaufen und ihm bringen und weitere 3 Stunden warten. Dafür hat er dann 50€ gewollt, weil ers ja "zweimal machen musste".
Problem ist gewesen, dass er die Gährung auf der falschen Kante geschnitten hat.
Unsere Meinung über das Verursachen des Fehlers weicht natürlich ab.
Das Holz wollte er mir natürlich nur gegen Bezahlung aushändigen - aus Zeitnot habe ich dass dann auch machen müssen.
Bei der Montage musste ich dann (abgesehen von einem 4cm langen Fehlschnitt an einer Gähruung) feststellen, dass die Gährung nicht mal sauber gearbeitet war. Für das nächste mal kaufe ich mir das Werkzeug selbst. Der Schreiner war mit ca. 30€ geplant - daraus sind 50€ + 22€ für die zweite Ladung Holz gewesen. Das eigentliche Ziel, Zeitersparnis und sicher saubere Arbeit wurde NICHT erreicht und mein Fazit steht fest:
Das einzige Geld was ein Schreiner jemals von mir zu sehen bekommen wird, ist dass was ich an der Kasse beim Supermarkt der/dem Kassierer/in gebe, wenn er zufällig hinter mir in der Schlange steht.
Somit konnte ich erst am Tag 3 da beginnen, wo ich schon bei Tag 1 hätte sein sollen.
Zu allem Überfluss kamen die Glasfasern dann auch noch mit Produktionsschwankungen an.
Die 0,75mm Faser, für die ich über das Wochenende die 280 0,8mm Löcher gebohrt hatte, war unterschiedlich dick.
Die Glasfaserrolle als lfm. hatte einen 0,75 bis (geschätze) 0,9mm Durchmesser. Auch ein mehrfaches nachbohren mit dem 0,8mm Bohrer (und leichtes seitliches wackeln) brachte dann an der Verdickung nichts mehr und es musste NOCHMAL mit einem 1,1mm Bohrer alle Löcher nachbohren!
Allein dafür war ein weiterer Tag weg - und das zu einem Zeitpunkt, wo ich alle Vorarbeiten aufgrund der nicht ankommenden Glasfaser so gemacht hatte, dass es nur noch hätte eingesteckt werden müssen.
Die Glasfaser kam diesen Montag um 11:00 bei mir an.
Geplante Fertigstellung des gesamten Projekts war gestern, Mittwoch 20:00 - und um 23:00 hat es nicht gepasst und nicht mit dem Sketch funktioniert.
Dann musste ich meine Freundin vom Flughafen abholen und hatte als Überraschung eine komplett verdreckte Wohnung...

Ich ärgere mich am meisten darüber, dass ich nun am Ende aus Zeitdruck Pfuschen musste, weil jeweils andere mir 3 von 6,5 Tagen geraubt haben.

Nun aber zum Problem:
Mein Testsketch mit 50 LEDs funktionierte.
Als ich den Sketch auf meine ca. 150 LEDs angepasst habe, klappte gar nichts mehr. (kein leuchten)

Ich vermute sehr stark, dass hier der Speicher das Problem ist.
Abgesehen von 8 byte Variablen und 4 booleans habe ich diesen Ausdruck hier:

CRGB leds[NUM_LEDS];

und jetzt der Killer:

//zum speichern der LED helligkeiten: [0] = istWert; [1] = sollWert beim funkeln; [2] = Farbwert; [3] = Sättigung:
int memory [NUM_LEDS][4];
  • Also 600 weitere Byte Variablen.

Das Problem ist, dass der Sternenhimmel nicht statisch leuchtet und diese Werte definitiv braucht, um so zu funktionieren, wie er soll.
Ich brauche also wirklich zu jeder LED vier 255Bit große Speicherbereiche.

Verwendet wird ein Ardunio UNO, dass eigentlich auch schon zu groß ist.
Ein Mega kommt also nicht in Frage.
Von unten hat man ein Loch mit einem 64mm Durchmesser und nur 4cm Abstand nach oben - ein Mega würde also nicht mehr aus der Konstruktion raus kommen können Zwecks Wartung/Erweiterung.

Dazu gesellt sich ein Soundmodul, dass beim Klatschen unterschiedliche Programme startet.
Die Arduino IDE zeigt an:
Binäre Sketchgröße: 9.780 Bytes (von einem Maximum von 32.256 Bytes)

Ich hoffe ihr könnt mir weiterhelfen und sagen ob der Speicher das Problem wirklich ist und was für Alternativen es nun gibt.
Vielen Dank!

Wenn es denn tatsächlich der Speicher ist und die Baugröße eine Rolle spielt, könntest du einen Teensy 3.1 verwenden. Gibts für wenig Geld bei Watterott und Exp-Tech. Das ist aber ein Mikrocontroller mit 3,3V, vielleicht sollte man dann noch den OctoWS2811-Adapter dazunehmen.

http://www.exp-tech.de/Shields/LED-Controller/OctoWS2811-Teensy-Adapter.html

Wie waere es, wenn Du mal den kompletten Sketch zeigst?

Verstehe ich richtig: Mit wenigen LEDs funktioniert es, wenn Du NUM_LEDS erhoehst, laeuft der Sketch nicht mehr?

Gruesse

Helmuth

edit: Und ja, 450 Byte fuer das CRGB plus 600 Byte belegt schon ueber die Haelfte vom RAM des Uno. Du kannst versuchen, z.B. das Temporal Dithering zu deaktivieren, um Speicher zu sparen oder deinen Sketch umzuschreiben.

Ein Teensy fuer 150 blinkende LEDs ist zwar mit so, wie mit einer Kanone auf einen Spatz zu schiessen, aber moeglicherweise ist allein die kleine Bauform ein Argument.

Bitte schlagt mich nicht für teilwese fehlende Kommentare oder noch debugging Sachen - das konnte ich aus Zeitmangel nicht so wie es SOLLTE :slight_smile:

Hier der Sketch Teil1:

//------------------------------------Initialisierung zum funkeln --------------------------------//  
#include "FastSPI_LED2.h"
//#include <FastLED.h> // HIERMIT GEHT DAS  FastLED.clear(); NICHT!

#define NUM_LEDS 150
#define DATA_PIN 3

CRGB leds[NUM_LEDS];
boolean ledsOn = 0;

byte ledHelligkeit = 0;
byte ledPulseWeite = 0;
byte ledHellerOderDunkler = 0;

//zum speichern der LED helligkeiten: [0] = istWert; [1] = sollWert beim Pulsieren; [2] = Farbwert; [3] = Sättigung:
int memory [NUM_LEDS][4];

//wird benötigt um ein delay ohne delay() zu realisieren. Statt dessen wird geprüft ob randomDelay >=1 ist und erst wenn es abgelaufen ist, wird weiter gemacht. So kann das programm schneller auf andere Einflüsse reagieren.
byte randomDelay= 0;  

//------------------------------------Initialisierung zum Klatschen erkennen, zählen und auswerten---------------------------------//  

#define SOUNDPIN  2 // Ausgang des LM393 mir DigitalPin 2 des Arduinos verbinden

// onboard-LED zum Debugging
#define LEDPIN    13 

#define intervallMax 600 // millisekunden; für maximal erlaubte Länge zwischen dem Kltaschen 
#define intervallMin 100  // millisekunden; um den Eingang zu "entprellen" (es wird sonst pro Klatsch 6x registriert)


byte tempKlatschCount = 0;
byte klatschAnzahl=0;

byte Modus=0;  // Modus0 = aus, Modus1 = funkeln, Modus2 = herz;
boolean AnOderAus = false;






//------------------------------------LEDs die den zweiten Modus darstellen ------------------------------//  


byte besondereLED[]={0,2,3,5,8,9,11,13,16,17,23,24,25,28,30};
byte anzahlBesondereLeds = sizeof(besondereLED) / sizeof(byte);;




//------------------------------------Funkeln---------------------------------//  
void funkeln(int thisFarbwert, int thisSaettigung, int thisMinHelligkeit, int thisMaxHelligkeit, int thisMinDelay, int thisMaxDelay, int thisMinPulse, int thisMaxPulse)
{
  //wenn die leds an sind "funkeln"
  if(ledsOn == true)
  {
    //Warten bis die Delayzeit augelaufen ist. Dies wird hier mittels if abfrage statt mittels delay(randomDelay); gemacht, damit das Programm nicht "wartet" und schnell auf andere Einflüsse reagieren kann.
    if(randomDelay >= 1)
    {
      randomDelay = randomDelay - 1;
    }
    else
    {
      for(int i=0; i < NUM_LEDS ; i++)
      {    
                     
        //wenn die LED noch nicht ihr Puls-Ziel erreicht hat...

        if(memory[i][0]!=memory[i][1])
        {
          //wenn die LED heller pulsieren soll
          if(memory[i][0] < memory[i][1])
          {
            leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] + 1);  
            //HSVtoRGB(thisFarbwert, thisSaettigung, ibright, color);   
            memory[i][0] = memory[i][0] + 1;        
          }         
          //wenn die LED dunkler pulsieren soll
          else
          {     
           leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1);      
           memory[i][0]= memory[i][0] - 1;          
          }               
        }
        //wenn die LED ihr Puls-Ziel erreicht hat neuen Puls anfangen...
        else
        {

          // entscheiden ob die led in diesem Durchlauf pulsieren soll: gleichbleiben=0, heller=1, dunkler=2
          ledHellerOderDunkler = random( 0, 3);

          //heller werden
          if(ledHellerOderDunkler == 1)
          {    
            ledPulseWeite= random( thisMinPulse, thisMaxPulse + 1);
            
            //prüfen ob die maximale helligkeit überschritten wird
            if(memory[i][0] + ledPulseWeite < thisMaxHelligkeit)
            {          
              //wenn der Farbwert nicht erreicht ist (weil vom Herz-Modus noch anders gefärbt)
              if ( (memory[i][2]) > thisFarbwert)
              {
                memory[i][2] = memory[i][2] - 1; //farbwert anpassen 
              }
              else if ( (memory[i][2]) < thisFarbwert)
              {
                memory[i][2] = memory[i][2] + 1; //farbwert anpassen 
              }
              
              //wenn nicht die Ziel-Sättigung erreicht ist
              if ( (memory[i][3]) > thisSaettigung)
              {
                memory[i][3] = memory[i][3] - 1; //sättigung anpassen
              }
              else if ( (memory[i][3]) < thisSaettigung)
              {
                memory[i][3] = memory[i][3] + 1; //sättigung anpassen
              }

              //eins heller werden und ggf. farbe und sättigung anpassen            
              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] + 1);
              
              //merken bis zu welcher helligkeit diese LED in den nächsten Durchgängen pulsieren soll
              memory[i][1] = memory[i][0] + ledPulseWeite;
              
              //neuer Istwert speichern
              memory[i][0] = memory[i][0] + 1;
            }
          }
                  
          //dunkler werden
          if(ledHellerOderDunkler == 2)
          {                
                 
            ledPulseWeite= random( thisMinPulse, thisMaxPulse + 1);
            
            //prüfen ob die minimale helligkeit unterschritten wird
            if(memory[i][0] - ledPulseWeite > thisMinHelligkeit)
            {         
              //wenn der Farbwert nicht erreicht ist (weil vom Herz-Modus noch anders gefärbt)
              if ( (memory[i][2]) > thisFarbwert)
              {
                memory[i][2] = memory[i][2] - 1; //farbwert anpassen 
              }
              else if ( (memory[i][2]) < thisFarbwert)
              {
                memory[i][2] = memory[i][2] + 1; //farbwert anpassen 
              }
              
              //wenn nicht die Ziel-Sättigung erreicht ist
              if ( (memory[i][3]) > thisSaettigung)
              {
                memory[i][3] = memory[i][3] - 1; //sättigung anpassen
              }
              else if ( (memory[i][3]) < thisSaettigung)
              {
                memory[i][3] = memory[i][3] + 1; //sättigung anpassen
              }

              //eins dunkler werden und ggf. farbe und sättigung anpassen
              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1);     
                                      
              //merken bis zu welcher helligkeit diese LED in den nächsten Durchgängen pulsieren soll
              memory[i][1] = memory[i][0] - ledPulseWeite;  

              //neuer Istwert speichern
              memory[i][0] = memory[i][0] - 1;        
            }           
          } 
        } 
      }
      
      //da in diesem Durchlauf das Delay bereits bei 0 war und gefunkelt wurde, ein neues Delay erzeugen, damit es weiterhin zufällig bleibt.
      randomDelay = random(thisMinDelay, thisMaxDelay + 1); 
      
    }    
  }
  //wenn die leds noch aus sind - helligkeiten für LEDs bestimmen
  else
  {
     for(int i=0; i < NUM_LEDS ; i++)
     {
       ledHelligkeit = random( thisMinHelligkeit, thisMaxHelligkeit+1); 
       leds[i] = CHSV( thisFarbwert, thisSaettigung, ledHelligkeit);  
              
       //hier das geht evtl nicht... array nicht lang genug
       memory[i][0] = ledHelligkeit;
       memory[i][1] = ledHelligkeit;
       
       //Farbwert im array speichern um bei späteren Farbwechsel zu wissen welche LED in welcher farbe leuchtet
       memory[i][2] = thisFarbwert;
       //Sättigung im array speichern um bei späteren Farbwechsel zu wissen welche LED mit welcher Sättigung leuchtet
       memory[i][2] = thisFarbwert;
       
     }
     //AnOderAus=true;
    ledsOn=true;
  }
  
  //LEDs leuchten lassen
  LEDS.show();  
}


//------------------------------------zum prüfen ob LED Teil der Menge BesondereLED ist--------------------------------//  
bool containsElement(byte* array, byte element)
{
    for(int i = 0; i < anzahlBesondereLeds; i++)
    {
          if(array[i] == element)
               return true;
    }
    return false;
}

Teil2:

//------------------------------------Besonderer Modus---------------------------------//  
void  besondererModus(int thisMinHelligkeit, int thisMaxHelligkeit, int thisMinDelay, int thisMaxDelay, int thisMinPulse, int thisMaxPulse)
{

    //Warten bis die Delayzeit augelaufen ist. Dies wird hier mittels if abfrage statt mittels delay(randomDelay); gemacht, damit das Programm nicht "wartet" und schnell auf andere Einflüsse reagieren kann.
    if(randomDelay >= 1)
    {
      randomDelay=randomDelay-1;
    }
    else
    {
      for(int i=0; i < NUM_LEDS ; i++)
      {  
    
        
        //prüfen ob die LED zum besonderen Modus gehört
        if (containsElement(besondereLED,i))
        {

          
          //wenn die LED noch nicht ihr Puls-Ziel erreicht hat...
          if(memory[i][0]!=memory[i][1])
          {
            
            //wenn noch nicht komplett rot
            if ( (memory[i][2]) > 0)
            {
              memory[i][2] = memory[i][2] - 1; //roter leuchten 
            }
                
            //wenn noch nicht komplett gesättigt
            if ( (memory[i][3]) < 255)
            {
              memory[i][3] = memory[i][3] + 1; //satter leuchten
            }
            
            
            
              
            //wenn die LED heller pulsieren soll
            if(memory[i][0] < memory[i][1])
            {  
              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] + 1);
              //leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] + 1); 

              memory[i][0] = memory[i][0] + 1; 
 
            }         
            //wenn die LED dunkler pulsieren soll
            else
            {    

              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1); 
       
              memory[i][0] = memory[i][0] - 1;   
    
            }               
          }
          //wenn die LED ihr Puls-Ziel erreicht hat neuen Puls anfangen...
          else
          {
            

            // entscheiden ob die led in diesem Durchlauf pulsieren soll: gleichbleiben=0, heller=1, dunkler=2
            ledHellerOderDunkler = random( 0, 3);
            //heller werden
            if(ledHellerOderDunkler == 1)
            {    
              ledPulseWeite= random( thisMinPulse, thisMaxPulse + 1);
              
              //prüfen ob die maximale helligkeit überschritten wird
              if(memory[i][0] + ledPulseWeite < thisMaxHelligkeit)
              {       
                //wenn noch nicht komplett rot
                if ( (memory[i][2]) > 0)
                {
                  memory[i][2] = memory[i][2] - 1; //roter leuchten 
                }
                
                //wenn noch nicht komplett gesättigt
                if ( (memory[i][3]) < 255)
                {
                  memory[i][3] = memory[i][3] + 1; //satter leuchten
                }
                
                //eins heller werden        
                leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] + 1); 
                
                //merken bis zu welcher helligkeit diese LED in den nächsten Durchgängen pulsieren soll
                memory[i][1] = memory[i][0] + ledPulseWeite;
                            
              //neuer Istwert speichern
                memory[i][0] = memory[i][0] + 1;     
                
              }
            }
                     
            //dunkler werden
            if(ledHellerOderDunkler == 2)
            {                
                   
              ledPulseWeite= random( thisMinPulse, thisMaxPulse + 1);
              
              //prüfen ob die minimale helligkeit unterschritten wird
              if(memory[i][0] - ledPulseWeite > thisMinHelligkeit)
              {          
                
                //wenn noch nicht komplett rot
                if ( (memory[i][2]) >0)
                {
                  memory[i][2] = memory[i][2] - 1; //roter leuchten 
                }
                
                //wenn noch nicht komplett gesättigt
                if ( (memory[i][3]) < 255)
                {
                  memory[i][3] = memory[i][3] + 1; //satter leuchten
                }
              
                
                //eins dunkler werdenen             
                leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1);  
                // HSVtoRGB(thisFarbwert, thisSaettigung, ibright, color);
              
                //merken bis zu welcher helligkeit diese LED in den nächsten Durchgängen pulsieren soll
                memory[i][1] = memory[i][0] - ledPulseWeite;    

              //neuer Istwert speichern
                memory[i][0] = memory[i][0] - 1;       
              }           
            }                             
          }  
        }
        else
        {     
          
          //wenn die LED noch nicht ihr Puls-Ziel erreicht hat...
          if(memory[i][0]!=memory[i][1])
          {


            //wenn die LED heller pulsieren soll
            if(memory[i][0] < memory[i][1])
            {
              
              leds[i] = CHSV(memory[i][2], memory[i][3], memory[i][0] + 1);  
              //HSVtoRGB(thisFarbwert, thisSaettigung, ibright, color);   
              memory[i][0] = memory[i][0] + 1;     

            }         
            //wenn die LED dunkler pulsieren soll
            else
            {     
              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1);      
              memory[i][0]= memory[i][0] - 1;      
          
            }               
          }
          //wenn die LED ihr Puls-Ziel erreicht hat und NICHT AUS IST neuen Puls anfangen...
          else if ( (memory[i][0] == memory[i][1]) && (memory[i][0] != 0))
          {
            //dunkler werden   
            ledPulseWeite= random( thisMinPulse, thisMaxPulse + 1);
            
            //prüfen ob die minimale helligkeit unterschritten wird
            if(memory[i][0] - ledPulseWeite >= 0)
            {          
              //eins dunkler werden
              leds[i] = CHSV( memory[i][2], memory[i][3], memory[i][0] - 1);  
              // HSVtoRGB(thisFarbwert, thisSaettigung, ibright, color);
              
              //merken bis zu welcher helligkeit diese LED in den nächsten Durchgängen pulsieren soll
              memory[i][1] = memory[i][0] - ledPulseWeite;     
              memory[i][0] = memory[i][0] - 1;               
            }
            else
            {
             memory[i][1] =0; 
            }                         
          }     
        } 

        //debuging
        if(i==5)
        { 
          Serial.print("IST-Helligkeit: ");
          Serial.print(memory[i][0]);
          Serial.print(" | Soll-Helligkeit: ");
          Serial.print(memory[i][1]);
          Serial.print(" | Farbe: ");
          Serial.print(memory[i][2]);
          Serial.print(" | Saettigung: ");
          Serial.print(memory[i][3]);  
          Serial.print(" | Modus: ");
          Serial.println(Modus);  
        }     
      }
      
      //da in diesem Durchlauf das Delay bereits bei 0 war und gefunkelt wurde, ein neues Delay erzeugen, damit es weiterhin zufällig bleibt.
      randomDelay = random(thisMinDelay, thisMaxDelay+1);   
      
    }    
   
  //LEDs leuchten lassen   
  LEDS.show();  

}

Teil3:

//------------------------------------Setup---------------------------------//  
void setup() 
{
  pinMode(SOUNDPIN, INPUT);
  // onboard-LED zum Debugging
  pinMode(LEDPIN, OUTPUT);
  Serial.begin(9600);    
  Serial.println("Test:");  
  
  
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);

}

void loop()
{
  
  //------------------------------------Klatschen erkennen, zählen und auswerten---------------------------------//  
  static unsigned long lastKlatschTime=0; // Zum merken der Zeit, wann zuletzt geklatsch wurde
  if (digitalRead(SOUNDPIN)==LOW && millis()-lastKlatschTime>intervallMin)
  {
    tempKlatschCount++;
    lastKlatschTime=millis();
    Serial.println ("Klatsch!"); // Ausgabe das geklatscht wurde
  } 
  if (millis()-lastKlatschTime>intervallMax)
  {
    if (tempKlatschCount>0)
    {
      Serial.print(tempKlatschCount);  // Ausgabe wir oft geklatscht wurde
      Serial.println(" mal geklatscht"); // Ausgabe wir oft geklatscht wurde
      
      
      klatschAnzahl = tempKlatschCount;  // Modus anhand der Klatschzahl setzen.
    }
    tempKlatschCount=0;
    lastKlatschTime=millis(); // Zähler mitziehen um Probleme mit Timerüberlauf zu vermeiden
  }



  //----------------------------------zweimal Klatschen zum Ein- und Ausschalten---------------------------------//  
  
  
  if (klatschAnzahl==2 && AnOderAus==true) 
  {
    // onboard-LED zum Debugging
    // digitalWrite(LEDPIN, LOW);
 
    klatschAnzahl=0; 
    Modus=0;
    
    Serial.print("Klatsch Anzahl: "); 
    Serial.println(klatschAnzahl);
    Serial.print("Modus: "); 
    Serial.println(Modus);
  }  
  

  if (klatschAnzahl==2 && AnOderAus==false) 
  {
    // onboard-LED zum Debugging
    // digitalWrite(LEDPIN, HIGH);

    klatschAnzahl=0; 
    AnOderAus=true;
    Modus=1;
    
      
    Serial.print("Klatsch Anzahl: "); 
    Serial.println(klatschAnzahl);
    Serial.print("Modus: "); 
    Serial.println(Modus); 
  }
  
  

  
  
//----------------------------------dreimal Klatschen zum besonderen Modus Ein- und Ausschalten---------------------------------//   

  if (klatschAnzahl >= 3 && AnOderAus==true && Modus==1) 
  {
    
     // onboard-LED zum Debugging
     digitalWrite(LEDPIN, HIGH);
    
    
    klatschAnzahl=0; 
    Modus=2;
    
    Serial.print("Klatsch Anzahl: "); 
    Serial.println(klatschAnzahl);
    Serial.print("Modus: "); 
    Serial.println(Modus); 
  }
  
  
  if ((klatschAnzahl >= 3) && (AnOderAus==true) && (Modus==2)) 
  {
    // onboard-LED zum Debugging
     digitalWrite(LEDPIN, LOW);
    
    
    //Hier von besonderen Modus auf  funkeln wechseln
    
    klatschAnzahl=0; 
    Modus=1;
    
    Serial.print("Klatsch Anzahl: "); 
    Serial.println(klatschAnzahl);
    Serial.print("Modus: "); 
    Serial.println(Modus); 
  }  
  
  

  
//-------------------------------------------------Modi---------------------------------------------//
  
  
  //ausschalten
  if (AnOderAus==true && Modus==0)
  {   
    //das dauert zu lange
    FastLED.clear();
    AnOderAus=false;
  }  
   
  //funkeln
  if (AnOderAus==true && Modus==1)
  {
    // HSVtoRGB(thisFarbwert, thisSaettigung, thisMinHelligkeit, thisMaxHelligkeit, thisMinDelay, thisMaxDelay, thisMinPulse, thisMaxPulse);
        funkeln(    133,           20,           70,                250,            10,              70,             6,            25);
        //funkeln(    135,           130,           40,                170,            0,              70,             0,            18);  
  }
  
  //besonderer Modus
  if (AnOderAus==true && Modus==2)
  {
    // HSVtoRGB(thisMinHelligkeit, thisMaxHelligkeit, thisMinDelay, thisMaxDelay, thisMinPulse, thisMaxPulse);
           besondererModus(      70,                170,            0,              70,             0,            18); 
  }
  
}

Bis wieviele LEDs funktioniert das?

Haette spontan die Idee, nur 10-20 HSV Koplettsets zu speichern und die wiederholt fuer alle LEDs zu verwenden.

Alternativ nur ein einziges Set und alle anderen LEDs in Relation dazu definieren. Die Bytes sind implizit gecasted, d.h. zu kannst z.B auch sowas machen:

leds[i] = CHSV( memory[i][2] + i, memory[i][3] - i, memory[i][0] + 2 * i )

Leon333:
und jetzt der Killer:

//zum speichern der LED helligkeiten: [0] = istWert; [1] = sollWert beim funkeln; [2] = Farbwert; [3] = Sättigung:

int memory [NUM_LEDS][4];



- Also 600 weitere Byte Variablen.

Das sind 600 Variablen vom Typ "int" zu je zwei Bytes = 1200 Bytes.

Mit

byte memory [NUM_LEDS][4];

wären es 600 Variablen vom Typ "byte" zu je ein Byte = 600 Bytes.

Die IDE 1.5XXX zeigt den Ramverbrauch (ohne Stack, der wächst zur laufzeit)

 Serial.print("Klatsch Anzahl: ");

Besser so:

Serial.print(F("Klatsch Anzahl: "));

Das spart nochmal einiges an Ram

Den RAM - Bedarf während der Laufzeit ( solange es noch läuft ) kann man sich auch leicht anzeigen lassen, und die Auswirkung von NUM_LEDS Änderungen ansehen.
Zuletzt auf Deutsch hier diskutiert: Programmoptimierung: SRAM sparen - #2 by guntherb - Deutsch - Arduino Forum

Also erstmal:

VIELEN DANK euch allen!
Jurs, du bist der Hammer...

Bei soviel Code verliert man beim debuggen schnell mal die Übersicht.
Ich war fest davon überzeugt, dass ich sie als byte initialisiert habe und habe daher gar nicht mehr an dieser Stelle nachgeschaut.
Die Umstellung auf byte hat die LEDs zum leben erweckt... alle.
Das bedeutet auch, dass ich beim löten und verkabeln keinen Fehler gemacht habe (puhhh!!).

Ich lasse mir gerade den freien Ram mit anzeigen. (danke michael_x)
Jede LED nimmt zusätzliche 11 Byte Ram weg.

Seltsamerweise funktioniert der Sketch bei genau 129 LEDs nicht mehr.
Bei 128 LEDs zeigt mir der SM noch 136 freie Byte an.

Es kann also nicht allein der Ram sein oder?
Weil bei 129 LEDs müsste ich ja noch 125 Byte Ram haben.
Es könnte auch sein, dass sich das Programm wegen den Seriellen Ausgaben aufhängt....

Ich habe außerdem alle Strings die Seriell ausgegeben werden per
Serial.print(F("String"));
ausgegeben.

Das hat mir 146Byte Ram erspart und ich bin dann auf insgesamt bei 282 Byte gewesen.

Danach habe ich die LEDanzahl wieder erhöht.

Bei 148 LEDs zeigte mir der SM folgendes an:

freies RAM: 16863
freies RAM: 17375
freies RAM: 17375
freies RAM: 16607
freies RAM: 16863
freies RAM: 17375
freies RAM: 17375
freies RAM: 16607

Kann das jemand erklären?

Bei 147 habe ich noch genau 95 Byte frei.
Da funktioniert der Sketch gerade noch - bei 148 die oben gezeigte Problematik mit den komischen RAMwerten.
Ich gehe davon aus, dass der Sketch ab da nicht mehr funktioniert.

Seltsam finde ich, dass der Sketch nicht mehr geht, obwohl ja noch RAM verfügbar ist.

Nun aber zum wesentlichen:
Ich habe genau 139LEDs.
Das heißt es würde sogar ohne den wichtigen Hinweis von jurs klappen, dank combies Hinweis auf das printf.

Bei 139 LEDs ging es mit meinem Code gerade so nicht mehr (nur bis 128), obwohl noch 125 Byte Ram da sein müssten.
Mit print(F( komme ich auf 161 Byte freien Ram bei 139 LEDs und der Sketch funktioniert.
Mit der Umstellung des Killer-Arrays von int auf byte komme ich nun bei 139 LEDs auf 717 freie Byte.
Super!

Bei 147 habe ich noch genau 95 Byte frei.
Da funktioniert der Sketch gerade noch - bei 148 die oben gezeigte Problematik mit den komischen RAMwerten.
Ich gehe davon aus, dass der Sketch ab da nicht mehr funktioniert.

Du brauchst immer etwas Ram für den Stack.
Der AVR Stackpointer ist doof. Keinerlei Speicherschutz.
Wächst der Stack zu sehr an, wird erst der Heap und dann die statischen Daten Bereiche überschrieben.
Und schon stehen die lustigsten Erscheinungen in der Tür.

Siehe zur Speichernutzung: http://jeelabs.org/2011/05/22/atmega-memory-use/

Wenn du Funktionen aufrufst werden:
1.) Register auf dem Stack gesichert und die Rücksprung-Adresse abgespeichert
2.) Lokale Variablen innerhalb der Funktion dort gespeichert!

Also bitte nicht den Speicher bis aufs letzte Byte belegen. Du brauchst immer eine Reserve für den restlichen Programmablauf.

Ich habe jetzt den Sketch soweit angepasst, wie ich ihn brauche.
ich habe noch 659 Byte frei.
Sollte also passen.

Ich werde die Tage noch etwas testen müssen und noch das ein oder andere verbessern und anpassen.

ich danke euch jedenfalls sehr jungs!

Das ist wirklich eine der effektivsten communitys in der ich unterwegs bin!

Mach mal ein Photo / Video von der Installation in Aktion!

Gruesse

Helmuth

Werde ich machen.
Momentan steht das Teil noch an der Wand (angelehnt).
Ich muss noch ein paar sachen fixen, bevor es an die Decke kommt (unter anderem die abgerissene Tapete, die bei der ersten "hau-ruck-aktion" schaden genommen hat).
Danach steht nur noch das "Klatschen erkennen" an, da das noch sehr unzuverlässig funktioniert.
Eigentlich will ich: 2x Klatschen = AN/AUS, 3x Klatschen = Modus wechsel.

Leider funktioniert schon das Klatschen erkennen nicht zuverlässig.
Ein kleiner Vorgeschmack:
Video

Nice!

Wegen dem Klatschschalter: Ich nehme an, das die mit AnaogRead gelesenen Werte ziemlich "flattern". Versuche es doch mal mit einer Debounce Logik. Wenn was oberhalb des Schwellwertes erkannt wird, erstmal 150mS (oder laenger - bis der Hall verklungen ist) warten und dann nochmal lauschen. Wenn wieder Signal (= 2x geklatscht), dann Zustandswechsel.

Tiefpassfilter wäre wohl auch ganz gut, falls du den noch nicht schon hast.

Es handelt sich dabei um dieses Sound Modul.
Es gibt LOW aus, wenn was erkannt wird.
Den Schwellenwert stellt man mechanisch an einem Poti per Schraubendreher ein.
Die Schaltung wird dann mittels comparator o.ä. die werte vergleichen und LOW ausgeben, wenn der Schwellenwert überschritten wurde.

Das Klatschen wird dann so erfasst:

#define SOUNDPIN  2 // Ausgang des LM393 mir DigitalPin 2 des Arduinos verbinden

// onboard-LED zum Debugging
#define LEDPIN    13 
#define intervallMax 500 // millisekunden; für maximal erlaubte Länge zwischen dem Kltaschen 
#define intervallMin 100  // millisekunden; um den Eingang zu "entprellen" (es wird sonst pro Klatsch 6x registriert)

byte tempKlatschCount = 0;
byte klatschAnzahl=0;

void setup() 
{
  pinMode(SOUNDPIN, INPUT);
  Serial.begin(9600);    
}

void loop()
{ static unsigned long lastKlatschTime=0; // Zum merken der Zeit, wann zuletzt geklatsch wurde
  if (digitalRead(SOUNDPIN)==LOW && millis()-lastKlatschTime>intervallMin)
  {
    tempKlatschCount++;
    lastKlatschTime=millis();
    Serial.println(F("Klatsch!")); // Ausgabe das geklatscht wurde
  } 
  if (millis()-lastKlatschTime>intervallMax)
  {
    if (tempKlatschCount>0)
    {
      Serial.print(tempKlatschCount);  // Ausgabe wir oft geklatscht wurde
      Serial.println(F(" mal geklatscht")); // Ausgabe wir oft geklatscht wurde
      
      
      klatschAnzahl = tempKlatschCount;  // Modus anhand der Klatschzahl setzen.
    }
    tempKlatschCount=0;
    lastKlatschTime=millis(); // Zähler mitziehen um Probleme mit Timerüberlauf zu vermeiden
  }
}

Es wird also schon "entprellt"....
Leider funktioniert das nur sehr schlecht.
Eventuell ist mein kompletter Code zu groß und daher braucht der andere Teil außer dem "klatschen erkennen" zu lange um das klatschen wirklich gut zu erkennen.

Leider bin ich gerade etwas ratlos.

2x Klatschen wird relativ gut erkannt.
3x (und mehr) kaum noch.

Zum richtigen debuggen kam ich noch nicht, da ich erst noch ein paar Dinge am Sternenhimmel selbst verändere...
Dennoch hoffe ich auf Ratschläge, weil ich momentan etwas in der Luft schwebe, was die Ursache der unsauberen Erkennung anbelangt.

Bei mehreren Klatschern muss jeder Klatscher kürzer als 100 ms sein,
die einzelnen Klatscher müssen 100 ... 500 ms auseinander liegen.

Bei heftigem Klatschen könnte Hall etc. ein Problem werden.

Aufschlussreicher als die on board LED:
Man sollte das Signal sich mal mit einem Logik-Analyzer anschauen

Wer schreibt mal eben einen 1-Kanal Logik-Analyzer (1 - 20 Hz) für Arduino mit einem Terminal-Programm ... :wink:
Oder einfach die jeweils erkannten Zeiten > 100 ms zwischen den Klatschern mitschreiben...