RGB aus Bytes zusammensetzen

Hallo,
ich versuche einen RGB Wert in seine Farben zu zerlegen und später wieder zusammen zu setzen.
Der tiefer Sinn dahinter ist, dass ich einen Gradient von einer Farbe zu einer anderen programmieren will.
Das Zerlegen klappt, nur verstehe ich nicht warum er die Werte falsch zusammen setzt Das erste Byte ist immer FF. Wenn ich die einzelnen Farben verändere wird es ganz komisch.
Analoges Vorgehen auf einen Linux funktioniert.

Hat jemand eine idee ?

// Pseudocode   

#define COLOR1 0XAABBCC

byte r = (COLOR1 >> 16) & 0XFF;
byte g = (COLOR1 >> 8) & 0XFF;
byte b = (COLOR1) & 0XFF;

Serial.println(r,HEX);  // prints: AA 
Serial.println(g,HEX); // prints: BB 
Serial.println(b,HEX); // prints: CC
Serial.println(COLOR1,HEX);   // prints: AABBCC

// so far so good but:                                                                        <FF>?
Serial.print("0X");Serial.println((r << 16 | g << 8| b),HEX);  // prints 0XFFBBCC

Hallo,

Stelle dir eine Frage. Was passiert mit den Bits von deinen Bytes wenn du diese 16 oder 8 Stellen nach links schiebst?

"Alle" Kompilerwarnungen solltest du auch einschalten.

Der Standard Datentyp ist int! Auf einem Arduino hat der nur 16 Bit. r << 16 wird in int ausgeführt

Analoges Vorgehen auf einen Linux funktioniert.

Die Größe von int ist plattformabhängig. Deshalb muss man vorsichtig Code sein von 32/64-Bit System direkt zu übertragen

Korrekt:

byte r = 0xAA;
byte g = 0xBB;
byte b = 0xCC;

void setup()
{
   Serial.begin(9600);

   unsigned long value = (unsigned long)r << 16 | (unsigned long)g << 8 | b;
   Serial.println(value, HEX);
}

void loop()
{
}

// prints 0XFFBBCC

glaub ich nicht. Ich kenne jedenfalls keinen Arduino mit 24bit Integer.

Aber die richtige Antwort ist schon da.

glaub ich nicht.

ja, ich hatte noch einen &FFFFFF vergessen zu dokumentieren.

Danke an alle !

michael_x:
glaub ich nicht. Ich kenne jedenfalls keinen Arduino mit 24bit Integer.

print() druckt keine führenden Nullen

Serenifly:
Der Standard Datentyp ist int! Auf einem Arduino hat der nur 16 Bit. r << 16 wird in int ausgeführt

oh ja, hab ich vergessen bzw. nicht daran gedacht, sorry,

Serenifly:
print() druckt keine führenden Nullen

aber führende gesetzte Bits, wenn mal wo was ins Negative übergelaufen ist.

“auf einem Linux”, also auf einem größeren Rechner, egal mit welchem Betriebssystem, kann man es mit

        unsigned char r=0xaa, g=0xbb,  b=0xcc;   
 printf ( "Farbe: %x\n", (short)(r << 16) | (short)(g << 8) | b);
Farbe: ffffbbcc

simulieren.

Ich verstehe noch nicht wieso Du eine Variable brauchst die die RGB werte speichert und Du nicht 3 Variablen oder ein Array mit 3 Elementen nimmst.
Grüße Uwe

uwefed:
Ich verstehe noch nicht wieso Du eine Variable brauchst die die RGB werte speichert und Du nicht 3 Variablen oder ein Array mit 3 Elementen nimmst.

irgendwie stehst du auf dem Schlauch. :slight_smile:

Sein kompletter Farbwert steht in einer großen Variablen, zum speziellen manipulieren muss er sie kurz zerlegen und dann wieder zusammensetzen. Ich sehe dabei keinen Widerspruch.

Doc_Arduino:
Sein kompletter Farbwert steht in einer großen Variablen, zum speziellen manipulieren muss er sie kurz zerlegen und dann wieder zusammensetzen. Ich sehe dabei keinen Widerspruch.

Das ist mir bewußt.
Wenn er aber statt eines unsigned long 3 byte Variablen verwendet dann spart er sich:
1.) 1 Byte
2.) das zerlegen und zusammensetzen.

Grüße Uwe

Warum benutzt du für das Rechnen mit den Farben keine uinion?

const uint32_t COLOR1 = 0xAABBCC;
union {
  struct Bytes {
    byte blau;
    byte gruen;
    byte rot;
    byte unused;
  } b;
  uint32_t wert;
} Test;

void setup() {
  Serial.begin(250000);

  Test.wert = COLOR1;

  Serial.println(Test.b.rot, HEX);
  Serial.println(Test.b.gruen, HEX);
  Serial.println(Test.b.blau, HEX);
  Serial.print(F("0x"));
  Serial.println(COLOR1, HEX);

  Serial.print(F("0x"));
  Serial.println(Test.wert, HEX);
}
void loop() {}
AA
BB
CC
0xAABBCC
0xAABBCC

Ist natürlich nur zur Berechnung sinnvoll, nicht direkt als Array für z.B. FASTLed.

Hinzugefügt: Die Reihenfolge der Farbbytes im Speicher ist von der Endianness der Systems abhängig,
bei AVRs ist das little endian, also die niederwertigsten Bytes zuerst.

Hallo Uwe,

achso, ich vermute das er eine Lib oder ähnliches verwendet die mit einem kompletten RGB Farbwert arbeitet und sendet. Vielleicht sagt uns demwz noch etwas zu den Details, manchmal ergibt sich für den TO dabei erstaunlich neues, wie bei mir selbst neulich.

Jetzt haben sich schon zwei Leute dazwischen gemogelt :slight_smile:
Ich lasse meine Gedanken so stehen, auch wenn es nicht mehr ganz 100% zu der Antwortreihenfolge passt.
Auf union hätte ich auch später angespielt wenn es zu seinem Code passen könnte. Wenn er den Farbwert ohne Lib selbst erstellt.

Ja, warten wir was der TO genau machen will.
Oft haben die TO genaue Ideen wie was gemacht werden kann, sind sich aber nicht bewußt daß es auch andere, bessere Lösungswege geben kann als die gedachten. Wenn der TO mehr Infos gibt dann können wir ihm unter Umständen bessere Lösungen als seinen eingeschlagenen Weg zeigen.
Grüße Uwe

Wenn man etwas mit Farben "inhaltlich" machen will - z.B. einen Gradienten berechnen - verwendet man besser das Farbmodell HSV bzw. HSL (hue = Farbe, saturation = Sättigung, value/luminance = Intensität). Damit hat man nämlich z.B. die eigentliche "Farbe" als solche getrennt von den anderen Werten. RGB ist dagegen ein sog. "Mischfarbmodell"; wo jedes mit jedem äusserst unpraktisch zusammenhängt.

H läuft dann von 0 - 359 (Farbkreis Rot - Gelb -Grün - Cyan - Blau - Magenta - Rot), während S die "Reinheit" beschreibt, im Idealfall bei 100% nur eine einzige Wellenlänge. V bzw. L ist schlicht die Lichtmenge. So kann man wunderbar die Werte einzeln und unabhängig verändern.

Natürlich benötigt man "am Ende" wieder RGB, um die eintsprechenden LEDs technisch anzusteuern.

Eingabe RGB -> HSV -> Farbmanipulation -> RGB -> Ausgabe RGB

Beispiel: RGBConverter/RGBConverter.cpp at master · ratkins/RGBConverter · GitHub