TruckTree!

From pauljmac.com Projects
Jump to: navigation, search

This project is for a Christmas tree that I put in the back of my truck each year around that time. It uses a strand (or 2) of individually addressable RGB LEDs. The LEDs have a WS2811 driver IC which communicates using 1 wire serial. This is NOT to be confused with the WS2801 which is a 2 wire serial IC, and quite frankly a lot easier to work with. Luckily though, people like Alan Burlison have already done the hard work for everyone and have been nice enough to share. Alan has written a very good AVR driver for the nasty WS2811 chip which covers about 95% of the work. His article on it can be seen here.

My project uses his WS2811.h and would not be possible at all without it. Thanks very much Alan!

Operation

The idea here is to have a nice little tree in your truck that fades slowly randomly R G and B and everything in-between. But when you apply the brakes it will cause the whole tree to fade to red. When the brake are released it will go back to its normal random color stuff.

The brake lights are hooked up to an opto isolator on the board which tell the micro when the brake is applied.

There is a DC to DC converter on the board that will provide power for everything. Be mindful about the current limitations of it. It should be fine for at least 100 LEDs.

These strands of lights are found on ebay. Just search for WS2811. THE MANUFACTURING QUALITY OF THESE LIGHTS IS NOT GREAT. You will most likely have to fix some bad solder joints and/or other things like that. Everything is "potted" so it makes it that much more difficult. Just be ready to do this kind of work.

In hindsight… I have no idea why I chose to use the beefy TI switching regulator. Maybe I had a good reason when I drafted the original schematic some months ago but I can’t remember what it is now. Maybe I thought it would use more current than it actually does? Yea that’s it… we’ll go with that. The reality is 2 strings does not use that much current and you could probably get away with using a linear regulator with some good heat dissipation.

Video and Pics

http://www.youtube.com/watch?v=dCNIRQI3RAA

Tree with color!
Tree all red!
A completed board.

Board and schematic

Schem

Gerbers

EagleCAD

TruckTree.png

BOM

Qty	Value	Part Num	Package	Parts
3		*	FE08	PORTB, PORTC, PORTD
1		609-3218-ND	MA03-2	ISP
4	.1uF	311-1361-1-ND	C0805K	C4, C6, C7, C8
1	1.4K	RHM1.40KBDCT-ND	R1210	R1
1	2.2uF	490-1733-1-ND	C0805K	C3
1	4N25SM	4N25SM-ND	DIL6-SMD	OK1
1	16MHz	535-10226-1-ND	HC49UP	Q1
2	18pF	399-9179-1-ND	C0805K	C1, C2
1	21k	P21.0KCCT-ND	M0805	R2
1	330uF	338-1790-1-ND	153CLV-0810	C5
1	ATMEGA88PA	ATMEGA88PA-AU-ND	TQFP32-08	IC1
1	Brake Signal	WM4201-ND	22-23-2031	BRAKE
1	PTN78020WAH	296-20515-ND	PTH	DC
1	Power	WM4201-ND	22-23-2031	POWER
1	TPPAD1-13Y	*	P1-13Y	INHIB
1	Tree	WM4201-ND	22-23-2031	TREE
3	WM2012-ND
9	WM1114CT-ND	

Code

I am only posting my edited example file from Alan. You will need to grab the WS2811.h from Alan's page.

/*
 * Copyright 2012 Alan Burlison, alan@bleaklow.com.  All rights reserved.
 * Use is subject to license terms.
 */
/* Fuse settings
BOOTSZ = 1024W_0C00
BOOTRST = [ ]
RSTDISBL = [ ]
DWEN = [ ]
SPIEN = [X]
WDTON = [ ]
EESAVE = [ ]
BODLEVEL = DISABLED
CKDIV8 = [ ]
CKOUT = [X]
SUT_CKSEL = EXTXOSC_8MHZ_XX_258CK_14CK_4MS1

EXTENDED = 0xF9 (valid)
HIGH = 0xDF (valid)
LOW = 0x8E (valid)

*/

#include <avr/io.h>
#include <util/delay.h>
#include "WS2811.h"
#include	<stdlib.h> 

#define BIT(B)           (0x01 << (uint8_t)(B))
#define SET_BIT_HI(V, B) (V) |= (uint8_t)BIT(B)
#define SET_BIT_LO(V, B) (V) &= (uint8_t)~BIT(B)

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))

#define PAUSE  500    // msec
#define DELAY    10	// msec
#define CHASE_SPEED    10	// msec
#define FADE_TO_RED_SPEED 1 // msec
#define RAND_MAX 0xFF
#define NUMBER_OF_NODES 100
#define COLOR_CHANGE_SPEED 1000

volatile uint8_t direction=0, LED_num=0;
 
// Define the output function, using pin 0 on port b.
DEFINE_WS2811_FN(WS2811RGB, PORTC, 0)

RGB_t rgb[NUMBER_OF_NODES];
volatile uint8_t colorchange=0;
volatile uint8_t desired_color[NUMBER_OF_NODES][3];

void Blank (void);
void All_Red (void);
void Random (void);
void Chase (void);
void Random_fader(void);
void Update_Colors(void);

void main(void){	
	// Configure pin for output.
	SET_BIT_HI(DDRC, 0);
	SET_BIT_LO(PORTC, 0);
	SET_BIT_LO(DDRC, 1); //an input
	SET_BIT_HI(PORTC, 1); //enable pull up
	Blank();
	for (;;) {
		WS2811RGB(rgb, ARRAYLEN(rgb)); //call the LED driver
		_delay_ms(DELAY);
		if(bit_get(PINC, BIT(1)) == 0 ){ //if 0 then pressed
			_delay_ms(FADE_TO_RED_SPEED);
			Fade_to_red();
		}
		else{
			_delay_ms(FADE_TO_RED_SPEED);
			Update_Colors();
			Random_fader();
		}
		//Chase();
	}
}

void Blank (void){ //blanks the color of all the LEDs
	 for(int i=0; i<NUMBER_OF_NODES ; i++){
		 rgb[i].r = 0;
		 rgb[i].g = 0;
		 rgb[i].b = 0;
	 }
}

void All_Red (void){ //blanks the color of all the LEDs
	for(int i=0; i<NUMBER_OF_NODES ; i++){
		rgb[i].r = 255;
		rgb[i].g = 0;
		rgb[i].b = 0;
	}
}

void Fade_to_red(void){
	for(int i=0; i<NUMBER_OF_NODES ; i++){
		 if (rgb[i].r < 255 ){
			 rgb[i].r++;
		 }
		 if (rgb[i].g > 0 ){
			 rgb[i].g--;
		 }
		 if (rgb[i].b > 0 ){
			 rgb[i].b--;
		 }
	}
}

void Update_Colors(void){
	static dominant_color;
	if (colorchange++ == 255){ //its time to change the color
		for(int i=0; i<NUMBER_OF_NODES ; i++){
			dominant_color=random() % 3;
			switch (dominant_color){
				case 0: //red is dominant color
				desired_color[i][0] = random();
				desired_color[i][1] = random() % 95;
				desired_color[i][2] = random() % 95;
				break;
				case 1: //green is dominant color
				desired_color[i][0] = random() % 95;
				desired_color[i][1] = random();
				desired_color[i][2] = random() % 95;
				break;
				case 2: //blue is dominant color
				desired_color[i][0] = random() % 95;
				desired_color[i][1] = random() % 95;
				desired_color[i][2] = random();
				break;
				default: //white
				desired_color[i][0] = random();
				desired_color[i][1] = random();
				desired_color[i][2] = random();
				break;
			}
		}
		colorchange=0; //reset colorchange timer
	}
}

void Random_fader(void){
	 //adjust the driven LED color to get close to the desired color
		for(int i=0; i<NUMBER_OF_NODES ; i++){
			 if (rgb[i].r > desired_color[i][0]){	//if driven color is greater than desired color
				 rgb[i].r--;						//decrease driven color
			 }
			 else if(rgb[i].r < desired_color[i][0]){ //if driven color is less than desired color
				 rgb[i].r++;						//increase driven color
			 }
			 if (rgb[i].g > desired_color[i][1]){	//if driven color is greater than desired color
				 rgb[i].g--;						//decrease driven color
			 }
			 else if(rgb[i].g < desired_color[i][1]){ //if driven color is less than desired color
				 rgb[i].g++;						//increase driven color
			 }
			  if (rgb[i].b > desired_color[i][2]){	//if driven color is greater than desired color
				 rgb[i].b--;						//decrease driven color
			 }
			 else if(rgb[i].g < desired_color[i][2]){ //if driven color is less than desired color
				 rgb[i].b++;						//increase driven color
			 }
		}		
}

void Random (void){
	_delay_ms(PAUSE);
	static dominant_color;
	for(int i=0; i<NUMBER_OF_NODES ; i++){
		dominant_color=random() % 3;
		switch (dominant_color){
				case 0: //red is dominant color
					rgb[i].r = random();
					rgb[i].g = random() % 125;
					rgb[i].b = random() % 125;
					break;
				case 1: //green is dominant color
					rgb[i].r = random() % 125;
					rgb[i].g = random();
					rgb[i].b = random() % 125;
					break;
				case 2: //blue is dominant color
					rgb[i].r = random() % 125;
					rgb[i].g = random() % 125;
					rgb[i].b = random();
					break;
				default: //white
					rgb[i].r = random();
					rgb[i].g = random();
					rgb[i].b = random();
					break;
		}
	}
}

void Chase (void){
	_delay_ms(CHASE_SPEED);
	static int rand=89;
	if (direction == 0){ // value of 0 for direction means its increasing
			if (LED_num > 0){
				rgb[LED_num-1].r = 0;
				rgb[LED_num-1].g = 0;
				rgb[LED_num-1].b = 0;
			}
			rgb[LED_num].r =random();
			rgb[LED_num].g =random();
			rgb[LED_num].b =random();
			LED_num++;
			if (LED_num == NUMBER_OF_NODES)	{
				direction = 1; //switch directions
			}
	}
	else{ //else value if direction means decreasing
		if (LED_num < NUMBER_OF_NODES){
			rgb[LED_num+1].r = 0;
			rgb[LED_num+1].g = 0;
			rgb[LED_num+1].b = 0;
		}
		rgb[LED_num].r =random();
		rgb[LED_num].g =random();
		rgb[LED_num].b = random();
		LED_num--;
		if (LED_num == 0)	{
			direction = 0; //switch directions
		}
	}
}