Overview
In this part, we'll take what we've already done and extend it so that we can do more mixing: and cover the entire CIE triangle colorspace with the RGB LED
Functional Abstraction
Our first step is to abstract out the actual PWM work into a function, to make it cleaner and easier to use. We will also use this opportunity to speed up the PWM frequency so that we will get less flickering and more 'resolution' to our colormixing.
00029 void delay_10us(uint8_t us) 00030 { 00031 uint8_t delay_count = F_CPU / 2000000; 00032 volatile uint8_t i; 00033 00034 while (us != 0) { 00035 for (i=0; i != delay_count; i++); 00036 us--; 00037 } 00038 } 00039 00040 void do_pwm_fade(uint8_t start_duty, uint8_t end_duty, uint8_t rate) { 00041 uint8_t duty; 00042 uint8_t j; 00043 00044 duty = start_duty; 00045 while (duty != end_duty) { 00046 for (j = 0; j < rate; j++) { 00047 output_low(PORTB, RED); 00048 delay_10us(duty); 00049 output_high(PORTB, RED); 00050 delay_10us(255-duty); 00051 } 00052 if (start_duty < end_duty) { 00053 duty++; 00054 } else { 00055 duty--; 00056 } 00057 } 00058 } 00059 00060 int main(void) { 00061 // initialize the direction of the B port to be outputs 00062 // on the 3 pins that have LEDs connected 00063 set_output(DDRB, RED); 00064 set_output(DDRB, GREEN); 00065 set_output(DDRB, BLUE); 00066 00067 // start with all the LEDs off 00068 output_low(PORTB, RED); 00069 output_low(PORTB, GREEN); 00070 output_low(PORTB, BLUE); 00071 00072 // simple pulse width modulation 00073 while (1) { 00074 // go from 0% duty cycle to 100% 00075 do_pwm_fade(0, 255, 3); 00076 // now back again 00077 do_pwm_fade(255, 0, 3); 00078 } 00079 } 00080
In this case, we have reduced the minimum timing resolution from 1ms to 10us (100 times smaller). This means we can easily extend our resolution from 25 to 255 (we could go even farther, but 255 is plenty). We have also written a function that fades from one PWM duty cycle to another, in this case pulsing an LED on and off.
Exercises
- Extend the function do_pwm_fade() to also take a port (which is uint16_t type) and a pin (uint8_t) so that you can easily change what LED is being faded to/from
- Extend the resolution from 8-bit to 16-bit
ROYGBIV
Finally we'll do what we really want, to fade smoothly from red to orange to yellow to green to blue to indigo to violet back to red.
00017 void do_pwm(uint8_t r_duty, uint8_t g_duty, uint8_t b_duty, uint8_t rate) { 00018 uint8_t i; 00019 00020 while (rate != 0) { 00021 output_high(PORTB, RED); 00022 output_high(PORTB, GREEN); 00023 output_high(PORTB, BLUE); 00024 00025 for (i=0; i < 255; i++) { 00026 if (i == r_duty) 00027 output_low(PORTB, RED); 00028 if (i == g_duty) 00029 output_low(PORTB, GREEN); 00030 if (i == b_duty) 00031 output_low(PORTB, BLUE); 00032 } 00033 rate--; 00034 } 00035 } 00036 00037 int main(void) { 00038 uint8_t i; 00039 00040 // initialize the direction of the B port to be outputs 00041 // on the 3 pins that have LEDs connected 00042 set_output(DDRB, RED); 00043 set_output(DDRB, GREEN); 00044 set_output(DDRB, BLUE); 00045 00046 // slowly turn red on 00047 for (i=0; i<255; i++) 00048 do_pwm(i, 0, 0, 5); 00049 00050 while (1) { 00051 // slowly turn green on too 00052 for (i=0; i<255; i++) 00053 do_pwm(255, i, 0, 15); 00054 00055 // now turn red off 00056 for (i=255; i>0; i--) 00057 do_pwm(i, 255, 0, 15); 00058 00059 // slowly turn on blue 00060 for (i=0; i<255; i++) 00061 do_pwm(0, 255, i, 15); 00062 00063 // turn off green 00064 for (i=255; i>0; i--) 00065 do_pwm(0, i, 255, 15); 00066 00067 // turn on red 00068 for (i=0; i<255; i++) 00069 do_pwm(i, 0, 255, 15); 00070 00071 // turn off blue 00072 for (i=255; i>0; i--) 00073 do_pwm(255, 0, i, 15); 00074 } 00075 } 00076
Exercises
- Make do_pwm() generate your favorite color. Try also to make the purest white light you can.
- Try extending the resolution to more than 8 bits, or changing the speed of the fade.
- Try to create a full color do_pwm_fade(), that will fade from one RGB value to another. This is rather difficult because of the different rates, but it might be fun to try.