// From Mark Kriegsman's Anti-aliased light bar example: http://pastebin.com/g8Bxi6zW #include #define LED_PIN 13 // hardware SPI pin SCK #define NUM_LEDS 250 #define COLOR_ORDER RGB #define LED_TYPE WS2811 #define MAX_BRIGHTNESS 255 // watch the power! struct CRGB leds[NUM_LEDS]; int Width = 4; // width of each light bar, in whole pixels const int barCount = 8; int bars[barCount]; int F16delta = 1; // how many 16ths of a pixel to move the Fractional Bar uint16_t Fhue16 = 0; // color for Fractional Bar int InterframeDelay = 40; //ms void setup() { LEDS.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); FastLED.setBrightness(MAX_BRIGHTNESS); for (int i = 0; i < barCount; i++) { bars[i] = i * ((NUM_LEDS * 16) / barCount); } } // Draw a "Fractional Bar" of light starting at position 'pos16', which is counted in // sixteenths of a pixel from the start of the strip. Fractional positions are // rendered using 'anti-aliasing' of pixel brightness. // The bar width is specified in whole pixels. // Arguably, this is the interesting code. void drawFractionalBar(int pos16, int width, uint8_t hue, uint8_t sat) { int i = pos16 / 16; // convert from pos to raw pixel number uint8_t frac = pos16 & 0x0F; // extract the 'factional' part of the position // brightness of the first pixel in the bar is 1.0 - (fractional part of position) // e.g., if the light bar starts drawing at pixel "57.9", then // pixel #57 should only be lit at 10% brightness, because only 1/10th of it // is "in" the light bar: // // 57.9 . . . . . . . . . . . . . . . . . 61.9 // v v // ---+---56----+---57----+---58----+---59----+---60----+---61----+---62----> // | | X|XXXXXXXXX|XXXXXXXXX|XXXXXXXXX|XXXXXXXX | // ---+---------+---------+---------+---------+---------+---------+---------> // 10% 100% 100% 100% 90% // // the fraction we get is in 16ths and needs to be converted to 256ths, // so we multiply by 16. We subtract from 255 because we want a high // fraction (e.g. 0.9) to turn into a low brightness (e.g. 0.1) uint8_t firstpixelbrightness = 255 - (frac * 16); // if the bar is of integer length, the last pixel's brightness is the // reverse of the first pixel's; see illustration above. uint8_t lastpixelbrightness = 255 - firstpixelbrightness; // For a bar of width "N", the code has to consider "N+1" pixel positions, // which is why the "<= width" below instead of "< width". uint8_t bright; for (int n = 0; n <= width; n++) { if (n == 0) { // first pixel in the bar bright = firstpixelbrightness; } else if (n == width) { // last pixel in the bar bright = lastpixelbrightness; } else { // middle pixels bright = 255; } leds[i] += CHSV(hue, sat, bright); i++; if (i == NUM_LEDS) i = 0; // wrap around } } void loop() { // Draw everything: // clear the pixel buffer memset8(leds, 0, NUM_LEDS * sizeof(CRGB)); for (int i = 0; i < barCount; i++) { int bar = bars[i]; // Update the "Fraction Bar" by 1/16th pixel every time if (i % 2 == 0) bar += F16delta; else bar -= F16delta; // wrap around at end // remember that F16pos contains position in "16ths of a pixel" // so the 'end of the strip' is (NUM_LEDS * 16) if (bar >= (NUM_LEDS * 16)) bar -= NUM_LEDS * 16; else if (bar < 0) bar = (NUM_LEDS * 16) - 1; // draw the Fractional Bar, length=4px drawFractionalBar(bar, Width, 0, 0); bars[i] = bar; } FastLED.show(); FastLED.delay(InterframeDelay); }