Permalink
Browse files

Arduino library and example code for controlling strands of 15-bit co…

…lor LED 'pixels' - based off of bliptronic's example code
  • Loading branch information...
ladyada committed Nov 19, 2010
0 parents commit 1905f6a2b7cae0071e88394b0313828012e04d72
Showing with 321 additions and 0 deletions.
  1. +173 −0 LPD6803.cpp
  2. +15 −0 LPD6803.h
  3. +133 −0 examples/strandtest/strandtest.pde
@@ -0,0 +1,173 @@
+#include <TimerOne.h>
+#include "LPD6803.h"
+
+//Example to control LPD6803-based RGB LED Modules in a strand
+// Original code by Bliptronics.com Ben Moyes 2009
+//Use this as you wish, but please give credit, or at least buy some of my LEDs!
+
+// Code cleaned up and Object-ified by ladyada, should be a bit easier to use
+
+/*****************************************************************************/
+
+// the arrays of ints that hold each LED's 15 bit color values
+static uint16_t *pixels;
+static uint16_t numLEDs;
+
+static uint8_t dataPin, clockPin;
+
+enum lpd6803mode {
+ START,
+ HEADER,
+ DATA,
+ DONE
+};
+
+static lpd6803mode SendMode; // Used in interrupt 0=start,1=header,2=data,3=data done
+static byte BitCount; // Used in interrupt
+static byte LedIndex; // Used in interrupt - Which LED we are sending.
+static byte BlankCounter; //Used in interrupt.
+
+static byte lastdata = 0;
+
+//Interrupt routine.
+//Frequency was set in setup(). Called once for every bit of data sent
+//In your code, set global Sendmode to 0 to re-send the data to the pixels
+//Otherwise it will just send clocks.
+void LedOut()
+{
+ // PORTB |= _BV(5); // port 13 LED for timing debug
+
+ switch(SendMode)
+ {
+ case DONE: //Done..just send clocks with zero data
+ break;
+
+ case DATA: //Sending Data
+ if( (1 << (15-BitCount)) & pixels[LedIndex]) {
+ if (!lastdata) { // digitalwrites take a long time, avoid if possible
+ // If not the first bit then output the next bits
+ // (Starting with MSB bit 15 down.)
+ digitalWrite(dataPin, 1);
+ lastdata = 1;
+ }
+ } else {
+ if (lastdata) { // digitalwrites take a long time, avoid if possible
+ digitalWrite(dataPin, 0);
+ lastdata = 0;
+ }
+ }
+ BitCount++;
+
+ if(BitCount == 16) //Last bit?
+ {
+ LedIndex++; //Move to next LED
+ if (LedIndex < numLEDs) //Still more leds to go or are we done?
+ {
+ BitCount=0; //Start from the fist bit of the next LED
+ } else {
+ // no longer sending data, set the data pin low
+ digitalWrite(dataPin, 0);
+ lastdata = 0; // this is a lite optimization
+ SendMode = DONE; //No more LEDs to go, we are done!
+ }
+ }
+ break;
+ case HEADER: //Header
+ if (BitCount < 32) {
+ digitalWrite(dataPin, 0);
+ lastdata = 0;
+ BitCount++;
+ if(BitCount==32) {
+ SendMode = DATA; //If this was the last bit of header then move on to data.
+ LedIndex = 0;
+ BitCount = 0;
+ }
+ }
+ break;
+ case START: //Start
+ if(!BlankCounter) //AS SOON AS CURRENT pwm IS DONE. BlankCounter
+ {
+ BitCount = 0;
+ LedIndex = 0;
+ SendMode = HEADER;
+ }
+ break;
+ }
+
+ // Clock out data (or clock LEDs)
+ digitalWrite(clockPin, HIGH);
+ digitalWrite(clockPin, LOW);
+
+ //Keep track of where the LEDs are at in their pwm cycle.
+ BlankCounter++;
+
+ // PORTB &= ~_BV(5); // pin 13 digital output debug
+}
+
+
+LPD6803::LPD6803(uint16_t n, uint8_t dpin, uint8_t cpin) {
+ dataPin = dpin;
+ clockPin = cpin;
+ numLEDs = n;
+
+ pixels = (uint16_t *)malloc(numLEDs);
+ for (uint16_t i=0; i< numLEDs; i++) {
+ setPixelColor(i, 0, 0, 0);
+ }
+
+ SendMode = START;
+ BitCount = LedIndex = BlankCounter = 0;
+ cpumax = 50;
+}
+
+void LPD6803::begin(void) {
+ pinMode(dataPin, OUTPUT);
+ pinMode(clockPin, OUTPUT);
+
+
+ setCPUmax(cpumax);
+
+ Timer1.attachInterrupt(LedOut); // attaches callback() as a timer overflow interrupt
+
+}
+
+uint16_t LPD6803::numPixels(void) {
+ return numLEDs;
+}
+
+void LPD6803::setCPUmax(uint8_t m) {
+ cpumax = m;
+
+ // each clock out takes 20 microseconds max
+ long time = 100;
+ time *= 20; // 20 microseconds per
+ time /= m; // how long between timers
+ Timer1.initialize(time);
+}
+
+
+void LPD6803::show(void) {
+ SendMode = START;
+}
+
+void LPD6803::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
+ uint16_t data;
+
+ if (n > numLEDs) return;
+
+ data = g & 0x1F;
+ data <<= 5;
+ data |= b & 0x1F;
+ data <<= 5;
+ data |= r & 0x1F;
+ data |= 0x8000;
+
+ pixels[n] = data;
+}
+
+void LPD6803::setPixelColor(uint16_t n, uint16_t c) {
+ if (n > numLEDs) return;
+
+ pixels[n] = 0x8000 | c;
+}
+
@@ -0,0 +1,15 @@
+#include <WProgram.h>
+
+class LPD6803 {
+ private:
+ uint8_t cpumax;
+
+ public:
+ LPD6803(uint16_t n, uint8_t dpin, uint8_t cpin);
+ void begin();
+ void show();
+ void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b);
+ void setPixelColor(uint16_t n, uint16_t c);
+ void setCPUmax(uint8_t m);
+ uint16_t numPixels(void);
+};
@@ -0,0 +1,133 @@
+#include <TimerOne.h>
+#include "LPD6803.h"
+
+//Example to control LPD6803-based RGB LED Modules in a strand
+// Original code by Bliptronics.com Ben Moyes 2009
+//Use this as you wish, but please give credit, or at least buy some of my LEDs!
+
+// Code cleaned up and Object-ified by ladyada, should be a bit easier to use
+
+/*****************************************************************************/
+
+// Choose which 2 pins you will use for output.
+// Can be any valid output pins.
+int dataPin = 2; // 'yellow' wire
+int clockPin = 3; // 'green' wire
+// Don't forget to connect 'blue' to ground and 'red' to +5V
+
+// Timer 1 is also used by the strip to send pixel clocks
+
+// Set the first variable to the NUMBER of pixels. 20 = 20 pixels in a row
+LPD6803 strip = LPD6803(20, dataPin, clockPin);
+
+
+void setup() {
+
+ // The Arduino needs to clock out the data to the pixels
+ // this happens in interrupt timer 1, we can change how often
+ // to call the interrupt. setting CPUmax to 100 will take nearly all all the
+ // time to do the pixel updates and a nicer/faster display,
+ // especially with strands of over 100 dots.
+ // (Note that the max is 'pessimistic', its probably 10% or 20% less in reality)
+
+ strip.setCPUmax(50); // start with 50% CPU usage. up this if the strand flickers or is slow
+
+ // Start up the LED counter
+ strip.begin();
+
+ // Update the strip, to start they are all 'off'
+ strip.show();
+}
+
+
+void loop() {
+ // Some example procedures showing how to display to the pixels
+
+ colorWipe(Color(255, 0, 0), 50);
+ colorWipe(Color(0, 255, 0), 50);
+ colorWipe(Color(0, 0, 255), 50);
+
+ rainbow(50);
+
+ rainbowCycle(50);
+}
+
+void rainbow(uint8_t wait) {
+ int i, j;
+
+ for (j=0; j < 96 * 3; j++) { // 3 cycles of all 96 colors in the wheel
+ for (i=0; i < strip.numPixels(); i++) {
+ strip.setPixelColor(i, Wheel( (i + j) % 96));
+ }
+ strip.show(); // write all the pixels out
+ delay(wait);
+ }
+}
+
+// Slightly different, this one makes the rainbow wheel equally distributed
+// along the chain
+void rainbowCycle(uint8_t wait) {
+ int i, j;
+
+ for (j=0; j < 96 * 5; j++) { // 5 cycles of all 96 colors in the wheel
+ for (i=0; i < strip.numPixels(); i++) {
+ // tricky math! we use each pixel as a fraction of the full 96-color wheel
+ // (thats the i / strip.numPixels() part)
+ // Then add in j which makes the colors go around per pixel
+ // the % 96 is to make the wheel cycle around
+ strip.setPixelColor(i, Wheel( ((i * 96 / strip.numPixels()) + j) % 96) );
+ }
+ strip.show(); // write all the pixels out
+ delay(wait);
+ }
+}
+
+// fill the dots one after the other with said color
+// good for testing purposes
+void colorWipe(uint16_t c, uint8_t wait) {
+ int i;
+
+ for (i=0; i < strip.numPixels(); i++) {
+ strip.setPixelColor(i, c);
+ strip.show();
+ delay(wait);
+ }
+}
+
+/* Helper functions */
+
+// Create a 15 bit color value from R,G,B
+unsigned int Color(byte r, byte g, byte b)
+{
+ //Take the lowest 5 bits of each value and append them end to end
+ return( ((unsigned int)g & 0x1F )<<10 | ((unsigned int)b & 0x1F)<<5 | (unsigned int)r & 0x1F);
+}
+
+//Input a value 0 to 127 to get a color value.
+//The colours are a transition r - g -b - back to r
+unsigned int Wheel(byte WheelPos)
+{
+ byte r,g,b;
+ switch(WheelPos >> 5)
+ {
+ case 0:
+ r=31- WheelPos % 32; //Red down
+ g=WheelPos % 32; // Green up
+ b=0; //blue off
+ break;
+ case 1:
+ g=31- WheelPos % 32; //green down
+ b=WheelPos % 32; //blue up
+ r=0; //red off
+ break;
+ case 2:
+ b=31- WheelPos % 32; //blue down
+ r=WheelPos % 32; //red up
+ g=0; //green off
+ break;
+ }
+ return(Color(r,g,b));
+}
+
+
+

0 comments on commit 1905f6a

Please sign in to comment.