Umrechnen von HEX Farbcode in RGB565 Farbcode während der Laufzeit

Hallo,

ich versuche es auch nochmal im deutschen Teil dieses Forums, da ich mir denke, das einige vielleicht nur hier lesen.
Vor 25 Jahren habe ich eine Menge Basic, Turbo Pascal und Visual Basic programmiert.
Allerdings bisher noch nie etwas mit Arduino.
Deswegen brauche ich ein wenig Eure Unterstützung.

Ich bin auf der Suche nach einer kleinen Funktion, die während der Laufzeit einen HEX Farbcode in einen RGB565 Farbcode umrechnet.

Hier ein paar Beispiele:
#000000 soll 0x0000 (schwarz) zurückgeben
#FF0000 soll 0xF800 (rot) zurückgeben
#00FF00 soll 0x07E0 (grün) zurückgeben
#0000FF soll 0x001F (blau) zurückgeben
#FFFFFF soll 0xFFFF (weiss) zurückgeben

...und so weiter.

Nach einiger Recherche habe ich folgenden codeschnipsel finden können:

uint16_t rgb565( const unsigned long rgb)
{
  uint16_t R = (rgb >> 16) & 0xFF;
  uint16_t G = (rgb >>  8) & 0xFF;
  uint16_t B = (rgb      ) & 0xFF;

  uint16_t ret  = (R & 0xF8) << 8;  // 5 bits
           ret |= (G & 0xFC) << 3;  // 6 bits
           ret |= (B & 0xF8) >> 3;  // 5 bits
       
  return( ret);
}

Dieser Code ist sehr kompakt und einfach gehalten, was mir schon mal sehr gut gefällt.
Leider macht er noch nicht ganz genau das was ich suche.

Vielleicht kann mir jemand helfen diesen Code so umzuschreiben, dass er "0x07E0" zurückgibt, wenn er "#00FF00" geliefert bekommt?

Vielen Dank und liebe Grüße,
Chris

Willst du die gleiche Frage auch noch im chinesischen, spanischen, etc. Forum wiederholen?

Convert HEX color to RGB565

Wäre da nicht das Lernen von ein paar Bit Befehlen wesentlich weniger aufwändig?

Die Funktion macht genau was du beschrieben hast

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

  Serial.println(rgb565(0x000000), HEX);
  Serial.println(rgb565(0xFF0000), HEX);
  Serial.println(rgb565(0x00FF00), HEX);
  Serial.println(rgb565(0x0000FF), HEX);
  Serial.println(rgb565(0xFFFFFF), HEX);
}

Wenn du deine Eingabe als String hast, musst du das halt erst mal in einen Integer konvertieren

Willst du die gleiche Frage auch noch im chinesischen, spanischen, etc. Forum wiederholen?

Nein, chinesisch und spanisch kann ich nicht.
Und ich vermute, dass auch nicht jeder der englischen Sprache mächtig ist, sonst würde es wohl kein separaten deutschen Bereich geben.

Wäre da nicht das Lernen von ein paar Bit Befehlen wesentlich weniger aufwändig?

Ich würde nicht fragen wenn ich es könnte. Ich habe mich schon einige Stunden mit dem Thema beschäftigt, komme aber leider nicht weiter.
Wenn du mir hilfst würde ich gerne die richtigen Befehle lernen!

Lieben Gruß,
Christian

Wenn du deine Eingabe als String hast, musst du das halt erst mal in einen Integer konvertieren

Moment, da komme ich noch nicht ganz so schnell mit.
Du hast die Funktion z.B. mit "0xFF0000" gefüttert.
Ich habe aber nicht "0xFF0000" zum füttern, sondern "#FF0000".
Und es soll nicht "F800" rauskommen, sondern "0xF800".
Ich brauche genau diese Schreibweisen der Farbcodes.

Lieben Gruß,
Chris

Sag doch genau was du willst. Gerade Anfänger verwenden " auch gerne mal für Zitate statt wirklich ein String-Literal zu meinen.

Wenn du sagst "während der Laufzeit" umrechnen, dann heißt dass rein auf Integer-Basis. Alles andere außen herum ist da Nebensache

Und es soll nicht "F800" rauskommen, sondern "0xF800".

Dann schreib ein "0x" davor. Wieso scheitert es daran? :confused:

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

  formatOutput("#000000" + 1);
  formatOutput("#FF0000" + 1);
  formatOutput("#00FF00" + 1);
  formatOutput("#0000FF" + 1);
  formatOutput("#FFFFFF" + 1);
}

void loop()
{
}

void formatOutput(const char* str)
{
  char buffer[7];
  uint16_t value = rgb565(strtoul(str, NULL, 16));
  sprintf(buffer, "0x%04X", value); //Hexadezimal mit führenden Nullen, 4 Zeichen breit
  Serial.println(buffer);
}


uint16_t rgb565(uint32_t rgb)
{
  uint16_t R = (rgb >> 16) & 0xFF;
  uint16_t G = (rgb >> 8) & 0xFF;
  uint16_t B = (rgb) & 0xFF;

  uint16_t ret = (R & 0xF8) << 8;  // 5 bits
  ret |= (G & 0xFC) << 3;  // 6 bits
  ret |= (B & 0xF8) >> 3;  // 5 bits

  return ret;
}

EDIT: etwas geändert damit es logischer ist. formatOuput() bekommt den String als Parameter und macht die Konvertierung

.....Bahnhof :frowning:
Mist, das hab ich mir viel einfacher vorgestellt.

Ich befürchte, ich muss mal etwas weiter ausholen, um zu erklären was ich brauche. Ich dachte ich hätte das eindeutig formuliert, aber ich fühle mich irgendwie noch mißverstanden.

Wozu brauche ich das ganze?
Ich möchte Daten auf einem Display anzeigen, welches nur sporadisch eingeschaltet wird.
Ich habe einen volkszähler laufen, darin werden bei mir Temperaturen aus dem Haus mitgeloggt.
Diese landen in einer mySQL Datenbank.
Daraus kann man ein JSON abfragen.
In dem JSON steht neben den Temperaturdaten auch die Farbe des Kanals drin, und zwar so z.B. "color":"#009933"
Nun möchte ich also zur Laufzeit des Displayprogramms die Farbe aus dem JSON auslesen z.B. "#009933" und in eine Variable zwischenspeichern.

Dann möchte ist mit einem ESP8266 und einem SPI Display die Werte aus der Datenbank auslesen und anzeigen.
Und in dem Zuge soll auch die Kanalfarbe korrekt angezeigt werden.

Die muss ich dann für den jeweiligen Kanal setzen.
Leider funktioniert tft.setTextColor(#009933) nicht. (das wäre direkt der zur Verfügung stehende HEX Farbcode)
Sondern es muss tft.setTextColor(0x04C6) heissen. (das ist der HEX Farbcode umgewandelt in RGB565 Farbcode)

Es muss letztendlich also z.B. #009933 in 0x04C6 umgewandelt werden.

Und dazu wollte ich nun eine Funktion haben, die es ermöglich das ganze folgendermaßen zu schreiben:
z.B.:
tft.setTextColor(rgb565(#009933));

Ich dachte ich hätte mich mit meiner Fragestellung verständlich ausgedrückt?! Das war offensichtlich nicht der Fall.
Ist das denn jetzt verständlicher?

Lieben Gruß und danke für Eure Geduld!
Chris

Wenn du schon in mehrere Sprachen programmiert hast, sollten dir zwei Dinge klar sein:

1.) Es gibt verschiedene Datentypen und ein String ist etwas anderes als eine Zahl

2.) Ob etwas Dezimal oder Hexadezimal geschrieben wird ist dem Prozessor egal. 10 ist das gleiche wie 0x0A. Hex ist für dich einfacher zu lesen, aber für den Prozessor musst du nichts nach Hex konvertieren.

Nun möchte ich also zur Laufzeit des Displayprogramms die Farbe aus dem JSON auslesen z.B. "#009933" und in eine Variable zwischenspeichern.

Dann hast du einen String. Entweder ein null-terminiertes char Array oder ein Arduino String Objekt

Leider funktioniert tft.setTextColor(#009933) nicht. (das wäre direkt der zur Verfügung stehende HEX Farbcode)
Sondern es muss tft.setTextColor(0x04C6) heissen. (das ist der HEX Farbcode umgewandelt in RGB565 Farbcode)

Siehe oben. Hier bricht alles zusammen. Du musst dir darüber klar werden mit welchen Datentypen du hier arbeitest. Und lass dich nicht von der Hex-Schreibweise verwirren

Diese Methode will einen Integer. Keinen String! Du musst also den String konvertieren. Dazu gibt es strtoul() (string to unsigned long). Das ist nichts exotisches, sondern eine Standard C Funktion die du googeln kannst. Tu das, dann siehst du welche Parameter sie erwartet

Es muss letztendlich also z.B. #009933 in 0x04C6 umgewandelt werden.

Nein. Du willst lediglich einen String in einen Integer wandeln

Mit einem char Array:

char str[] = "#009933";
unsigned long value = strtoul(str + 1, NULL, 16)

Mit einem Arduino String Objekt:

String str = "#009933";
unsigned long value = strtoul(str.c_str() + 1, NULL, 16)

Die + 1 ist um das '#' am Anfang zu überspringen. Die Funktion erwartet einfach einen Zeiger aus das erste Zeichen im String

Danach hast du einen 32 Bit Integer den du an die RGB-Funktion übergeben kannst. Die 16 gibt an dass der String als Hex interpretiert wird. Aber was herauskommt ist einfach ein Integer. Wie du denn für Test-Ausgaben formatierst ist vollkommen egal. Also nicht mit "da muss 0x dran stehen". Das 0x ist auch nur eine Anweisung an den Compiler die folgenden Ziffern als Hex zu interpretieren

Moin,

1.) Ja, das weiß ich.
2.) Das wusste ich nicht. Ich habe tatsächlich bisher nie was mit HEX gemacht, soweit ich mich erinnere. Ist ja aber auch schon ein paar Tage her. Ich dachte das es natürlich wichtig ist in welchem Format man eine Funktion füttert. Da hab ich dann was dazugelernt. ....obwohl ich mir noch nicht ganz sicher bin, ob ich das wirklich verstanden habe. Naja, werden wir sehen.

Aber mir scheint, das dies die Antwort auf mein Problem ist.
(Ich muss nur noch wieder Zeit finden und sie verstehen.)

Vielen lieben Dank auf jeden Fall dafür!

Nun muss ich mich erst mal mit dem JSON auseinandersetzen, wie ich die Daten davon auslese.
Ich denke dann wird es klar ob es ein char Array oder ein Arduino String Objekt ist/wird.

Ich denke ich bin einen Schritt weiter gekommen :slight_smile:

Vielen Dank und lieben Gruß,
Chris