Jump to content
43oh

WS2801 RGB Led Strip


Recommended Posts

Hey guys, just to break the programming monotony and get the kiddo more interested in electronics, we ported the Arduino code over to control the WS2801 RGB Led Strip from Sparkfun. http://www.sparkfun.com/products/10312 We scored one of these from their 'scratch & dent' sales a while back at half price. It's not waterproof but rainbow lights entertain an 8 year girl like nothing else.

It runs fine at 3.3v but the Launchpad does not supply enough current to run the strip so we're using a breadboard power supply as well. The software is running on a G2553 plugged into the LP but running at 1MHz. The SPI is bit banged so it should load fine on other devices as well.

The goal with this is to mount it above her bedroom window, tape a thermistor to the window and provide ambient light based on temperature as well as using a rotary encoder to allow her to set the color on demand.

Now I think I want another to cut down into a matrix for simple animations. :)

 

http://www.youtube.com/watch?v=4qlUw-dbkew

 

/****************************************************************/
/* Greg Whitmore												*/
/* greg@gwdeveloper.net											*/
/* www.gwdeveloper.net											*/
/****************************************************************/
/* released under the "Use at your own risk" license			*/
/* use it how you want, where you want and have fun				*/
/* debugging the code.											*/
/* MSP430 spi bit bang WS2801 RGB LED strip						*/
/****************************************************************/
/* code was translated from adafruit ws2801 arduino library		*/
/* https://github.com/adafruit/WS2801-Library					*/

#include 

// constant defines
#define DATA BIT7
#define CLOCK BIT6
#define NUMLEDS 32

// wdt delay constants
#define MCLK_FREQUENCY      1000000
#define WDT_DIVIDER        512

const unsigned long WDT_FREQUENCY = MCLK_FREQUENCY / WDT_DIVIDER;
volatile unsigned long wdtCounter = 0;

// data arrays
unsigned long pixels[NUMLEDS];

//incrementers
int p;
long i;

// prototypes
void init(void);
void display(void);
unsigned long color(unsigned char r, unsigned char g, unsigned char ;
void setPixelS(unsigned int n, unsigned long c);
void setPixel(unsigned int n, unsigned char r, unsigned char g, unsigned char ;
unsigned long wheel(unsigned char wheelpos);

// pattern functions
void copcar(void);
void goJoe(unsigned long time); // larger time value is slower chase
void randomdance(void);
void solidblink(unsigned long c);
void colorwipe(unsigned long c);
void rainbowcycle(void);
void showrainbow(void);

// random function and delay millis borrowed from NatureTM.com
// random generator slightly modified to create 32bit value
unsigned long adcGenRand32(void);
void delayMillis(unsigned long milliseconds);

// main colors
unsigned long clear = 0x000000;
unsigned long red = 0xFF0000;
unsigned long green = 0x00FF00;
unsigned long blue = 0x0000FF;
unsigned long white = 0x80FFFF;  // red is half strenght; full strength yields pink instead of white

unsigned long randomcolor;

void main(void)
{
//WDTCTL = WDTPW + WDTHOLD;

// use 1MHz calibrated values
DCOCTL = CALDCO_1MHZ;
BCSCTL1 = CALBC1_1MHZ;
// wdt set as interval
WDTCTL = WDTPW + WDTTMSEL + WDTIS1;
// wdt interrupt
IE1 |= WDTIE;
// enable global interrupts using intrinsic
__enable_interrupt();

// initialize pins for SPI
init();

colorwipe(clear); // clear led strip

while (1)
{	
	int x;

	// run demos for display

	for (x = 0; x < 3; x++)
	{
		copcar();
	}

	for (x = 0; x < 3; x++)
	{
		goJoe(50);
	}

	for (x = 0; x < 5; x++)
	{
		randomdance();
	}

		colorwipe(clear);

	for (x = 0; x < 3; x++)
	{
		solidblink(green);
	}

	for (x = 0; x < 2; x++)
	{
		rainbowcycle();
	}		

}

}

/* use functions */

// police light bar chaser
void copcar(void)
{
int m;
int middle = NUMLEDS / 2 ;

colorwipe(clear);

for ( m = 0; m < NUMLEDS; m++ )
{
	if ( m <= middle )
	{
		pixels[m] = red;
		pixels[m - 2] = clear;

		pixels[NUMLEDS - m] = blue;
		pixels[NUMLEDS - m + 2] = clear;
	}
	display();

	if  ( m >= middle )
	{
		pixels[m] = blue;
		pixels[m - 2] = clear;

		pixels[NUMLEDS - m] = red;
		pixels[NUMLEDS - m + 2] = clear;
	}
	display();
}
}

// red white and blue chasers
void goJoe(unsigned long time)
{
int m;

colorwipe(clear); // clear display from existing patterns

for ( m = 0; m < NUMLEDS; m++ )
{
	pixels[m] = blue;
	pixels[m - 1] = red;
	pixels[m - 2] = white;
	pixels[m - 3] = clear;
	display();
	delayMillis(time);
}
for ( m = NUMLEDS; m >= 0; m-- )
{
	pixels[m] = clear;
	pixels[m - 1] = white;
	pixels[m - 2] = red;
	pixels[m - 3] = blue;
	display();
	delayMillis(time);
}
}

// send random colors down each pixel
void randomdance(void)
{
int m;

	for ( m = 0; m < NUMLEDS; m++ )
	{
		pixels[m] = adcGenRand32();
		display();
	}
}

// blink solid color
void solidblink(unsigned long c)
{
colorwipe(c);
delayMillis(500);
colorwipe(clear);
}

// animate fading rainbow cycle
void rainbowcycle(void)
{
int k, j;

for ( j=0; j<256; j++ )
{
	for ( k=0; k < NUMLEDS; k++ )
	{
		setPixelS(k, wheel( ( k+j) % 255 ) );
	}
	display();
	delayMillis(100);
}
}

// display static rainbow
void showrainbow(void)
{
int k, j;

for ( j=0; j < 256 * 5; j++ )
{
	for ( k=0; k < NUMLEDS; k++ )
	{
		setPixelS(k, wheel( ((k * 256 / NUMLEDS ) + j) % 255) );
	}
}
display();
delayMillis(100);
}

// wipe strip to selected color
void colorwipe(unsigned long c)
{
int v;

for ( v=0; v < NUMLEDS; v++)
	setPixelS(v, c);
	display();
	//delayMillis(100);
}


/* library functions */

//initialization
void init(void)
{
P1DIR |= DATA + CLOCK; // set data and clock pins to output
}

// send data to led strip; create patten with a 'use' function then send with display
void display(void)
{
unsigned long data;

   P1OUT &= ~CLOCK;
   delayMillis(1);

   // send all the pixels
   for ( p=0; p < NUMLEDS ; p++ )
   {
       data = pixels[p];
// 24 bits of data per pixel
       for ( i=0x800000; i>0 ; i>>=1 )
       {
           P1OUT &= ~CLOCK;
           if (data & i)
           {
               P1OUT |= DATA;
           }
           else
           {
               P1OUT &= ~DATA;
           }
           P1OUT |= CLOCK;    // latch on clock rise
       }
   }
   // toggle clock low to display data
   P1OUT &= ~CLOCK;
   delayMillis(1);
}

// create 24bit color value
unsigned long color(unsigned char r, unsigned char g, unsigned char 
{
unsigned long c;
c = r;
c <<= 8;
c |= g;
c <<= 8;
c |= b;
return c;
}

// set pixel to specified color
void setPixel(unsigned int n, unsigned char r, unsigned char g, unsigned char 
{
 unsigned long data;

 if (n > NUMLEDS) return;

 data = g;
 data <<= 8;
 data |= b;
 data <<= 8;
 data |= r;

 pixels[n] = data;
}

//set pixel to color by function
void setPixelS(unsigned int n, unsigned long c)
{
if ( n > NUMLEDS ) return;

pixels[n] = c & 0xFFFFFF;
}

// rotate colorwheel for rainbows
unsigned long wheel(unsigned char wheelpos)
{
if (wheelpos <85)
{
	return color( wheelpos * 3, 255 - wheelpos * 3, 0 );
}
else if ( wheelpos < 170 )
{
	return color( 255 - wheelpos * 3, 0, wheelpos * 3 );
}
else
{
	wheelpos -= 170;
	return color( 0, wheelpos * 3, 255 - wheelpos * 3 );
}
}

// generate random 32bit number using ADC10 channel 5; leave P1.4 & P1.5 floating
unsigned long adcGenRand32(void)
{
 char bit;
 unsigned long random;

 for(bit = 0; bit < 32; bit++){
   ADC10CTL1 |= INCH_5;
   ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON;
   ADC10CTL0 |= ENC + ADC10SC;
   while(ADC10CTL1 & ADC10BUSY);
   random <<= 1;
   random |= (ADC10MEM & 0x01);
 }
 return random;
}

// millisecond delay counter using WDT
void delayMillis(unsigned long milliseconds){
 unsigned long wakeTime = wdtCounter + (milliseconds * WDT_FREQUENCY / 1000);
 while(wdtCounter < wakeTime);
}

// wdt isr
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void){
 wdtCounter++;
}

Link to post
Share on other sites

Haha, I do too!

 

Go ahead, it's all under the "use at your own risk" license. I taught myself the bit bang SPI method the other day to drive a single 7 segment led with a 74hc595. Everyone else has been using 2,4 or 8 digit displays. I just needed to flash error codes on a single and got a little lost. Now it's working great.

Link to post
Share on other sites

Thanks.

 

Not too much. Pencil and paper to sort out what each function was doing. And then relate the different Arduino functions like pinMode and digitalWrite over to MSP430 code.

 

ie; pinMode = PxDIR, digitalWrite = PxOUT. Then add the bits for HIGH or LOWS.

 

After that is was sorting out the different typedefs (uint32_t = unsigned long, byte = unsigned char...) The arduino declares them in different places and I didn't want to include the overhead of stdint.h. As of now, the whole program is under 1K.

Link to post
Share on other sites

It now has a few animations. I updated the code above and posted 2 more videos of demos running.

 

@Bluehash This one is for you:

http://www.youtube.com/watch?v=05PP9gl7BnY

 

The 2nd animation display (goJoe function) has a red, white and blue chaser which the camera has issues capturing. The rainbow fading function has a small glitch for some reason and sends a blue chaser in reverse after full red is achieved.

 

http://www.youtube.com/watch?v=JRe-rayffxA

Link to post
Share on other sites
  • 3 months later...

Hi all,

I've been working on getting Adafruit's newer LPD8806-based RGB LED strips working with an MSP430 - using this code as a base and Adafruit's LPD8806 Arduino library as a reference, I've managed to achieve control of the strip. Next up is a followup based on the LED array version of this, expanded to a larger display - I'm aiming to create a larger (primarily text-based) display, as I have a larger quantity of the strips than gwdeveloper made use of here.

Link to post
Share on other sites
  • 1 year later...

I got my ws2801 strip from http://www.lightingnext.com/ws2801-digital-addressable-rgb-led-strips.html, and used WS2801 library (https://github.com/adafruit/WS2801-Library) in the following program, however I still don't know how to change the last 6 LED into red before turning them off. Even I don't know whether it is possible or not. Can anyone let me know?

 

#include "SPI.h"
#include "WS2801.h"
int SDI = 2; // Serial gray scale data input
int CKI = 3; // Data clock input
WS2801 strip = WS2801(32, SDI, CKI);
 
void setup() {
strip.begin();
strip.show();
}
 
void loop() {
colorAppear (Color(255, 250, 250), 50);
colorAppear (Color(0, 0, 0), 5000);
}
 
void colorAppear (uint32_t c, uint8_t wait) {
for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
 
// Creating a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte B)
{
uint32_t c;
c = r;
c <<= 8;
c |= g;
c <<= 8;
c |= b;
return c;
}
Link to post
Share on other sites

Your question isn't clear to me, do you want to set all but the last 6 LEDs to a certain color, and those last 6 to red. Then thereafter turn all LEDs off?

void loop() {
  int32_t c;

  c = Color(255,0,0);
  for (int i=0; i < 6; i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(50);
  }

  c = Color(255,250,250);
  for (int i=6; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(50);
  }

  c = Color(0,0,0);
  for (int i=0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(5000);
  }
}

like this?

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...