8-bit Color Palette Using Neopixel..?

I searched here and watched a few YouTube vids too but surprisingly didn't find anything...

Is there a handy function or some fairly clear math that would help me cycle LEDs on a WS2812B strip through just an 8-bit (256 color) palette choice a-la Windows 95, or "web colors"?

I'm using the Adafruit_NeoPixel.h library.

Many thanks in advance!

EDIT: After reading some of the example code on GitHub I'm thinking as a last resort maybe just to use ColorHSV() in increments of 256 and hit each choice with gamma32(). May test later, but still happy to hear of any other suggestions or pointers!

not clear what is your problem. yes WS2812B uses 8 bit for each R, G, or B LED.
if you want to cycle some colors, you write this in your program.

Each Neopixel LED contains pixels of three colors - R G B.
How do you expect to divide 8 bits between three colors?

Are you trying to save memory? Simple math is R2G2B2, which would give 64 colors.

You can pick whatever subsets of colors to use that you want. However, you still need to send 24 bit color to the WS2812B. All libraries I know of also expect to get a buffer of 24 bit values, however, one could write code to buffer palette indexes, which are only expanded to 24 bits on transmission.

Web colors are 24 bit, so don't see what you are getting at there. Earlier versions of Windows supported color palettes, because that is how the graphics cards worked. Since graphics cards are now 32 bit and memory is cheap, color palettes are mostly not used I think.

Thanks @Kolaha, @b707 and @bobcousins, I greatly appreciate the extra eyeballs.

Very sorry if I wasn't clear enough.

The goal was to come up with an easier to select palette of colors that I'd be cycling through with a pushbutton or at some point perhaps a dial. Twiddling R/G/B or going through 65536 H selections would be a bit much. Even 256 is a bit exhausting, but, manageable. EDIT: I'm now using increments of 1024 for 64 selections and I think that's good enough now.

At the moment I'm using this [below] on a pushbutton, which is "good enough for government work". (Three variables because I need a brightness gradient). It has some of the envisioned palette missing because it uses the HSV mapping and just sticks 255 into S and then the brightness gradients into V. But it gives me pretty much all of the outer ring of the color wheel.

I'd be totally cool with an old-skool "basic colors" selection (~48 more or less) from early MS Windows but I think I'd have to build an array with the hue/sat/lum values and cycle through the array. I was just hoping maybe that particular wheel was already invented and tucked away in a corner or collecting dust in a shed someplace. :wink:

FYI I tried this code without gamma32() as well and it really screwed up the apparent brightness of the gradients so I put it back.

unsigned int DefaultH = 0;

DefaultH = DefaultH + 256;
Color1 = strip.gamma32(strip.ColorHSV(DefaultH, 255, 255));
Color2 = strip.gamma32(strip.ColorHSV(DefaultH, 255, 130));
Color3 = strip.gamma32(strip.ColorHSV(DefaultH, 255, 70));

If I understood correctly, maybe this code will help.
It varies 16 million possibilities divided into
combinations from 0,0,0 to 256,256,256.

Simulated at: "neopixel - Wokwi ESP32, STM32, Arduino Simulator

// Adafruit NeoPixel library
#include <Adafruit_NeoPixel.h>
#define PIN        6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 1 // Popular NeoPixel ring size
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//-----------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
}
//-----------------------------------------------------------------------
void loop() {
  pixels.clear(); // Set all pixel colors to 'off'
  for (int j = 0; j < 256; j++) {
    Serial.println(j);
    for (int k = 0; k < 256; k++) {
      //Serial.println(k);
      for (int l = 0; l < 256; l++) {
       // Serial.println(l);
        //Serial.println(j);
        for (int i = 0; i < NUMPIXELS; i++) { // For each pixel...
          // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
          pixels.setPixelColor(i, pixels.Color(l, k, j));
          pixels.show();    // Send the updated pixel colors to the hardware.
          //delay(1);       // Pause before next pass through loop
        }
      }
    }
  }
}

And pointless, too, since Neopixels are 8-bits per channel, not 16 bits!

2^8 = 256
2^16 = 65536

LOL yeah, it's a bit of a puzzle to me how that all maps out in reality. :slight_smile:

Most 8-bit palettes used 3 bits for the red & green channels and 2 bits for blue channel. You can easily translate that into 8 bits for each channel:

byte myColour = <some colour value 0..255>;
byte red = (myColour & 0b00000111) << 5;
byte grn = (myColour & 0b00111000) << 2;
byte blu = (myColour & 0b11000000);

MSX2_Screen8_palette

Hmmm, actual maths. Thanks @PaulRB!

And a simulation... running "fadeHSV" currently...

sketch
// https://wokwi.com/projects/377183196488010753

#include <FastLED.h> // https://github.com/FastLED/FastLED

#define PIN 0   // ATtiny85 Neopixel pin
#define led 1   // Number of Neopixels
#define MAX 255 // Maximum brightness
#define MIN 0   // Minimum brightness

CRGB leds[led];

void setup() {
  FastLED.addLeds<WS2812, PIN, GRB>(leds, led);
  FastLED.clear();
  FastLED.setBrightness(255);
  FastLED.show();
}

void loop() {
  // zero(); // startup, pixel 0 random max R, G, B
  // blink(); // Helo, Blink!
  // candle(); // candle flicker with orange color values
  // diffused(); // white pixel for diffusion media (paper, plastic, et c.)
  fadeHSV(); // Hue, Saturation, Value transitions
  // rgbycm(); // six basic colors cycling
  // rnd(); // any of (256 * 256 * 256) = 16,777,216 colors
}

//**************************************************
// patterns
//**************************************************

void blink() { // Hello, Blink!
  leds[0] = CRGB::White; FastLED.show(); delay(500);
  leds[0] = CRGB::Black; FastLED.show(); delay(500);
}

void zero() { // at startup, pixel 0 random max R, G, B
  leds[0] =  CRGB(random(2) * random(MAX), // 0 or 1 removes or includes the color
                  random(2) * random(MAX),
                  random(2) * random(MAX));
  FastLED.show();
  delay(100);
}

void candle() { // candle flicker with orange color values without diffuser
  int r = random (127, 255);
  int g = random (50, 127);
  int b = random (0, 15);
  leds[0] = CRGB(r, g, b);
  FastLED.show();
  delay(random(63, 255));
}

void diffused() { // white pixel flicker for beneath diffusion media (paper, plastic, et c.)
  int i = random (63, 255);
  leds[0] = CRGB(i, i, i);
  FastLED.show();
  delay(random(63, 255));
}

void rgbycm() { // basic seven colors cycling
  int pause = 500;
  leds[0] = CRGB(MAX, 000, 000); FastLED.show(); delay(pause); // red
  leds[0] = CRGB(000, MAX, 000); FastLED.show(); delay(pause); // grn
  leds[0] = CRGB(000, 000, MAX); FastLED.show(); delay(pause); // blu
  leds[0] = CRGB(MAX, MAX, 000); FastLED.show(); delay(pause); // yel
  leds[0] = CRGB(000, MAX, MAX); FastLED.show(); delay(pause); // cyn
  leds[0] = CRGB(MAX, 000, MAX); FastLED.show(); delay(pause); // mag
  leds[0] = CRGB(MAX, MAX, MAX); FastLED.show(); delay(pause); // wht
}

void fadeHSV() { // Hue, Saturation, Value transitions
  uint8_t speed = 10; uint8_t change = 10; uint8_t hue = beat8(speed, 255);
  fill_rainbow(leds, led, hue, change);
  FastLED.show();
}

void rnd() { // random r, random g, random b
  leds[0] = CRGB(random(255), random(255), random(255));
  FastLED.show();
  delay(500);
}

/************************************************************************************************
  ATTINY85 information
*************************************************************************************************
                                       +-- --+
             PCINT5/-RESET/ADC0/dW/PB5 |1 * 8| VCC
      PCINT3/XTAL1/CLKI/-OC1B/ADC3/PB3 |2   7| PB2/SCK/USCK/SCL/ADC1/T0/INT0/PCINT2
  PWM4/PCINT4/XTAL2/CLKO/OC1B/ADC2/PB4 |3   6| PB1/MISO/DO/AIN1/OC0B/OC1A/PCINT1/PWM1
                                   GND |4   5| PB0/MOSI/DI/SDA/AIN0/OC0A/-OC1A/AREF/PCINT0/PWM0
                                       +-----+
*************************************************************************************************

  // BlinkM
  // https://thingm.com/products/blinkm

  // BlinkM-MinM
  // https://thingm.com/products/blinkm-minm/

  // sequencer
  // https://thingm.com/products/blinkm/
  // https://github.com/todbot/LinkM/releases/download/v20150915/BlinkMSequencer2-win.zip

  // https://thingm.com/products
  // https://raw.githubusercontent.com/todbot/LinkM/master/docs/LinkM_datasheet.pdf

  // https://www.instructables.com/Ghetto-Pixels-Building-an-open-source-BlinkM/
  // https://forum.arduino.cc/t/desperately-seeking-minm-leds-from-thingm/1173261

************************************************************************************************/

diagram.json
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-attiny85", "id": "tiny", "top": -1.2, "left": -4, "attrs": {} },
    { "type": "wokwi-neopixel", "id": "rgb1", "top": -22.7, "left": -1, "attrs": {} },
    { "type": "wokwi-vcc", "id": "vcc1", "top": -47.24, "left": -19.2, "attrs": {} },
    { "type": "wokwi-gnd", "id": "gnd1", "top": 28.8, "left": 28.2, "attrs": {} }
  ],
  "connections": [
    [ "vcc1:VCC", "rgb1:VDD", "red", [ "v9.6", "h134.4" ] ],
    [ "gnd1:GND", "rgb1:VSS", "black", [ "v-9.6", "h9.6", "v-27.9" ] ],
    [ "vcc1:VCC", "tiny:VCC", "red", [ "v9.6", "h124.8" ] ],
    [ "gnd1:GND", "tiny:GND", "black", [ "v0" ] ],
    [ "tiny:PB0", "rgb1:DIN", "green", [ "h-1.2", "v-18" ] ]
  ],
  "dependencies": {}
}

Thanks, cool sim @xfpd! I knew it was around but never played with it before. :slight_smile:

Oh my, into the fading rabbit-hole I go... :upside_down_face:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.