#define LED_PIN_ON 0xff //PB0 (0x01) #define LED_PIN_OFF 0xfe //need this defined to speed up timings #define PACKT_SIZE 24 //size of color packet 3x 8bit #define NUM_LED 300 //Max number LEDs, you can tweak this to slow down color changes #define MAX_BRIGHTNESS 150 //max value 255!!! #define MIN_BRIGHTNESS 10 //min value 1!!! #define RGB_SEED_1 0xf02802 //RGB seed 1 (greens/reds) #define CUSTOM_0 0xFF0070 //Custom color 0 (cyan) #define CUSTOM_1 0x00CCDF //Custom color 1 (pink) #define CUSTOM_2 0x00d00f //Custom color 2 (light green) #define CUSTOM_3 0xFF0000 //Custom color 3 (red) #define CUSTOM_4 0x150F4F //Custom color 4 (blue - Purple) #define CUSTOM_5 0x550F6F //Custom color 5 (dim-purple) //Yes I have commited a sin, behold THE global variables uint8_t inputs; //Store user inputs uint32_t rgb_glb = 0; //Full RGB color code bool rgb_arr[24]; //array of bits of rgb_glb uint32_t rgb[3]; //rgb_glb seperated by color (ideally this would be 8-bit, but this creates a headache for bitshifting) uint16_t rgb_counter =0x0; //counter for rgb pulse algorithm bool dir_arr[3] = {false, true, true}; //flags for rgb pulse algorithm, tweaking this starting contition will change the rgb strobing pattern bool rgb_flag = false; //Flag to enable different strobe pattern //Configure ATTINY registers void setup() { DDRB = ~LED_PIN_OFF; //Configure PB0 as Output (all other pins as inputs) PORTB = LED_PIN_OFF; //Configure PULL-UPs on inputs // rgb[0] = (rgb_glb >> 16) & 0xff; //Configure rgb array // rgb[1] = (rgb_glb >> 8) & 0xff; // rgb[2] = rgb_glb & 0xff; uint16_t counter = 500; //Turn 500 LED's off while (counter > 0) { set_rgb(); counter--; } } //Main Function void loop() { uint16_t counter = NUM_LED; while (1) { counter = NUM_LED; //Reset Counter variable PORTB = LED_PIN_OFF; //This is part of RESET command //Different Cases for the inputs inputs = PINB & 0x16; //Pull user inputs if(inputs == 0b00010110){ //Setting #0 = OFF (max 0.1A w/ 50LED) rgb_glb = 0x000000; rgb_flag = false; }else if(inputs == 0b00010100){ //Setting #1 = Custom0 (max 1.01A w/ 50LED) rgb_glb=CUSTOM_0; rgb_flag = false; }else if(inputs == 0b00010010){ //Setting #2 = Custom1 (max 0.90A w/ 50LED) rgb_glb = CUSTOM_1; rgb_flag = false; }else if(inputs == 0b00010000){ //Setting #3 = Custom2 (max 0.56A w/ 50LED) rgb_glb = CUSTOM_2; rgb_flag = false; }else if(inputs == 0b00000110){ //Setting #4 = Custom3 (max 0.65A w/ 50LED) rgb_glb = CUSTOM_3; rgb_flag = false; }else if(inputs == 0b00000100){ //Setting #5 = Custom4 (max 0.54A w/ 50LED) rgb_glb = CUSTOM_4; rgb_flag = false; }else if(inputs == 0b00000010){ //Setting #6 = Custom5 (max 0.34A w/ 50LED) rgb_glb = CUSTOM_5; rgb_flag = false; }else if(inputs == 0b00000000){ //Setting #7 = RGB pattern 1 (max 1.0 A w/ 50LED) if(!rgb_flag){ rgb_glb = 0xf00802; rgb_flag = true; rgb[0] = (rgb_glb >> 16) & 0xff; //Configure rgb array rgb[1] = (rgb_glb >> 8) & 0xff; rgb[2] = rgb_glb & 0xff; } RGB_strobe(); } delay_clk(300); //Hold data low for atleast 50us (RESET) format(); //Format color code in rgb_arr //This loop sends data to all leds in string while (counter > 0) { set_rgb(); counter--; } __asm( "nop" ); //Fix timing error __asm( "nop" ); //between different 24bit packets __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); } } /* Function: push data from rgb_glb into rgb_arr[] */ void format(void) { uint32_t temp_rgb = rgb_glb; for (uint8_t i = 0; i < 24; i++) { rgb_arr[i] = (temp_rgb) % 2; temp_rgb = temp_rgb >> 1; } return; } /* Function: Updates the various colors based on rgb_counter. Calls update_color() to update each rgb_glb */ void RGB_strobe(void ) { rgb_counter++; //We expect this to overflow back to 0 uint16_t temp_counter = rgb_counter>>6; //You can tweak this value to slow down color changes //Fastest updating, red if((temp_counter & 0x1)==0x1){ update_color(0); } //slightly slower updating, green temp_counter>>1; if((temp_counter & 0x1)==0x1){ update_color(1); } //slowest updating, blue temp_counter>>1; if((temp_counter & 0x1)==0x1){ update_color(2); } //Throw the data back into the global variable rgb_glb = (rgb[0]<<16) & 0xff0000; rgb_glb |= (rgb[1] << 8) & 0x00ff00; rgb_glb |= rgb[2] & 0x0000ff; } /* Function: Increment or decrement a single element of rgb[]. Index 0 = red, 1 = green, 2 = blue. */ void update_color(uint8_t index){ //Avoid invalid index if(index > 2){ index = 0; } //update color code if(rgb[index] >MAX_BRIGHTNESS){ rgb[index]--; dir_arr[index] = false; return; }else if(rgb[index] < MIN_BRIGHTNESS ){ rgb[index]++; dir_arr[index] = true; return; } //If we don't need to change our counting direction //just follow the previous direction in dir_arr[] if(dir_arr[index]){ rgb[index]++; }else{ rgb[index]--; } return; } /* Function: Sends Green -> Red -> Blue data to WS2812B led. Parameters: - grb: xxxx xxxx - xxxx xxxx - xxxx xxxx (24 bit color code) */ void set_rgb(void) { //Send Green (MSB -> LSB) PORTB = LED_PIN_OFF; send_bit(rgb_arr[15]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[14]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[13]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[12]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[11]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[10]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[9]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[8]); //Send Red (MSB -> LSB) PORTB = LED_PIN_OFF; send_bit(rgb_arr[23]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[22]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[21]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[20]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[19]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[18]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[17]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[16]); //Send Blue (MSB -> LSB) PORTB = LED_PIN_OFF; send_bit(rgb_arr[7]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[6]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[5]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[4]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[3]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[2]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[1]); PORTB = LED_PIN_OFF; send_bit(rgb_arr[0]); PORTB = LED_PIN_OFF; return; } /* Function: delay by approx. n clk cycles. */ void delay_clk(uint16_t n) { while (n > 0) { __asm( "nop" ); n = n - 1; } } /* Function: Sends a single bit 1 or 0 */ void send_bit(bool value) { if (!value) { //send a zero PORTB = LED_PIN_ON; //want 400ns +width __asm( "nop" ); //7x "nop" __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); // __asm( "nop" ); PORTB = LED_PIN_OFF; //want 850ns -width __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); } else { //Send a One PORTB = LED_PIN_ON; //0.80us high __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // PORTB = 0x00; //To speed up process I had to do this externally // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); // __asm( "nop" ); } }