Rotation der RGB Farbkanäle

Hallo zusammen,

nachdem ich es nicht geschafft habe, meine 2801 Leds mit dem Raspi individuell anzusteuern , bin ich auf den Arduino gestoßen, der das ganze Problemlos machen soll.

Ohne Programmiererfahrung (kann fast alles lesen und kleinere Fehler beheben - aber nichts von Grund auf neu schreiben) hat es 2 Tage gedauert.
Am ersten Abend funktionierte die Ansteuerung der Matrix über Glediator, am Tag danach die manuelle Ansteuerung des Rests.

Jetzt will ich aber die Farbkanäle unabhängig voneinander - parallel laufend - mit unterschiedlicher Schleifenzeit ansteuern, um einen Farbverlauf zu erzeugen, der sich nicht ständig wiederholt.

Hier fehlen mir aber die theoretischen Grundlagen. Derzeit arbeite ich mit 3 For schleifen, mit integrierter If Schleife, die jeden Kanal befeuert.

Mein Problem dabei ist, dass durch diese Verschachtelung natürlich die innerste Schleife am häufigsten durchlaufen wird.

Ich will das also irgendwie "parallelisieren" - ich weiß nur nicht wie.
Mache ich das über Interrupts? Also irgend nen Zähler laufen lassen und je nach Zählerstand dann interrupten und den jeweiligen Kanals beeinflussen?

Mein ziel ist folgendes:
Der erste Farbkanal faded in ca 30 Sec von 0 auf 255 und wieder auf 0
Der zweite macht das gleiche in 40 Sec
Der Dritte macht das in 35 Sec

Bitte gebt mir mal Stichpunkte, wie ich da weiterkomme.

Für die Programmierprofis unter euch nun was zum lachen - mein "Code", wie er derzeit läuft.

#include "SPI.h"
#include "Adafruit_WS2801.h"

//Pins setzen
int dataPin  = 2; 
int clockPin = 3;

//Variablen für schleifen
int r = 0;
int r_color = 0;
int g = 0;
int g_color = 0;
int b = 0;
int b_color = 0;

//Strip Setup
Adafruit_WS2801 strip = Adafruit_WS2801(80, dataPin, clockPin);

//Los gehts - setup
void setup() {
strip.begin();
strip.show();
}

//Richtig los
void loop() {

//3 verschachtelte For - Pro kanal
 for (r=0; r < 512;) 
 {
   for (g=0; g < 512;) 
   {    
     for (b=0; b < 512;) 
     {    
     //Dirty hack für hoch und runterzählen und Farbwert setzen 
     if (b < 255){b_color = b;} 
     else{b_color = 512 - b;}
     //Streifen befeuern
     colorWipe(Color(r_color, g_color, b_color), 1);
     // für schnellen Test erstmal 30 - später irgendwas zw. 1 und 5
     b = b + 30;
   }
   if (g < 255){g_color = g;}
   else{g_color = 512 - g;}  
   g = g + b_color ;  
 }
 if (r < 255){r_color = r;}
 else{r_color = 512 - r;}
 r = r + g_color;
 }
}

//Copy&Paste aus Beispielscript - notwendig für Farbübergabe
void colorSet(uint32_t c) 
{
 int i;
 for (i=0; i < strip.numPixels(); i++) 
 {
   strip.setPixelColor(i, c);  // set the color for each pixel
 }
 strip.show();  // write the pixels to the strip
}

//Copy&paste aus Beispiel - schreibt den Strip mit delay
void colorWipe(uint32_t c, uint8_t wait) {
 int i;
 for (i=0; i < strip.numPixels(); i++) {
     strip.setPixelColor(i, c);
     strip.show();
     delay(wait);
 }
}

//Copy&Paste aus Beispielscript - notwendig für Farbübergabe
uint32_t Color(byte r, byte g, byte b)
{
 uint32_t c;
 c = r;
 c <<= 8;
 c |= g;
 c <<= 8;
 c |= b;
 return c;
}

Hallo und willkommen im Forum!

Meine Antwort ist ganz einfach: Laß loop() für Dich arbeiten!

Du hast Dein Problem ja schon bestens analysiert: die Verschachtelung der for-Schleifen. Interrupts sind nicht notwendig, sondern die "Öffnung" der for-Schleifen. Man könnte, nur mal so als Stichwort, auch sagen, schreibe keinen blockierenden Code.

Die Lösung besteht in der, bei Dir dreifachen Verwendung von millis(). Ich habe eine Ampelschaltung mit einer asynchron dazu blinkenden blauen LED als Beispiel realisiert (Anleitung Ein Endlicher Automat entsteht), wobei es bei Dir nicht auf den endlichen Automaten ankommt. Bitte beachte auch die Links am Ende, besonders das Beispiel mit dem Wachmann, der ums Haus geht.

Du kannst mittels millis() die Schaltmomente paralellisieren.
Du kontrollierst wieviel Zeit vergangen ist und änderst im richtigen Moment die Farbe.
Grüße Uwe

Auch wenn du nicht danach gefragt hast, ein Tip von mir: Mit "Farben" im eigentliche Sinne kann man per HSV-Farbmodell viel besser umgehen, als mit den einzelnen RGB-Kanälen.

Du solltest dir eine Funktion schreiben "HSV-nach-RGB", damit du vorne wirklich "Farben" (H=hue, 0..360) eigeben kannst und hinten die RGB-Werte für die physische Ansteuerung der LED rauskommen. Die Formel findest du z.B. ein Wikipedia ...

qualidat:
Mit "Farben" im eigentliche Sinne kann man per HSV-Farbmodell viel besser umgehen, als mit den einzelnen RGB-Kanälen.

Mir wurde FastLED als Bibliothek empfohlen, da könnte HSV schon drin sein. Das Problem des Themenstellers ist aber davon noch etwas weiter entfernt. Bei FastLED gibt es allerdings schöne Beispielsketche, möglicherweise sind die ja hilfreich.

FastLED hat u.a. auch zwei HSV Modelle eingebaut.

Ich verstehe die Frage so, dass R, G und B mit verschiedenen Periodenlängen ein- und ausfaden sollen. Sagt jedenfalls meine Kristallkugel. Hielt ich auch mal für eine gute Idee.

Was passiert dabei: man sieht jede menge "dreckige" bzw. "pastellige" Farben, weil man im desaturierten Bereich unterwegs ist. Nur in den kurzen Momenten, wo mindestens eine Grundfarbe aus ist, ist das Ergebnis "schön".

Mit dem HSV Farbrad hat man da wirklich mehr Spaß.

Grüße,

Helmuth

Helmuth:
Ich verstehe die Frage so, dass R, G und B mit verschiedenen Periodenlängen ein- und ausfaden sollen. Sagt jedenfalls meine Kristallkugel. Hielt ich auch mal für eine gute Idee.

Hi, genau das ist meine Intention.
Werde mir heute Abend mal eure Antworten detaillierter ansehen, bisher verstehe ich noch nicht allzuviel davon :slight_smile:

Mit FastLED sähe das (ungetestet) z.B. so aus:

#include "FastLED.h"
#define NUM_LEDS 60

CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS);
}

void loop() {
  //beatsin8( BPM, DIMMEST, BRIGHTEST);
  byte r = beatsin8( 60, 0, 255);  // 60 bpm
  byte g = beatsin8( 42, 0, 255);  // 42 bpm
  byte b = beatsin8( 23, 0, 255);  // 23 bpm

  for(int i = 0; i < NUM_LEDS; i++) {

    leds[i] = CRGB( r, g, b);
  }

  FastLED.show();
}

Hi Helmuth,

deine Lösung macht genau das, was ich suchte - vielen Dank.
Vor allem Verstehe ich diese Lösung sogar :slight_smile:

Ein kleiner Fehler war drin, die Zeile zur Initialisierung des Strips.
der Vollständigkeit halber:
FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);

Bei dir fehlten Data und Clock Pin

Na fein.

Wenn man Data und Clock Pin nicht angibt, geht das Signal an die Hardware SPI Pins vom ICSP Header - konkret an MOSI (Master Out Slave In) und SCK (Serial Clock).

Ich habe jetzt die 2 irritierenden #define Zeilen rausgenommen.

Gruß!