Last active
January 4, 2025 00:13
-
-
Save postspectacular/2a4a8db092011c6743a7 to your computer and use it in GitHub Desktop.
Super compact HSV/RGB conversions for Arduino/C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int redPin = 6; | |
int greenPin = 5; | |
int bluePin = 9; | |
float col[3]; | |
float hue = 0.0; | |
void setup() { | |
pinMode(redPin, OUTPUT); | |
pinMode(greenPin, OUTPUT); | |
pinMode(bluePin, OUTPUT); | |
} | |
void loop() { | |
setColor(hsv2rgb(hue, 1.0, 1.0, col)); | |
delay(50); | |
hue += 0.01; | |
if (hue >= 1.0) hue = 0.0; | |
} | |
void setColor(float *rgb) { | |
analogWrite(redPin, (int)((1.0 - rgb[0]) * 255)); | |
analogWrite(greenPin, (int)((1.0 - rgb[1]) * 255)); | |
analogWrite(bluePin, (int)((1.0 - rgb[2]) * 255)); | |
} | |
// HSV->RGB conversion based on GLSL version | |
// expects hsv channels defined in 0.0 .. 1.0 interval | |
float fract(float x) { return x - int(x); } | |
float mix(float a, float b, float t) { return a + (b - a) * t; } | |
float step(float e, float x) { return x < e ? 0.0 : 1.0; } | |
float* hsv2rgb(float h, float s, float b, float* rgb) { | |
rgb[0] = b * mix(1.0, constrain(abs(fract(h + 1.0) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); | |
rgb[1] = b * mix(1.0, constrain(abs(fract(h + 0.6666666) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); | |
rgb[2] = b * mix(1.0, constrain(abs(fract(h + 0.3333333) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s); | |
return rgb; | |
} | |
float* rgb2hsv(float r, float g, float b, float* hsv) { | |
float s = step(b, g); | |
float px = mix(b, g, s); | |
float py = mix(g, b, s); | |
float pz = mix(-1.0, 0.0, s); | |
float pw = mix(0.6666666, -0.3333333, s); | |
s = step(px, r); | |
float qx = mix(px, r, s); | |
float qz = mix(pw, pz, s); | |
float qw = mix(r, px, s); | |
float d = qx - min(qw, py); | |
hsv[0] = abs(qz + (qw - py) / (6.0 * d + 1e-10)); | |
hsv[1] = d / (qx + 1e-10); | |
hsv[2] = qx; | |
return hsv; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am trying to implement this on TinkerCAD, but it's not working:
`#include <Adafruit_NeoPixel.h>
#define PIN 2 // input pin Neopixel is attached to
#define NUMPIXELS 3 // number of neopixels in strip
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int redColor = 255;
int greenColor = 0;
int blueColor = 0;
int timeDel = 50;
void setup() {
// Initialize the NeoPixel library.
pixels.begin();
}
void loop() { //repeat while power is supplied to Uno board
for (float i=0.0; i < 100; i++){
int rAgAbA = [0,0,0];
redColor = (int)(hsv2rgb(i/100,1.0,1.0,rAgAbA)[0]);
greenColor = (int)(hsv2rgb(i/100,1.0,1.0,rAgAbA)[1]):
blueColor = (int)(hsv2rgb(i/100,1.0,1.0,rAgAbA)[2]);
setColor();
}
}
// setColor()
void setColor(){
for (int i=0; i < NUMPIXELS; i++) {
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(redColor, greenColor, blueColor));
}
// This sends the updated pixel color to the hardware.
pixels.show();
}
// HSV->RGB conversion based on GLSL version
// expects hsv channels defined in 0.0 .. 1.0 interval
float fract(float x) { return x - int(x); }
float mix(float a, float b, float t) { return a + (b - a) * t; }
float step(float e, float x) { return x < e ? 0.0 : 1.0; }
float* hsv2rgb(float h, float s, float b, float* rgb) {
rgb[0] = b * mix(1.0, constrain(abs(fract(h + 1.0) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
rgb[1] = b * mix(1.0, constrain(abs(fract(h + 0.6666666) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
rgb[2] = b * mix(1.0, constrain(abs(fract(h + 0.3333333) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
return rgb;
}
`