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?
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_ti=0;i<256;i++)
2
{
3
for(uint16_tj=0;j<256;j++)
4
{
5
for(uint16_tk=0;k<256;k++)
6
{
7
RGB(i,j,k);
8
}
9
}
10
}
Vielleicht versteh ich ja aber dein Problem auch nicht richtig :-/
Gruesse
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
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.
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.
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
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
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
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
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.
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
voidinterrupttc_int()
2
{
3
if(TMR1IE&&TMR1IF)
4
{
5
LATB3=~LATB3;
6
7
for(uint8_ti=0;i<255;i++)
8
{
9
for(uint8_tj=0;j<255;j++)
10
{
11
for(uint8_tk=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
voidinterrupttc_int()
2
{
3
staticuint8_tred,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.
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.
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.
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?
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.
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?