1 | #include "stdafx.h"
|
2 |
|
3 | struct cRGB { uint8_t r; uint8_t g; uint8_t b; };
|
4 | struct cHSV { uint8_t h; uint8_t s; uint8_t v; };
|
5 |
|
6 | const uint8_t NUM_LEDS = 6;
|
7 | struct cRGB rgb[NUM_LEDS];
|
8 | struct cHSV hsv[NUM_LEDS];
|
9 |
|
10 | #define APPLY_DIMMING(X) (X)
|
11 | #define HSV_SECTION_6 (0x55)
|
12 | #define HSV_SECTION_3 (0x40)
|
13 | void hsv2rgb_raw_C(struct cRGB *rgb, struct cHSV *hsv, int16_t led)
|
14 | {
|
15 | // Convert hue, saturation and brightness ( HSV/HSB ) to RGB
|
16 | // "Dimming" is used on saturation and brightness to make
|
17 | // the output more visually linear.
|
18 |
|
19 | // Apply dimming curves
|
20 | uint8_t value = hsv[led].v;
|
21 | uint8_t saturation = hsv[led].s;
|
22 |
|
23 | // The brightness floor is minimum number that all of
|
24 | // R, G, and B will be set to.
|
25 | uint8_t invsat = APPLY_DIMMING(255 - saturation);
|
26 | uint8_t brightness_floor = (value * invsat) / 256;
|
27 |
|
28 | // The color amplitude is the maximum amount of R, G, and B
|
29 | // that will be added on top of the brightness_floor to
|
30 | // create the specific hue desired.
|
31 | uint8_t color_amplitude = value - brightness_floor;
|
32 |
|
33 | // Figure out which section of the hue wheel we're in,
|
34 | // and how far offset we are withing that section
|
35 | uint8_t section = hsv[led].h / HSV_SECTION_3; // 0..2
|
36 | uint8_t offset = hsv[led].h % HSV_SECTION_3; // 0..63
|
37 |
|
38 | uint8_t rampup = offset; // 0..63
|
39 | uint8_t rampdown = (HSV_SECTION_3 - 1) - offset; // 63..0
|
40 |
|
41 | // We now scale rampup and rampdown to a 0-255 range -- at least
|
42 | // in theory, but here's where architecture-specific decsions
|
43 | // come in to play:
|
44 | // To scale them up to 0-255, we'd want to multiply by 4.
|
45 | // But in the very next step, we multiply the ramps by other
|
46 | // values and then divide the resulting product by 256.
|
47 | // So which is faster?
|
48 | // ((ramp * 4) * othervalue) / 256
|
49 | // or
|
50 | // ((ramp ) * othervalue) / 64
|
51 | // It depends on your processor architecture.
|
52 | // On 8-bit AVR, the "/ 256" is just a one-cycle register move,
|
53 | // but the "/ 64" might be a multicycle shift process. So on AVR
|
54 | // it's faster do multiply the ramp values by four, and then
|
55 | // divide by 256.
|
56 | // On ARM, the "/ 256" and "/ 64" are one cycle each, so it's
|
57 | // faster to NOT multiply the ramp values by four, and just to
|
58 | // divide the resulting product by 64 (instead of 256).
|
59 | // Moral of the story: trust your profiler, not your insticts.
|
60 |
|
61 | // Since there's an AVR assembly version elsewhere, we'll
|
62 | // assume what we're on an architecture where any number of
|
63 | // bit shifts has roughly the same cost, and we'll remove the
|
64 | // redundant math at the source level:
|
65 |
|
66 | // // scale up to 255 range
|
67 | // //rampup *= 4; // 0..252
|
68 | // //rampdown *= 4; // 0..252
|
69 |
|
70 | // compute color-amplitude-scaled-down versions of rampup and rampdown
|
71 | uint8_t rampup_amp_adj = (rampup * color_amplitude) / (256 / 4);
|
72 | uint8_t rampdown_amp_adj = (rampdown * color_amplitude) / (256 / 4);
|
73 |
|
74 | // add brightness_floor offset to everything
|
75 | uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
|
76 | uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
|
77 |
|
78 |
|
79 | if (section) {
|
80 | if (section == 1) {
|
81 | // section 1: 0x40..0x7F
|
82 | rgb[led].r = brightness_floor;
|
83 | rgb[led].g = rampdown_adj_with_floor;
|
84 | rgb[led].b = rampup_adj_with_floor;
|
85 | }
|
86 | else {
|
87 | // section 2; 0x80..0xBF
|
88 | rgb[led].r = rampup_adj_with_floor;
|
89 | rgb[led].g = brightness_floor;
|
90 | rgb[led].b = rampdown_adj_with_floor;
|
91 | }
|
92 | }
|
93 | else {
|
94 | // section 0: 0x00..0x3F
|
95 | rgb[led].r = rampdown_adj_with_floor;
|
96 | rgb[led].g = rampup_adj_with_floor;
|
97 | rgb[led].b = brightness_floor;
|
98 | }
|
99 | }
|
100 |
|
101 | int main()
|
102 | {
|
103 | const uint8_t color[6] = { 0, 42, 85, 127, 170, 212 };
|
104 |
|
105 | printf("-- hue 0-255, sat 255, val 255\n");
|
106 | for (uint8_t i = 0; i < NUM_LEDS; i++)
|
107 | {
|
108 | hsv[i].h = color[i];
|
109 | hsv[i].s = 255;
|
110 | hsv[i].v = 255;
|
111 |
|
112 | hsv2rgb_raw_C(rgb, hsv, i);
|
113 | printf("hue %3d:\t%3d\t%3d\t%3d\n", hsv[i].h, rgb[i].r, rgb[i].g, rgb[i].b);
|
114 | }
|
115 |
|
116 | printf("\n");
|
117 | printf("-- hue 0-255, sat 0, val 255\n");
|
118 | for (uint8_t i = 0; i < NUM_LEDS; i++)
|
119 | {
|
120 | hsv[i].h = color[i];
|
121 | hsv[i].s = 0;
|
122 | hsv[i].v = 255;
|
123 |
|
124 | hsv2rgb_raw_C(rgb, hsv, i);
|
125 | printf("hue %3d:\t%3d\t%3d\t%3d\n", hsv[i].h, rgb[i].r, rgb[i].g, rgb[i].b);
|
126 | }
|
127 |
|
128 | while (1);
|
129 | return 0;
|
130 | }
|