Forum: Mikrocontroller und Digitale Elektronik wie alle RGB Farben (8Bit) durchlaufen?


von Pfunk (Gast)


Lesenswert?

Grüß Gott,

hab die ganze Nacht versucht eine entsprechende Routine in C zu 
schreiben, aber mir will es einfach nicht gelingen - sapperlot!

Ich will alle RGB Möglichkeiten durchlaufen.. Also Von RGB(0;0;0), 
RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis 
RGB(255;255;255)

Selbst ein Soft PWM samt Timer Interrupts laufen - nur eben das 
"Farbspiel" nicht.

Ich weiß, es ist eigentlich ganz banal, aber kann mir da jemand 
aushelfen?

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Pfunk schrieb:
> Ich will alle RGB Möglichkeiten durchlaufen.. Also Von RGB(0;0;0),
> RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis
> RGB(255;255;255)
Hmm, wo ist denn dein Problem? Ohne das ganze drum herum zu kennen, 
sieht das fuer mich erst mal nach drei schleifen aus:
1
for(uint16_t i = 0; i < 256; i++)
2
{
3
  for(uint16_t j = 0; j < 256; j++)
4
  {
5
    for(uint16_t k = 0; k < 256; k++)
6
    {
7
      RGB(i, j, k);
8
    }
9
  }
10
}
Vielleicht versteh ich ja aber dein Problem auch nicht richtig :-/

Gruesse

: Bearbeitet durch User
von Dennis H. (t1w2i3s4t5e6r)


Lesenswert?

Ist die Frage, was du über haupt genau willst. So wie du es beschrieben 
hast wäre es von dunkel nach hell. Wenn du alle Farben haben willst, 
musst du das anders machen. Also SAG mal, was denn genau raus kommen 
soll..


Dennis

von Pfunk (Gast)


Angehängte Dateien:

Lesenswert?

Kaj G. schrieb:
> Hmm, wo ist denn dein Problem? Ohne das ganze drum herum zu kennen,
> sieht das fuer mich erst mal nach drei schleifen aus:for(uint16_t i = 0;
> i < 256; i++)
> {
>   for(uint16_t j = 0; j < 256; j++)
>   {
>     for(uint16_t k = 0; k < 256; k++)
>     {
>       RGB(i, j, k);
>     }
>   }
> }
> Vielleicht versteh ich ja aber dein Problem auch nicht richtig :-/

Okay,

Also ich habe zwei Timer, einen schnellen der die I/Os schaltet und 
einen langsameren, der das "Faden" steuern soll.

Aber ein Faden gibt es nicht... maximal ein hochzählen :-(

Der µC ist ein PIC18F2550 interner Osc und der Compiler ein XC8.

von Pfunk (Gast)


Lesenswert?

Also ich würde gerne wie zuvor schon angedeutet (Also Von RGB(0;0;0),
RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis
RGB(255;255;255)) durch den ganzen Farbbaum durch-faden, wenn möglich.

von Sven (Gast)


Lesenswert?

Such mal nach HSV Farbraum, ist es das was Du möchtest ?

von .... (Gast)


Lesenswert?

http://de.m.wikipedia.org/wiki/HSV-Farbraum

Entweder Farbwert H oder Dunkelstufe V (das spezifizierst du ja nicht so 
genau in deiner frage) durchlaufen und dann nach rgb umrechnen und 
ausgeben

von Andreas K. (necromancer1982)


Lesenswert?

Pfunk schrieb:
> Also ich würde gerne wie zuvor schon angedeutet (Also Von RGB(0;0;0),
> RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis
> RGB(255;255;255)) durch den ganzen Farbbaum durch-faden, wenn möglich.

Hallo,

die Frage ist, ob RGB(255;255;255) Sinn macht... das wäre ja weiß und 
kommt in den Spektralfarben nicht vor (weiß ist ja schließlich die Summe 
aus den Spektralfarben)

Wenn du eine Art Regenbogen-Fader aufbauen möchtest, reicht es wenn du 
z.B. mit rot (255;0;0) startest, dann den grün-Anteil von 0 - 255 
ansteigen lässt (=> Fade zu gelb). Anschließend nimmst du den rot-Anteil 
von 255 zurück zu 0 (=> Fade zu grün). Dann nimmst den blau-Anteil von 0 
zu 255 zu (=> Fade zu türkis), dann grün weg (Fade zu blau) dann rot 
dazu (=> Fade zu pink) und schlussendlich blau wieder weg (=> Fade 
zurück zu rot).

Damit hast du insgesamt 6 Schleifen, in der du jeweils eine Farbe im 
Bereich 0 <=> 255 dazu oder weg nimmst.

Soll weiß tatsächlich dabei sein, könntest du einfach nach blau (0, 0, 
255) rot und grün gleichzeitig ansteigen lassen (=> Fade zu weiß) und 
anschließend blau und grün absteigen lassen (=> Fade zu rot) um wieder 
an den Anfang zu kommen. Das würde dann nochmal zwei zusätzliche 
Schleifen zur Folge haben.

Gruß Andi

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Hallo,

.... schrieb:
> http://de.m.wikipedia.org/wiki/HSV-Farbraum
>
> Entweder Farbwert H oder Dunkelstufe V (das spezifizierst du ja nicht so
> genau in deiner frage) durchlaufen und dann nach rgb umrechnen und
> ausgeben

Aus Erfahrung mit einer Steuerung für LED-Kannen kann ich sagen, dass 
HSV am intuitivsten zu bedienen ist und auch bei der Wahrnehmung den 
besten Eindruck macht. Also den Farbton (H) ändern ergibt einen 
Regenbogen, Sättigung (S) ergibt den Übergang zu weiss und die 
Helligkeit stellst Du mit V ein. Bei einfachen LED-Kannen kannst Du Dich 
auf den Farbton H beschränken, bei sehr guten LED-Quellen kann man alle 
drei Komponenten nutzen.
Grüße, Kurt

von Markus (Gast)


Lesenswert?

Hi,

in tc_int() (höhere Prio als LowIsr(void)?) zählst Du einmal fast (nur 
bis 254) komplett durch. Wann kommt LowIsr(void) dran? Erst wenn 
tc_int() fertig ist?

Wenn der TO meint, er wolle RGB trivial von 0 bis 255 durchlaufen 
lassen, warum wird ihm hier von Regenbogen und HSV gefaselt? Hat wohl 
keiner in den Code geguckt.

Grüße, Markus

von .... (Gast)


Lesenswert?

Ich mag regenbögen!

von Axel S. (a-za-z0-9)


Lesenswert?

Pfunk schrieb:
> Ich will alle RGB Möglichkeiten durchlaufen.. Also Von RGB(0;0;0),
> RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis
> RGB(255;255;255)

> Ich weiß, es ist eigentlich ganz banal, aber kann mir da jemand
> aushelfen?

Entweder 3 geschachtelte Schleifen wie oben oder - wenn dir das besser 
gefällt - ein long int (irgendwas >=24 Bit) hochzählen und je 8 
beliebige Bits auf die 3 Farbkanäle mappen.

Die viel entscheidendere Frage ist jedoch, ob das entstehende 
Farbenspiel auch ästhetischen Gesichtspunkten genügt. Und da versagen 
die einfachen Methoden.

Es gibt dann ein paar weitere Varianten:

1. den Farbwechsel im HSV-Modell machen (da muß man nur einen Parameter 
ändern) und in RGB umrechnen. Gibt halt nur den Regenbogen.

2. nur Farbwechsel zwischen je zwei Primärfarben machen. Also z.B. von 
Rot über Zwischenstufen zu Grün. Von da zu Blau. Und wieder zurück zu 
Rot. Das machen viele einfache Moodlights so.

3. eine Farbe zufällig auswürfeln und dann von der aktuellen Farbe dahin 
faden, wenn angekommen kurz warten und neue zufällige Farbe auswürfeln.

von Karl H. (kbuchegg)


Lesenswert?

Pfunk schrieb:

> Also ich habe zwei Timer, einen schnellen der die I/Os schaltet und
> einen langsameren, der das "Faden" steuern soll.

Wenn  man dann das auch noch mit dazu nimmt, dann musst du eben die 
entsprechenden Schleifen in Increments samt Logik umwandeln, die bei 
jedem Interrupt Aufruf des langsamen Timers einmal ausgeführt wird und 
dann eben den jeweils nächsten Fading Schritt realisiert.

Denn genau das hier
1
void interrupt tc_int()
2
{
3
    if(TMR1IE && TMR1IF)
4
    {
5
        LATB3 = ~LATB3;
6
7
        for(uint8_t i = 0; i < 255; i++)
8
        {
9
            for(uint8_t j = 0; j < 255; j++)
10
            {
11
                for(uint8_t k = 0; k < 255; k++)
12
                {
13
                    RGB(i, j, k);
14
                }
15
            }
16
        }
17
        TMR1IF = 0;
18
        WriteTimer1(0xF0BD); //Please use HEX. Decimal don't work
19
    }
20
}
willst du nicht machen. Bei jedem Interrupt Aufruf wird zur genau 
nächsten Farbe weitergeschaltet. Aber nicht in Schleifen alle Farben 
durchspielen. Dazu musst du dir eben überlegen, wie das geht, wenn r/g/b 
gerade auf 248/26/27 steht, welches dann die nächste Farbe laut deinem 
Verlaufsschema ist.
1
void interrupt tc_int()
2
{
3
  static uint8_t red, green, blue;
4
5
    if(TMR1IE && TMR1IF)
6
    {
7
        LATB3 = ~LATB3;
8
9
        if( blue != 255 )
10
          blue++;
11
        else {
12
          blue = 0;
13
          
14
          if( green != 255 )
15
            green++;
16
          else {
17
            green = 0;
18
19
            if( red != 255 )
20
              red++;
21
            else
22
              red = 0;
23
          }
24
        }
25
      }
26
27
      RGB( red, green, blue );
28
29
      TMR1IF = 0;
30
      WriteTimer1(0xF0BD); //Please use HEX. Decimal don't work
31
   }
32
}

Das ist ein generelles Prinzip. In einer Interruptroutine willst du 
diese Schleifen eben nicht haben. Sondern was du statt dessen haben 
willst, ist ein Schema, bei dem du in der Nacht geweckt wirst, du dir 
die Situation ansiehst und anhand der Situation entscheidest, was als 
nächstes zu geschehen hat. Das machst du und dann legst du dich wieder 
schlafen. Bis du 10 Minten später wieder geweckt wirst, dich wieder 
umsiehst wie die Situation jetzt ist, entscheidest was es genau jetzt zu 
tun gibt und dich wieder schlafen legst.  Und so geht das die ganze 
Nacht durch. Aber du bleibst nicht die ganze Nacht über auf sondern 
unterbrichst deinen Schlaf alle 10 Minuten um 'die Arbeit ein kleines 
Stück fortzusetzen'.

Ob das jetzt das gezielte Weiterschalten einer Uhr, bestehend aus 
Sekunden, Minuten und Stunden ist, oder das Durchlaufen von 
Temperaturkurven oder eben bei dir das Abarbeiten von Farbschemata ist, 
spielt keine Rolle. Das generelle Prinzip ist immer dasselbe. Und wenn 
du mal genau überlegst: deine Software-PWM beruht im Prinzip auf genau 
dem gleichen Grund-Prinzip. Bei jedem Interrupt Aufruf wird erneut 
entschieden, ob die jeweilige LED aufgrund ihres PWM Wertes noch brennen 
soll oder nicht.

Die Interrupt Routine, die entspricht genau dem Wecker, der dich alle 10 
Minuten aus dem Schlaf holt. Nur das das bei einem µC eben nicht 10 
Minuten sind, sondern alle paar Sekundenbruchteile passiert. Je nachdem, 
wie du den Timer konfiguriert hast.

von Tontechniker (Gast)


Lesenswert?

255 mal 255 mal 255 = 16 Mio Werte
In welcher Zeit willst du das durchfahren?
Selbst bei einer Stunde Zeit würdest du die letzte Farbe 16 mal komplett 
(0 bis 255) durchlaufen. Das kann das Auge nicht auseinanderhalten.
Das sind zuviele Werte, sichtbarmachen in einer sinnvollen Zeit dürfte 
nicht gehen.

von Tontechniker (Gast)


Lesenswert?

Korrektur:
Selbst bei einer Stunde Zeit würdest du die letzte Farbe 16 mal komplett
(0 bis 255) IN EINER SEKUNDE durchlaufen.

von Tontechniker (Gast)


Lesenswert?

Also größere Schritte machen.

von Karl H. (kbuchegg)


Lesenswert?

Tontechniker schrieb:
> Also größere Schritte machen.


Wobei man auch sagen muss, dass das gezielte Durchiterieren aller RGB 
Werte noch so einem Schema ein höchst unbefriedigendes fades Ergebnis 
liefert. D.h hier wäre zumindest der Wechsel auf ein 'Regenbogen'-System 
anzuraten. Dann sind es bei einem ganz einfachen Schema nur noch zb 1536 
(=6*256) unterschiedliche Farben. Die allerdings sind um einiges 
'interessanter' zum zusehen.

von Daniel A. (daniel-a)


Lesenswert?

Karl Heinz schrieb:
> if( blue != 255 )
>           blue++;
>         else {

Wiso werden immer die einzelnen Komponenten inkrementiert, statt alle 
komponenten als ein Integer aufzufassen, und diesen zu Inkrementieren?
1
// ungetestet
2
3
#define RGB(r,g,b) (r|g<<8|b<<16)
4
#define COLOR_TYPE uint32_t
5
#define COLOR_UINT(x) x
6
#define COLOR_BITS 24
7
#define COLOR_STEP_SIZE 1
8
9
inline bool nextColor(COLOR_TYPE*color){
10
  return COLOR_UINT(*color)>(COLOR_UINT(*color)=(COLOR_UINT(*color)+COLOR_STEP_SIZE) & ((1ul<<COLOR_BITS)-1));
11
}
12
13
inline bool updateColor(*color){
14
15
  // <code, der color ausgibt>
16
  // ...
17
18
  return nextColor(color);
19
}
20
21
int main(){
22
  COLOR_TYPE color=RGB(0,0,0);
23
  while(updateColor(&color));
24
}

Ist doch einfacher, oder?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Pfunk schrieb:
> Also ich würde gerne wie zuvor schon angedeutet (Also Von RGB(0;0;0),
> RGB(0;0;1), RGB(0;0;2) ... über RGB(0;10;10), RGB(0;10;11),... bis
> RGB(255;255;255)) durch den ganzen Farbbaum durch-faden, wenn möglich.

Mit "durch-faden" verstehst du wohl, ohne Übergänge (bzw. mit möglichst 
kleinen Übergängen) und ohne Farben mehrfach anzuzeigen, den ganzen 
Farbraum von Schwarz nach Weiß zu durchwandern?

Im Grenzfall ist das eine Peano-Kurve: Eine 1-zu-1 Abbildung eines 
Intervalls (bei dir die Zeit) ein eine kompakte Teilmenge des R³ (bei 
dir der Farbraum, also RGB, HSV, HSB, YUV, CMY oder was auch immer).

Die oben angegebenen 3-fach Schleifen führen übrigens nicht zu einer 
Lösung in diesem Sinne.

Die Konstruktion kannst du nach endlich vielen Schritten abbrechen, 
nämlich dann, wenn die Granularität fein genug ist.  Da es einige Zeit 
dauert, ca. 16 Mio. Farben zu durchlaufen, wirst du also nicht alle 
Werte durchlaufen wollen, sondern z.B. jede Farbkomponente nicht in 256 
Teile aufteilen sondern z.B. nur in 32 oder 64.

Weil das menschliche Auge Farbabstufungen unterschiedlich wahrnimmt, ist 
es bestimmt besser, zunächst in einen Farbraum zu transformieren, in dem 
der "Unterschied" der Farben ihrem Abstand entspricht.  Nahe der 
Grauachse nimmt man z.B. viel feinere Farbabstufungen wahr als bei voll 
aufgedrehter Sättigung.

Hier die Animation einer solchen Kurve von [0,1] -> [0,1]², d.h. für den 
2-dimensionalen Fall.  I.W. wird die Binärdarstellung einer Zahl 
verwendet, um daraus den Zielpunkt zu erhalten.

Eine entsprechende Entwicklung für den 3-dimensionalen Fall, die 
ebenfalls von Pixel zu Nachbarpixel ist, fällt mir auf Anhieb keine ein. 
:-)

http://commons.wikimedia.org/wiki/File:Peano-curve_animated_(140x120).gif


Ganz interessant in dem Zusammenhang ist auch http://allrgb.com/ wo es 
Bilder gibt, die alle 2^24 Farben des 8-Bit RGB-Farbraums verwenden.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Eine entsprechende Entwicklung für den 3-dimensionalen Fall, die
> ebenfalls von Pixel zu Nachbarpixel ist, fällt mir auf Anhieb keine ein.

Ok, folgendes sollte gehen:

1) Man zerlegt den Würfel (RGB-Farbraum) in 8 gleich große Teilwürfel.

2) Man wählt einen Weg von einer Ecke des Würfels zur diametral 
gegenüberliegenden Ecke, so dass der Weg aus 8 Flächendiagonalen der 
Teilwürfel besteht.  Jede Flächendiagonale muss sich einem anderen 
Teilwürfel zuordnen lassen, d.h. auf dessen Oberfläche verlaufen.

3) Für alle 8 Teilwürfel analog zu 2), allerdings führt der Weg nicht zu 
einer diametral gegenüberliegenden (3 Kanten entfernten) Ecke, sondern 
zu einer der 3 Ecken, die nur 2 Kanten von der Ausgangsecke entfernt 
sind.  Wieder besteht der Weg aus 8 Flächendiagonalen von Teilwürfeln.

4) Gehe zu 3)

Dabei verläuft der Weg immer zwischen den Ecken, die im darüberliegenden 
Schritt bestimmt wurden.

Beispielsweite kann 3) durch folgenden Weg realisiert werden.  Der zu 
durchwanderne Würfel ist [0,2]^3.  Die 8 Teilwürfel werden mit Tripeln 
aus {0,1}^3 bezeichnet.  In der linken Spalte steht der Weg, und rechts 
daneben der Teilwürfel, auf dessen Oberfläche die Flächendiagonale 
verläuft:
1
 (0,0,0) -> (1,1,0)       000
2
         -> (2,1,1)       110
3
         -> (1,2,1)       111
4
         -> (0,1,1)       011
5
         -> (1,1,0)       010
6
         -> (1,0,1)       100
7
         -> (1,1,2)       001
8
         -> (2,0,2)       101

Dass die Wege auf Flächendiagonalen von Teilwürfeln sind, erkennt man 
daran, dass ein "->" Teilweg 2 Koordinaten um 1 ändert und eine 
Koordinate unverändert lässt.

Dass ein Teilweg auf dem in der 2. Spalte stehenden Teilwürfel verläuft, 
erkennt man daran, dass wenn links ein "0" steht, an der entsprechenden 
Stelle der Würfel-Nr. eine "0" steht, und dass wo links eine "2" steht, 
rechts eine "1" steht.  (1,0,1)->(1,1,2) gehört also zum Teilwürfel 001 
oder 101 (im Beispiel 001).

Zudem tauchen in der 2. Spalte alle 8 Teilwürfel auf, d.h. der ganze 
Farbraum wird abgedeckt.

Dieses Verfahren wendet man nur folgendermaßen rekursiv an, wobei der 
Weg durch das Intervall [0,1] parametrisiert sei:

Für ein x in [0,1] schaut man sich dessen Oktalentwicklung an und wählt 
anhand der nächsten Ziffer den (nächst kleineren) Teilwürfel, aus dem 
die Farben darzustellen sind.

Beispiel: 1/3 = 0,2525...

Man startet also mit Teilwürfel 2 (010), darin nimmt man Teilwürfel 5 
(101), darin Teilwürfel 2 (010), usw.

Mit 8 Iterationsebenen und damit 8^8 = 256^3 Farben ist die übliche 
Farbauflösung (3*8 Bit) erreicht; für schnelleres Durchnudeln bzw. 
gröbere Auflösung iteriert man entsprechend weniger.  Bei nur 1 
Iterationsschritt, also nur 2), ist ein möglicher Weg 
schwarz-rot-magenta-blau-cyan-grün-gelb-weiß.

Ob das zu einem ansprechenden Ergebnis führt, kann ich allerdings nicht 
versprechen.  Einfach ausprobieren :-)

Prinzipiell lässt sich auch das Problem unterschiedlicher 
Farbwahrnehmung lösen, d.h. dass Farbunterschiede zwischen Punkten 
gleichen Abstands (im Farbraum) unterschiedlich stark wahrgenommen 
werden.  Dazu müsste man aber zunächst mal die entsprechende Metrik 
kennen. Kennt die jemand?

von Conny G. (conny_g)


Lesenswert?


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.