Test program for my Multi_WS2811 library that started out as a fork of heroic/WS2811. My library uses hardware DMA on the FRDM-KL25Z to drive up to 16 strings of WS2811 or WS2812 LEDs in parallel.
Dependencies: Multi_WS2811 mbed MMA8451Q
Fork of WS2811 by
NOTE: I have accidentally pushed changes for another fork of this program that I used in the recent Georgetown Carnival Power Tool Races. When I get some time, I will restore the test program to its original glory.
You can see my power tool racer (Nevermore's Revenge) here
This tests my FRDM-KL25Z multi-string WS2811/WS2812 library. It uses the accelerometer to change the rainbow phase on two strings of LEDs as well as the touch sense to change brightness.
A video of this program in operation is here.
Here is the library that I developed to run the LEDs:
Import libraryMulti_WS2811
Library allowing up to 16 strings of 60 WS2811 or WS2812 LEDs to be driven from a single FRDM-KL25Z board. Uses hardware DMA to do a full 800 KHz rate without much CPU burden.
main.cpp
- Committer:
- Ned Konz
- Date:
- 2016-06-10
- Revision:
- 40:d5c8ce80b6c4
- Parent:
- 39:e735259e1d2e
File content as of revision 40:d5c8ce80b6c4:
#include "mbed.h" #include "Colors.h" #include "MMA8451Q.h" #define MMA8451_I2C_ADDRESS (0x1d<<1) #define INSTANTIATE_TEMPLATES 1 #include "WS2811.h" #include "audio.h" using namespace NKAudio; #include "1khz_1sec.h" AudioFile audioFiles[] = { { __1khz_1sec_s8, __1khz_1sec_s8_len }, { 0, 0 } // mark end }; // I/O pin usage // PTD2 (D11) data output for strip# 1 // PTD3 (D12) data output for strip# 2 // PTA12 (D3) servomotor (20 msec period; 1.0-2.0msec ON) // PTA5 (D5) blinking eyes output (HI = ON) // PTE30 const unsigned DATA_OUT_PIN1 = 2; // PTD2 const unsigned DATA_OUT_PIN2 = 3; // PTD3 // actually, sides have 21 LEDs each, and ends have 10 LEDs each. const unsigned MAX_LEDS_PER_STRIP = 31; // per LED: 3 * 20 mA = 60mA max // 60 LEDs: 60 * 60mA = 3600 mA max // 120 LEDs: 7200 mA max const unsigned nLEDs = MAX_LEDS_PER_STRIP; template class WS2811<MAX_LEDS_PER_STRIP>; typedef WS2811<MAX_LEDS_PER_STRIP> MyWS2811; static MyWS2811 lightStrip1(nLEDs, DATA_OUT_PIN1); static MyWS2811 lightStrip2(nLEDs, DATA_OUT_PIN2); Serial pc(USBTX, USBRX); // accelerometer static MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS); // RGB LED on FRDM board static DigitalOut rled(LED_RED); // PTB18 max = 0.0 static DigitalOut gled(LED_GREEN); // PTB19 max = 0.0 // LED_BLUE is on PTD1 static PwmOut servo(D3); // PTA12 static DigitalOut eyes(D5); // PTA5 // static DigitalOut greenLED2(D4); // max = 1.0 static DigitalIn button1(D6); // low=ON, debounced // static DigitalIn button2(D7); // low=ON, debounced // Limits const float maxBrite = 0.5; const float minServo = -0.7; // -1.0 = -60° const float maxServo = 0.6; // 1.0 = +60° // const float minFlapTime = (maxServo - minServo) * 0.17; // 0.17 seconds / 60° at 4.8V const float minFlapTime = 0.5; const float maxFlapTime = 1.0; float currentPosition = 1.0; float currentSpeed = 1.0; // @brief sets different colors in each of the LEDs of a strip // @param strip the light strip // @param sat saturation, 0.0 - 1.0 // @param brite brightness, 0.0 - 1.0 // @param hueShift shift, 0.0 - 1.0 is equivalent to 0 - 360 degrees static void showRainbow(MyWS2811 &strip, float sat, float brite, float hueShift, float hueRange = 1.0, int span = 1, int skip=0) { int nLEDs = strip.numPixels(); int direction, first, last; if (span < 0) { direction = -1; first = nLEDs-1; last = -1; span = -span; skip = -skip; } else { direction = 1; first = 0; last = nLEDs; } for (int i = first; i != last; i += direction) { uint8_t r, g, b; float hue = (i * hueRange / nLEDs) + hueShift; HSBtoRGB(hue, sat, brite, &r, &g, &b); if ((i + skip) % span == 0) strip.setPixelColor((unsigned)i, r, g, b); else strip.setPixelColor((unsigned)i, 0, 0, 0); } strip.show(); } static void showSolidColor(MyWS2811 &strip, uint8_t r, uint8_t g, uint8_t b) { unsigned nLEDs = strip.numPixels(); for (unsigned i = 0; i < nLEDs; i++) { strip.setPixelColor(i, r, g, b); } strip.show(); } // range is -1.0 (full CCW) to +1.0 (full CW) static void positionServo(float pos) { if (pos < minServo) pos = minServo; else if (pos > maxServo) pos = maxServo; if (pos < 0.0) { rled = 0; gled = 1; } else if (pos > 0.0) { rled = 1; gled = 0; } else { rled = gled = 1; } servo.pulsewidth_us((1.5 + (pos / 2.0)) * 1000.0); } void flap() { positionServo(currentPosition); currentPosition = -currentPosition; } static void selfTestServo() { pc.printf("Servo:\r\n"); pc.printf("CCW, "); positionServo(-1.0); wait(1.0); pc.printf("CW, "); positionServo(+1.0); wait(1.0); pc.printf("center.\r\n"); positionServo(0.0); } static void selfTestLEDs() { pc.printf("LEDs ."); rled = 0; // red LED on wait(0.5); pc.printf("."); rled = 1; // red LED off, green LED on gled = 0; wait(0.5); pc.printf("."); gled = 1; // green LED off, eyes on eyes = 1; wait(0.5); pc.printf("."); eyes = 0; pc.printf("\r\n"); } static void refreshLightStrips() { MyWS2811::startDMA(); // 24 bits per LED, 800kHz (1.25usec/bit) // wait_us((MAX_LEDS_PER_STRIP * 24 * 10 / 8) + 100); } static void blankLightStrips() { showSolidColor(lightStrip1, 0, 0, 0); showSolidColor(lightStrip2, 0, 0, 0); refreshLightStrips(); } static void selfTestLightStrips() { blankLightStrips(); pc.printf("light strips"); uint8_t rgb[4] = { (uint8_t)(255 * maxBrite), 0, 0, 0 }; for (int i = 0; i < 3; i++) { showSolidColor(lightStrip1, rgb[0], rgb[1], rgb[2]); showSolidColor(lightStrip2, rgb[1], rgb[2], rgb[0]); refreshLightStrips(); wait(1.0); rgb[3] = rgb[2]; rgb[2] = rgb[1]; rgb[1] = rgb[0]; rgb[0] = rgb[3]; pc.printf("."); } blankLightStrips(); pc.printf("\r\n"); } static void selfTest() { pc.printf("self test: "); selfTestLightStrips(); selfTestServo(); selfTestLEDs(); pc.printf("done\n"); } // rainbow that wraps around entire frame void updateStripsRainbow() { static int skip = 0; showRainbow(lightStrip1, 1.0, maxBrite, currentSpeed, 0.5, 3, skip); showRainbow(lightStrip2, 1.0, maxBrite, currentSpeed + 0.5, 0.5, -3, skip); refreshLightStrips(); skip++; skip %= 3; } void updateEyes() { static bool eyesOn; eyes = eyesOn ? 1 : 0; eyesOn = !eyesOn; } int main(void) { pc.baud(115200); pc.printf("\r\n\r\nNevermore's Revenge!\r\ncompiled " __DATE__ ", " __TIME__ "\r\n"); lightStrip1.begin(); lightStrip2.begin(); rled = 1.0; gled = 1.0; servo.period_ms(20); selfTest(); Timer elapsedTime; Ticker flapper; flapper.attach(flap, maxFlapTime); Ticker stripUpdater; stripUpdater.attach(updateStripsRainbow, 0.3); Ticker eyeUpdater; eyeUpdater.attach(updateEyes, 0.2); elapsedTime.start(); bool lastButton = button1.read(); for (;; ) { bool buttonValue = button1.read(); if (buttonValue != lastButton) { if (!buttonValue) { flapper.detach(); flapper.attach(flap, maxFlapTime); stripUpdater.detach(); stripUpdater.attach(updateStripsRainbow, 0.3); } else { flapper.detach(); flapper.attach(flap, minFlapTime); stripUpdater.detach(); stripUpdater.attach(updateStripsRainbow, 0.1); } } wait(0.1); } }