RGB driver

From pauljmac.com Projects
Jump to: navigation, search

Abstract

This project was for a Halloween prop wand. A tiny circuit board with a AA battery pack and RGB LED was held in the hand with a ~10" acrylic light pipe to pose as the wand. The wand had 4 modes.

RGB cycle mode - The wand cycled through the RGB color spectrum slowly fading into surrounding colors.

Color lock - Locks the wand onto the currently displayed color.

"Tink" mode - The wand slowly pulsates a tan color, much like what you would picture Tinkerbell's wand doing.

Off - Off!


Video of said wand: http://www.youtube.com/watch?v=B4l27Mpw3fE

Parts

Attiny45

RGB LED

NOMO button

2 cell battery pack

Light pipe

Code

Currently there is a bug I was unable to trace that causes the light to very quickly go out at what seems to be random intervals. It’s not totally obvious so I let it slide.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h> 

#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 NOP asm("nop")
#define OUT 1
#define IN 0
#define RED_DEF 2
#define BLUE_DEF 0
#define GREEN_DEF 1

#define PRELOAD 0xCE

volatile uint8_t red=0, green=0, blue=0, mode=0, RGB_mode=0, PWM=100, t0_preload=0xCF,
 last_mode, tink_play=0;
volatile uint16_t button_cooldown=0;

//this is kind of like a play file
//the rutine will play though this file in order
//format is R, G, B in % of light
static unsigned char file1[] PROGMEM =
{
	20,10,0,
	22,11,0,
	25,12,0,
	28,15,0,
	31,18,0,
	35,23,0,
	38,25,0,
	42,30,0,
	45,35,0,
	50,40,0,
	55,45,0,
	59,50,0,
	65,53,0,
	70,58,0,
	75,60,0,
	85,64,0,
	90,70,0,
	95,73,0,
	100,76,0,
	100,78,0,
	100,82,0,
	100,84,0,
	100,84,0,
	100,84,0,
	95,80,0,
	92,76,0,
	90,73,0,
	87,68,0,
	82,62,0,
	79,60,0,
	75,55,0,
	72,53,0,
	70,50,0,
	68,49,0,
	65,46,0,
	63,44,0,
	60,42,0,
	50,40,0,
	47,39,0,
	44,37,0,
	41,34,0,
	38,32,0,
	36,30,0,
	34,28,0,
	32,26,0,
	30,24,0,
	28,22,0,
	26,20,0,
	24,18,0,
	22,16,0,
	20,14,0
};


ISR(TIMER0_OVF_vect){ //SPECIAL COLOR STUFFF
	TCNT0=t0_preload;
	if(mode==1){ //rgb mode
		switch (RGB_mode){ //0 is red++, 1 is green++, 2 is blue ++;
			case 0:
				blue--;
				red++;
				if(red==100){
					RGB_mode=1;
				}
				break;
			case 1:	
				red--;
				green++;
				if(green==100){
					RGB_mode=2;
				}
				break;
			case 2:
				green--;
				blue++;
				if(blue==100){
					RGB_mode=0;
				}
			default:
				break;
			
		}
	}
	else if(mode==3){ //rgb mode
		red=pgm_read_byte(&file1[tink_play]);
		green=pgm_read_byte(&file1[++tink_play]);
		blue=pgm_read_byte(&file1[++tink_play]);
		tink_play++;
		if(tink_play>147){
			tink_play=0;
		}
	}
}

ISR(TIMER1_OVF_vect){ //COLOR UPDATE
	TCNT1=PRELOAD;
	if(bit_get(PINB, BIT(3))==0){ //if button pressed
		if(button_cooldown==0){ 
			mode++;
			button_cooldown=2000;
		}
	}
	if(button_cooldown > 0){
		button_cooldown--;
	}
	if(PWM==red){
		bit_set(PORTB, BIT(RED_DEF));
	}
	if(PWM==green){
		bit_set(PORTB, BIT(GREEN_DEF));
	}
	if(PWM==blue){
		bit_set(PORTB, BIT(BLUE_DEF));
	}
	PWM--;
	if (PWM==0){
		bit_clear(PORTB, BIT(RED_DEF));
		bit_clear(PORTB, BIT(GREEN_DEF));
		bit_clear(PORTB, BIT(BLUE_DEF));
		PWM=100;
	}

}


void timer0_setup(void){
	TIMSK|=(1<<TOIE0);
	TCNT0=t0_preload;
	TCCR0B=(1<<CS02)|(0<<CS01)|(1<<CS00); // 1024 div
}

void timer0_stop(void){
	bit_clear(TIMSK, (BIT(TOIE0)));
	TCCR0B=(0<<CS13)|(0<<CS12)|(0<<CS11)|(0<<CS10);
}

void timer1_setup(void){ //COLOR UPDATE 
	TCNT1=PRELOAD;
	TIMSK|=(1<<TOIE1);
	TCCR1=(0<<CS13)|(1<<CS12)|(0<<CS11)|(1<<CS10); //16 dev

}

void port_setup(void){
	DDRB = (IN<<DDB3)|(OUT<<BLUE_DEF)|(OUT<<GREEN_DEF)|(OUT<<RED_DEF);
	PORTB = (1<<PORTB3); //enable pullup
}


int main(){
	port_setup();
	timer1_setup();
	sei();
	for(;;){
		if (mode >= 5){
			mode=0;
			last_mode=0;
		}
		switch (mode){
			case 0: //off
				red=0;
				green=0;
				blue=0;
				break;
			case 1: //RGB mode
				if(last_mode == 0){
					last_mode=mode;
					blue=100;
					red=0;
					green=0;
					RGB_mode=0;
					t0_preload=0x00; //
					NOP;
					timer0_setup();
				}
				break;
			case 2: //lock
				if(last_mode == 1){
					last_mode=mode;
					timer0_stop();
				}
				break;
			case 3: //tink mode
				if(last_mode == 2){
					last_mode=mode;
					t0_preload=0x00; //
					timer0_setup();
				}
				break;
			case 4: //white
				if(last_mode == 3){
					last_mode=mode;
					timer0_stop();
				}
				red=100;
				green=100;
				blue=100;
				break;
			default:
				break;
		}
	}
}