Hallo
Ich habe mir mit einer 3W Led ein RGB Licht gebaut...
Funktioniert alles suuper... auch das Mischen der farben...
Doch derzeit habe ich noch sehr "statische" farb muster...
Ich verwende folgenden Code
1
if(ucDirR==0)
2
{
3
if(uiR<ucMax)uiR+=2;
4
elseucDirR=1;
5
}
6
else
7
{
8
if(uiR>2)uiR--;
9
elseucDirR=0;
10
}
11
12
if(ucDirG==0)
13
{
14
if(uiG<ucMax)uiG+=2;
15
elseucDirG=1;
16
}
17
else
18
{
19
if(uiG>2)uiG-=2;
20
elseucDirG=0;
21
}
22
23
if(ucDirB==0)
24
{
25
if(uiB<ucMax)uiB++;
26
elseucDirB=1;
27
}
28
else
29
{
30
if(uiB>2)uiB--;
31
elseucDirB=0;
32
}
ucDir gibt die richtung an ob heller oder dunkler
uiR,G,B sind die Variablen der Helligkeiten der entsprechenden farben
Ich wollte fragen, wie ich am einfachsten alle möglichen farben einmal
durchgehen kann...
Danke schonmal
Lustig wär das bestimmt mit ner 3D-Version der Peano-Kurve
http://de.wikipedia.org/wiki/Peano-Kurvehttp://commons.wikimedia.org/wiki/Image:Peano-curve_animated_%28140x120%29.gif
Mit der Peano-Kurve kann man R stetig und invertierbar nach R^2 und also
auch nach R^3 abbilden. Dein RGB-Farbraum (oder HVV-Farbraum) ist ja ein
Teil des R^3.
Das ist auf jedenfall intesessanter, als ne 24-Bit Variable laufen zu
lassen und die einzelnen Bytes als R, G und B zu inerpretieren, weil
dabei Farbsprünge entstehen, die alles verwaschen bei schnellem
Durchlauf.
Johann
Eine Standard-Lösung ist die Umrechnung von HSL zu RGB Farbwerten.
HSL (Hue, Saturation, Lumination), hier gibst du einfach S und L
konstant vor, und variierst den Farbton (Einfach durchlaufen lassen)
umrechnen in RGB und für die Ausgabe nutzen.
http://www.easyrgb.com/index.php?X=MATH&H=19#text19
Damit solltest du alle Farben der geordnet Farbkreises durchgehen
können, ohne Helligkeits/Blendvariationen.
Das ist natürlich Pseudocode.
Grundsätzlich:
r,g,b haben darin eine Spanne von 0..255, ordinal, ganzzahlig
die vars/h,s,l sind zahlen mit Komma, hsl im Bereich von 0.0-1.0
Hue2RGB (also dein return v1) gibt dir zu den ersten beiden Parametern
den Farbanteil in eine bestimmte Richtung an. Auch wieder von 0.0 bis
1.0. Ist ein wenig Trigonometrie. Kann mit anderen 3. Parametern auch
verwendet werden um z.B. CMYK Anteile zu erzeugen.
Am einfachsten (aber für den uC am langsamsten) kannst du das einfach
per float Variablen umsetzen. Ansonsten empfehle ich fixed-point für
alles ausser rgb.
Ganz grob:
1
// Sei fp ein fixed-point Datentyp
2
// fpmul, fpdiv die multiplikation/division zweier fp werte
3
// fp(int) die Wandlung von int zu fp
4
// fp2u8(fp) wandelt fixed point in u8, schneidet fractions ab
Vielen Dank für deine Antwort....
Also ich habe schon einige erfahrungen in C Programmierung
jedoch weiss ich nur sehr entfernt was FixedPoint ist...
Doch die eigentliche neue frage ist... Wie ich den Code zum laufen
bekommen kann....
Weil wenn ich ihn übernehme gibts fehler :(
Ganz ehrlich.
Bei deiner Anwendung würd ich nicht lange fackeln und floating point
nehmen. So ein durchdimmendes Licht ist ja nicht gerade high speed. Ob
der µC jetzt Däumchen dreht oder ob er 3 Hunderstel Sekunden länger für
die Berechnung braucht, spielt absolut keine Rolle.
Nichtd gegen Fixpunkt Arithmetik. Aber wenn der µC sowieso massig Zeit
hat ...
> jedoch weiss ich nur sehr entfernt was FixedPoint ist...
Im Grunde nimmst du einfach ein geeignetes Vielfaches und rechnest in
Integer. Du kannst zb. für dich definieren, dass 256 einer 1.0
entsprechen soll.
Addition und Subtraktion gehen wie gehabt.
128 + 128 = 256
(0.5 + 0.5 = 1.0)
200 - 80 = 120
(0.78125 - 0.3125 = 0.46875)
Nur bei Multiplikation und Division muss man aufpassen
0.2 * 0.8 = 0.16
( 51 * 204 ) / 256 = 40
> Wie ich den Code zum laufen bekommen kann....
Indem du dir einen Integer Datentyp für fp aussuchst und die Funktionen
fpmul und fpdiv definierst.
Aber wie gesagt: Ich würd ganz einfah die float Varianten nehmen.
Ja, hab auch noch ein paar gesehen, die ich eingebaut habe auf die
Schnelle.
FixedPoint Rechnung geht wie früher in der Schule, wenn man durch
Kommazahlen schriftlich teilen sollte.
Statt mit den Komazahlen zu rechnen, wurden beide Seiten mit 10, 100,
1000 ... multipliziert, bis das Komma verschwunden war. Kann man im
Computer natürlich auch, nur nimmt man hier 2,4,8, ...
Und um die Sache einfacher zu machen nimmt man immer die selbe Zahl mit
der man multipliziert (fixed), und lässt alles weitere hinter dem Komma
wegfallen. Die Umwandlung von einem fp zu einem "normalen" Wert ist also
nur das multiplizieren/teilen mit dieser Konstante
Beispiel mit 256:
1
typedeffpu16;
2
3
fpu8tofp(u8wert)
4
{
5
return(fp)wert*256;
6
}
7
8
u8fptou8(fpwert)
9
{
10
return(u8)(wert/256);
11
}
Beim Addieren kann man die normaln Addition nutzen:
fptou8(u8tofp(a) + u8tofp(a)) = (a*256 + b*256) / 256 = (a + b) * 256 /
256 = a + b
Sprich +/- sind lineare Abbildungen unter fp
Beim Multiplizieren/Dividieren ist das etwas schwieriger. Da benötigt es
eine Korrektur:
fptou8(u8tofp(a) * u8tofp(a)) = (a*256) * (b*256) / 256 = (a*b) *
256*256/256 = a*b*256, also zuviel. Deswegen braucht es hier eine
Korrektur des Ergebnisses (analog bei der Division)
* generates rgb from hue with saturation 1 and brightness 1
21
*/
22
staticinlinevoidhue2rgb(
23
uint16h,/*uint8 s, uint8 v,*/
24
uint8*r,uint8*g,uint8*b
25
/* ,sint32 relsat= -1 */)
26
{
27
uint8gr=hueWaveform(h);
28
*g=gr;
29
// *g = (gr>50)?gr-50:0; // hack because green is too bright
30
*b=hueWaveform((h+2*HUE_MAX/3)%HUE_MAX);
31
*r=hueWaveform((h+HUE_MAX/3)%HUE_MAX);
32
}
bin mir allerdings nicht sicher, ob das ganze noch funktioniert, wenn
HUE_MAX geändert wird.
Ich hatte da noch arg dran rumoptimiet, da mein tiny15 voll war
// *g = (gr>50)?gr-50:0; // hack because green is too bright
22
*b=hueWaveform((h+2*HUE_MAX/3)%HUE_MAX);
23
*r=hueWaveform((h+HUE_MAX/3)%HUE_MAX);
24
}
es gibt auch keine fehler doch nun meine frage...
Weshalb hast du für grün etwas eigenes geschaffen?
Bei mir verhält sich grün sehr linear zu den anderen farben...
wie muss ich den code anpassen das das grün "normal" behandelt wird?
Entsprechen die variablen r, g, b meinen variablenverten für die
helligkeit?
Von wo bis wo muss ich h durchlaufen lassen um ein schönes farbspektrum
zu erreichen?
danke schonmal
Das wollte ich noch nachreichen:
Erklärung:
zwischen 0 und HUE_MAX (1536) wird einmal der gesammte kreis
durchlaufen,
HUE_MAX ist jetzt so gewählt, dass die anstiege der Farben immer 1 bzW
-1 sind.
wenn man HUE_MAX auf 256 setzt, kann man auch h auf uint8 setzen. Das
sollte etwas code sparen, sieht dann aber nicht mehr so gut aus, da der
anstieg immer 6 (bzw -6) ist. Vor allem im unteren Bereich fällt das
auf.
Auch wird nicht berücksichtigt, dass unser helligkeitsempfinden
nichtlinear ist und unterschiedliche Farben unterschiedlich hell
wahrgenommen werden. (-> siehe hack mit g= g -50 :-)
Claudio H. schrieb:
> Danke für dein Code>> ich hab den mal so angepasst>>
1
>...
2
>
>> es gibt auch keine fehler doch nun meine frage...>> Weshalb hast du für grün etwas eigenes geschaffen?
wie was eigenes?
meisnt du den aukommentierten hack? siehe obige erklärung.
Auußerdem hat das grün in meiner rgb-led ne höhere leuchtkraft.
>> Bei mir verhält sich grün sehr linear zu den anderen farben...> wie muss ich den code anpassen das das grün "normal" behandelt wird?
der hack ist doch auskommentiert.
sollte also alles gleichbehandelt werden.
die funktion hueWafeform erzeugt den Verlauf für die grüne Kurve
http://de.wikipedia.org/w/index.php?title=Datei:HSV-RGB-comparison.svg&filetimestamp=20060830160028
Da die Kurve für alle Farben gleich aussieht und nur phasenverschoben
ist.
Können alle anderen Farben auch damit berechnet werden.
>> Entsprechen die variablen r, g, b meinen variablenverten für die> helligkeit?
die entsprechen den RGB wert, also quasi dem Wert, den du in die PWM
geben musst (bzw den invertierten, wenn deine PWM invertiert ist)
>> Von wo bis wo muss ich h durchlaufen lassen um ein schönes farbspektrum> zu erreichen?>> danke schonmal
siehe oben.
Hey Vielen Dank!
Funktioniert wunderbar...
bis auf eine kleinigkeit...
Es gibt zwischendurch farbsprünge... Kann man die irgendwie vermeiden
oder hab ich was falsch programmiert?
hier mein ganzes projekt, falls es dich interessiert.
ziel ist ein tiny13, läuft aber nach wenigen anpassungen sicher auch auf
anderen.
die leds können frei über den Port verteilt werden, wichitg ist nur,
dass der schalter an int0 sitzt.
ein druck auf den schalter wechselt den modus:
1
MODE_fade=0,/* walk through hue-cycle */
2
3
MODE_red,/* simple colors */
4
MODE_green,
5
MODE_yellow,
6
MODE_blue,
7
MODE_violet,
8
MODE_cyane,
9
MODE_white,
10
11
MODE_fade_pulse,/* walk pulsing through hue-cycle */
12
MODE_red_pulse,/* pulsing colors */
13
MODE_green_pulse,
14
MODE_yellow_pulse,
15
MODE_blue_pulse,
16
MODE_violet_pulse,
17
MODE_cyane_pulse,
18
MODE_white_pulse,
wird der schalter länger gedrückt blinkt es schnell rot und das licht
wird ausgeschalten, wenn man losläßt.
Hält man weiter gedrückt, kann man eine Abschaltzeit in 7,5min schritten
einstellen.
es blinkt einmal blau -> wenn man jetzt losläßt gehts in 7.5 min aus.
hällt man weiter gedrückt
blinkt es 2 mal blau -> wenn man jetzt losläßt gehts in 15 min aus.
und so weiter bis max 6 mal.
der MODE_fade_pulse flackert aber ein bisschen bei einem Farbübergang
im unteren helligkeitsbereich. Die ursache habe ich noch nicht gefunden.
Der Code ist teilweise etwas umständlich, das liegt daran, dass ich
manche sachen umformuliert hab, damit es noch in das 1k reinpasst
das ganze werklet bei mir mit 3 RGB-LEDs in so einem Cube:
http://www.instructables.com/id/How-to-Make-a-TRON-Style-Lamp-The-MADYLIGHT/
der schalter ist ein in einer ecke angebrachter reedkontakt, so dass von
außen mittels eines Magneten geschalten werden kann, ohne dass ein
schalter die Optik beeiträchigt.
Claudio H. schrieb:
> Hey Vielen Dank!>> Funktioniert wunderbar...>> bis auf eine kleinigkeit...>> Es gibt zwischendurch farbsprünge... Kann man die irgendwie vermeiden> oder hab ich was falsch programmiert?
Da hast du bestimmt was falsch gemacht. farbsprünge sollte es keine
geben.
läufst du wirklich mit einer 16bit variable von 0-(HUE_MAX-1) und setzt
sie danach wieder auf 0?
EDIT:
ergänzung zum Code:
das Licht wird mit dem schalter wieder eingeschalten.
deswegen der int0, um den tiny wieder aufzuwecken.
Der würfel wwird bei mir mit 4*AAA 900mAh akkus versorgt und ist schon
einige stungen gelaufen und wochenlang rumgestanden.
Bisher musste ich nicht aufladen
wiso testest du nicht auf h==HUE_MAX?
aber die fehlenden 6 Stufen sollte nix ausmachen.
da müsstest du den ganzen code zeigen.
Ich vermute irgendwelche verschluckten interupts
das sieht komich aus, was du da machst.
Blick da auch grad nicht durch.
das gibt schon mindestens deswegen komische effekte, da nicht alle
Codezweige gleichschnell abgearbeitet werden können.
das heißt für bestimmte x braucht huewaveform länger, für andere kürzer.
mache eine hauptschleife, die eine globale volatile variable abfragt,
die im timerinterrupt alle x interupts gesetzt.
Das schalten der LEDs gegört in die timer-ISR, damit das immer schön
gleichmäßig passiert.
schau dir den von mir geposteten Code aus dem Zip mal an.
Folgende schritte müssen gemacht werden:
gloabele volatile variable nextAnimStep
gloabele volatile variablen r,g,b
Timer aufsetzen
in timer ISR:
internen statichen zähler hochzählen und bei bestimmten wert(abhängig
davon wie schnell der farbwechsel sein soll) zurücksetzen, sowie
nextAnimStep auf true setzen
die PWM (auch in der ISR)
anderer statischer uint8 zähler immer nur hochzählen
die rgb variablen jeweils extra vergleichen, ob sie kleiner sind als
dieser Zähler und gebenenfalls auschalten, sonst anschalten.
das hauptprogramm dreht in einer while(1)schleife runden und fragt immer
ab, ob der nächste schritt gemacht werden soll, falls ja berechnen neue
rgb, werte und schreibe sie in die globalen rgb, variablen.
setze die nextAnimStep wieder auf false.
die hier verwendete PWM ist eine reine Software-PWM
Wennn den µC noch 3 freie PWMs hat, kannst du natürlich auch die nehmen,
du musst dann nur den neuen rgb-wert in die Compareregister schreiben
und kannst dir die globalen rgbvariaben sparen
Denkst du eigendlich mal nach, bevor du postest?
1. ist der Code selbstgeschrieben
2. optimiert der Compiler das weg
3. dann funktioniert das ganze mit 1 aber nicht mehr, wenn du HUE_MAX
auf 256 änderst, weil du in 8bit bleiben willst. Da sind die benötigten
Anstiege um trotzdem auf 255 Helligkeit zu kommen andere. Würde da ne 1
stehen, würde er nur bis 43, oder so gehen, anstatt auf 255.