/* RGB LED Controller Date: 7-21-05 Author: Evan Dudzik *This program controls two common-anode RGB LEDs via software-generated PWM. *The outputs are low for "on" and tri-stated for "off", for directly driving common-anode LEDs. *The available color values are 0 - 255 (red to yellow to green to blue to purple to red) *Each LED's color is either solid (chosen with button1 and button2) or it is set by whatever character arrives via serial input (using hardware UART) *There are 4 modes: 0 = both LEDs serial input color 1 = LED1 fixed, LED2 serial 2 = LED1 serial, LED2 fixed 3 = both LEDs fixed color *The mode is chosen by cycling with the mode_button. */ #include #pragma DATA 0x2007, 0x3F50//_INTRC_IO & _WDT_OFF & _LVP_OFF //define important SFR bits for interrupts, UART, and ADC volatile bit go @ ADCON0.GO; volatile bit gie @ INTCON.GIE; volatile bit rcie @ PIE1.RCIE; volatile bit peie @ INTCON.PEIE; volatile bit rcif @ PIR1.RCIF; volatile bit trmt @ TXSTA.TRMT; //define I/O pins bit RLED1 @ PORTA.0; bit GLED1 @ PORTA.1; bit BLED1 @ PORTA.2; bit RLED2 @ PORTA.3; bit GLED2 @ PORTA.4; bit BLED2 @ PORTB.4; bit button1 @ PORTB.0; bit button2 @ PORTB.1; bit mode_button @ PORTB.3; char mode; char r1val, g1val, b1val; char r2val, g2val, b2val; char color1, color2, color_in; void color_decode(); // interrupt service routine void interrupt(void) { if(rcif) //UART Recieve Interrupt { color_in = rcreg; rcreg = 0; } } //Function: update LED colors with latest received color if needed inline void checkserial() { if(mode!=3) { if(mode!=1) //mode 0 or 2 = LED1 serial input { if(color1!=color_in) { color1=color_in; color_decode(); } } if(mode<2) //mode 0 or 1 = LED2 serial input { if(color2!=color_in) { color2=color_in; color_decode(); } } } } //Function: perform one PWM cycle // (all 6 output lines = both LEDs) void PWM_cycle() { char a; RLED1=0; GLED1=0; BLED1=0; RLED2=0; GLED2=0; BLED2=0; for(a=0; a<255; a++) { if(a>=r1val) { RLED1 = 1; } if(a>=g1val) { GLED1 = 1; } if(a>=b1val) { BLED1 = 1; } if(a>=r2val) { RLED2 = 1; } if(a>=g2val) { GLED2 = 1; } if(a>=b2val) { BLED2 = 1; } delay_10us(5); } checkserial(); } //Function: calculate PWM duty cycles for R, G, and B LED segments // based on color1 and color2 values (0-255) void color_decode() { if(color1<=85) { r1val = (85 - color1) * 3; g1val = color1 * 3; b1val = 0; } else if(color1<=170) { r1val = 0; g1val = (170 - color1) * 3; b1val = (color1 - 85) * 3; } else { r1val = (color1 - 170) * 3; g1val = 0; b1val = (255 - color1) * 3; } if(color2<=85) { r2val = (85 - color2) * 3; g2val = color2 * 3; b2val = 0; } else if(color2<=170) { r2val = 0; g2val = (170 - color2) * 3; b2val = (color2 - 85) * 3; } else { r2val = (color2 - 170) * 3; g2val = 0; b2val = (255 - color2) * 3; } } //Function: check for button presses and change mode/colors as needed inline void checkbuttons() { if(!mode_button) { if(mode==3) { mode=0; } else { mode++; } //cycle modes color_decode(); while(!mode_button){ PWM_cycle(); } } if(mode!=0) { if(!button1) { if(mode!=2) //mode 1 or 3 = LED1 fixed color { color1++; color_decode(); } } if(!button2) { if(mode!=1) //mode 2 or 3 = LED2 fixed color { color2++; color_decode(); } } } } void main() { porta = 00000000b; trisa = 11100000b; //0 = Output, 1 = Input portb = 00000000b; trisb = 11101111b; osccon = 01110000b; //internal oscillator @ 8MHz ansel = 00000000b; //all A/D off cmcon = 00000111b; //comparators off // configure USART spbrg = 51; //9600 baud @ 8MHz txsta=00100100b; //full duplex asynchronous rcsta=10010000b; //full duplex asynchronous rcie = 1; //enable RX interrupt peie = 1; //enable peripheral interrupts (needed for RX) gie = 1; //global interrupt enable //initialize color1=0; color2=0; mode = 0; //main program loop while(1) { checkbuttons(); PWM_cycle(); PWM_cycle(); PWM_cycle(); } }