Forum: PC-Programmierung RGB Stripes Effekt-Routinen


von Steffen (Gast)


Lesenswert?

Hallo zusammen,

mein Problem hat zwar nicht explizit etwas mit PC-Programmierung zu tun, 
aber das kommt dem immer noch am nächsten.

Viele von euch kennen ja sicher diese tollen RGB-Stripes.

Ich habe mir nun eine Bit-Banging-Routine für die WS2812B-Chips 
geschrieben. Funktioniert soweit auch super. Allerdings möchte ich nun 
höhere Funktionen zur Visualisierung implementieren. Und genau da steckt 
das Problem. Einige Effekte machen mir ziemliche Probleme beim 
programmieren.

Folgende Routinen habe ich bereits:
1
void WS2812_Rainbow(RGB LEDs[],uint16_t Delay, uint8_t Step) {
2
  int l=0;
3
  int k=0;
4
  int LEDCount=0;
5
  RGB NewLED;
6
7
  for(l=0;l<=255;l+=Step){
8
    NewLED.R=l;
9
     NewLED.G=255-l;
10
      for(LEDCount=NumberOfLEDs;LEDCount>0;LEDCount--){
11
        LEDs[LEDCount]=LEDs[LEDCount-1];
12
       }
13
     LEDs[0]=NewLED;
14
     WS2812_Send_All(LEDs);
15
       WS2812_Update();
16
    for(k=0;k<Delay;k++){NOP500}
17
  }
18
  for(l=0;l<=255;l+=Step){
19
    NewLED.R=255-l;
20
    NewLED.B=l;
21
    for(LEDCount=NumberOfLEDs;LEDCount>0;LEDCount--){
22
      LEDs[LEDCount]=LEDs[LEDCount-1];
23
    }
24
    LEDs[0]=NewLED;
25
    WS2812_Send_All(LEDs);
26
    WS2812_Update();
27
    for(k=0;k<Delay;k++){NOP500}
28
    }
29
    for(l=0;l<=255;l+=Step){
30
      NewLED.B=255-l;
31
      NewLED.G=l;
32
      for(LEDCount=NumberOfLEDs;LEDCount>0;LEDCount--){
33
        LEDs[LEDCount]=LEDs[LEDCount-1];
34
      }
35
      LEDs[0]=NewLED;
36
      WS2812_Send_All(LEDs);
37
      WS2812_Update();
38
      for(k=0;k<Delay;k++){NOP500}
39
    }
40
}
1
void WS2812_Single_Color(RGB LEDs[],RGB Color){
2
  int j=0;
3
  for(j=0;j<=NumberOfLEDs;j++){
4
    LEDs[j]=Color;
5
  }
6
  WS2812_Send_All(LEDs);
7
}
1
oid WS2812_Spaces(RGB Color,uint8_t Space,int Delay){
2
  int j=0;
3
  for (j=0; j< 3 ; j++) {
4
    int q=0;
5
      for (q=0; q < Space ; q++) {
6
        unsigned int step=0;
7
        int i=0;
8
        for (i=0; i < NumberOfLEDs ; i++) {
9
          if (step==q) {
10
            WS2812_Send_RGB(Color);
11
          }else{
12
           WS2812_Send_LED(0,0,0);
13
          }
14
          step++;
15
          if (step==Space) step =0;
16
        }
17
        WS2812_Update();
18
        int g=0;
19
        for(g=0;g<Delay;g++){NOP1000 NOP1000 NOP1000 NOP1000}
20
      }
21
    }
22
}

Ich suche nun nicht nach einer spezifischen Lösung für ein Problem, 
sondern hoffe, dass sich hier einige "gängige" Routinen sammeln werden 
um RGB-Stripes anzusteuern.

Um es vielleicht doch etwas zu implizieren:
Eine Funktion bei der ein Balken einer bestimmten Farbe durch den Stripe 
läuft wäre gut. Als Parameter-Übergae stelle ich mir vor: Länge des 
Balkens, Länge des Abstands zum nächsten Balken, Shift-Delay und 
natürlich die gewünschte Farbe.

Programmiersprache spielt in erster Linie keine Rolle. Man kann die 
Routinen ja dann portieren. Nur finde ich halt das schreiben solcher 
Routinen recht kompliziert.

LG

Steffen

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Komplett undokumentierte Code-Schei.. Ähh Schnipsel interessieren mich 
nur wenn ich mit Geld dazu gezwungen werde :(

von Karl H. (kbuchegg)


Lesenswert?

Steffen schrieb:

> Um es vielleicht doch etwas zu implizieren:
> Eine Funktion bei der ein Balken einer bestimmten Farbe durch den Stripe
> läuft wäre gut. Als Parameter-Übergae stelle ich mir vor: Länge des
> Balkens, Länge des Abstands zum nächsten Balken, Shift-Delay und
> natürlich die gewünschte Farbe.

Und was genau hindert dich jetzt daran, so etwas zu implementieren?

generell:
was mir an deinem Code etwas fehlt, dass ist eine Zwischenschicht 
zwischen den Low-Level WS Funktionen und den High-Level Muster Routinen. 
Es gibt einige Funktionalitäten, die man immer wieder zum Aufbau von 
Mustern brauchen kann.

So zum Beispiel kommt in deiner ersten Funktion die Sequenz vor
1
    NewLED.R=l;
2
     NewLED.G=255-l;
3
      for(LEDCount=NumberOfLEDs;LEDCount>0;LEDCount--){
4
        LEDs[LEDCount]=LEDs[LEDCount-1];
5
       }
6
     LEDs[0]=NewLED;
und das mehrmals mit unterschiedlichen Farbwerten. Aber das grundlegende 
Prinzip ist in allen Fällen dasselbe: nämlich alle Farbwerte um 1 
POsition zu verschieben und an die Position 0 eine neue Farbe 
einschreiben.
Das könnte man als eine Art 'Grundfunktionalität' ansehen und sich dafür 
eine eigene Funktion schreiben
1
void WS2812_ShiftLeft( RGB LEDs[], RGB NewColor )
2
{
3
  int i;
4
5
  for( i = NumberOfLEDs; i > 0; i-- ) {
6
    LEDs[i] = LEDs[i-1];
7
  }
8
9
  LEDs[0] = NewColor;
10
}

mit dieser kleinen Hilfsfunktion vereinfacht sich dein Rainbow Effekt zu
1
void WS2812_Rainbow( RGB LEDs[], uint16_t Delay, uint8_t Step)
2
{
3
  int l=0;
4
  int k=0;
5
  int LEDCount=0;
6
  RGB NewLED;
7
8
  for( l = 0; l <= 255; l += Step ) {
9
10
    NewLED.R = l;
11
    NewLED.G = 255-l;
12
13
    WS2812_ShiftLeft( LEDs, NewLED );
14
    WS2812_Send_All(LEDs);
15
    WS2812_Update();
16
17
    for( k = 0; k < Delay; k++ )
18
      NOP500
19
  }
20
21
  for( l = 0; l <= 255; l += Step ) {
22
23
    NewLED.R = 255-l;
24
    NewLED.B = l;
25
26
    WS2812_ShiftLeft( LEDs, NewLED );
27
    WS2812_Send_All(LEDs);
28
    WS2812_Update();
29
30
    for( k = 0; k < Delay; k++)
31
      NOP500
32
  }
33
34
  for( l = 0; l <= 255; l += Step ) {
35
    NewLED.B=255-l;
36
    NewLED.G=l;
37
38
    WS2812_ShiftLeft( LEDs, NewLED );
39
    WS2812_Send_All(LEDs);
40
    WS2812_Update();
41
42
    for( k = 0; k < Delay; k++ )
43
      NOP500
44
  }
45
}

Ist schon ein bischen einfacher und überschaubarer.

Um bei der von dir angedachten Funktion zu bleiben:
Eine derartige Basiseinheit wäre es zum Beispiel, wenn es eine Funktion 
gäbe, die eine Anzahl von Leds, beginnend mit einer bestimmten Led 
Nummer auf eine bestimmte Farbe setzen könnte.
Also sowas
1
void WS2812_SetBlock( RGB LEDs[], int StartLed, int NrLeds, RGB BlockColor )
2
{
3
  ...
4
}

die Funktion muss ich dir sicher nicht schreiben. Die ist einfach genug, 
dass du das sicher alleine kannst.

Aber. Mit dieser Funktion in der Hinterhand vereinfacht sich zum 
Beispiel die Funktion WS2812_Single_Color zu
1
void WS2812_Single_Color( RGB LEDs[], RGB Color ) {
2
  WS2812_SetBlock( LEDs, 0, NumberOfLEDs, Color );
3
  WS2812_Send_All(LEDs);
4
}

und auch für die von dir angedachte Funktion, die einen Block einer 
Farbe durch die Leds durchschiebt, ist die Funktion zu gebrauchen.
1
void WS2812_ScrollBlock( RGB Leds[], RGB Color, int BlockSize, int delay ) {
2
3
  int i;
4
  RGB Black;
5
6
  for( i = 0; i <= NumberOfLEDs; i++ ) {
7
     // den Stripe in 3 Teile aufteilen
8
     //   ein Teil vor dem Farbblock
9
     //   dann den Farbblock
10
     //   dann den Teil nach dem Farbblock
11
12
     WS2812_SetBlock( LEDs, 0, i, Black );
13
     WS2812_SetBlock( LEDs, i, BlockSize, Color );
14
     WS2812_SetBlock( LEDs, i + BlockSize, NumberOfLEDs - BlockSize - i, Black );
15
16
     WS2812_Send_All(LEDs);
17
     
18
     ... delay ....
19
   }
20
}

diese Zwischenebene mit verwendbaren Basisfunktioalitäten fehlt mir bei 
dir komplett. Je bessere derartige Grundfunktionalitäten du dir hier 
zurecht legst, desto einfacher kannst du neue Muster implementieren.

Und achte ein wenig auf dein Codeform! Dein Code ist ziemlich schwer zu 
lesen. Inkonsistente Einrückung und die Nichtverwendung von Leerzeichen 
bzw. Leerzeilen um den Code zu strukturieren, machen einem das Leben nur 
unnötig schwer. Jede Sekunde, die du beim Code tippen vermeintlich 
einsparst, schlägt sich in weiterer Folge mit Minuten nieder, die du zum 
Lesen und Verstehen des Codes benötigst - es ist also ein 
Verlustgeschäft wenn man sagt "mach ich später". Machs gleich - und freu 
dich über eine bessere Lesbar- und Verstehbarkeit, die dir beim Debuggen 
unendlich viel mehr hilft als die 20 Sekunden, die du beim Hinrotzen des 
Codes einsparst.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

PS:
Die Blockdurchschiebe Funktionalität könnte man auch mit der ShiftLeft 
Funktion realisieren. Schliesslich ist das ja nichts anderes als ein 
Durchschieben, wobei je nach Kriterium an der Position 0 entweder die 
gewünschte Farbe oder eben Schwarz nachgeschoben wird.
Die ShiftLeft Funktion ist schon fertig und das Kriterium, nach welchem 
Schwarz oder eine Farbe nachgeschoben wird, ist dann auch nicht so 
schwer zu formulieren. Du siehst: die Basisfunktionalität 'Um 1 Stelle 
weiterschieben' beginnt sich auszuzahlen.

Viele Wege führen nach Rom.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

> Nur finde ich halt das schreiben solcher Routinen recht kompliziert.

Dann mach dir das Leben einfacher.
Die Kunst beim Programm-Schreiben besteht nicht darin seitenweise Code 
zu produzieren.
Die Kunst besteht darin, sich die Aufgabenstellungen in kleinere 
Einheiten aufzubrechen, die jede für sich einfach zu implementieren ist 
und wo höhere Einheiten auf 'tiefer liegende' Einheiten als Build Blocks 
zurück greifen können. So ensteht nach und nach ein Vorrat an Building 
Blocks (die sich durchaus auch gegenseitig benutzen können!), der einem 
das Leben immer einfacher macht, so dass man sich nicht mehr bei jeder 
neuen Aufgabenstellung um jeden Kleinscheiss erneut kümmern muss. Mit 
wachsender Erfahrung riecht man es förmlich, welche Teilfunktionalitäten 
sich als Build Blocks eignen bzw. vernünftig sind.

Organisation ist in der Programmierung das halbe Leben (und natürlich, 
dass man seine Programmiersprache beherrscht)

: Bearbeitet durch User
von Steffen (Gast)


Lesenswert?

Danke Karl!

Dein Beitrag ist einfach klasse und du hast natürlich vollkommen recht. 
Entsprechende Zwischenfunktionen vereinfachen die Routinen ungemein. 
Super. :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.