Project 1 Basic Pulse Width Modulation
More colormixing

OK so that was fun and all...you learned how to use 3 colors and mix them to make 3 more colors. Clearly its a start, but really you know that there's way more colors you can make with the primary red/green/blue. Hell, look closely at a TV/CRT screen and you'll see that all the pixels are also RGB and there are at least a thousand colors a TV can display. Thats because we're only mixing 100% red and 100% blue to make pure magnenta. What we really want to do is mix different proportions of color, as described by the CIE colorchart.

The CIE chart is a triangularish wedge which shows all the colors the eye can see, where the top left corner is pure green, the bottom right is pure red and the bottom left is pure blue. The numbers on the perimeter are corresponding wavelength (in nanometers) The inscribed triangle is a demonstration of actual color generated. For example, lets say our RGB LED can generate the following pure wavelengths: 700nm (red), 545nm (green) and 400nm (blue). That would correspond to the points plotted on the CIE chart and so we can make any of the colors inside the triangle, but none outside of it. Of course, your CRT/LCD monitor also has a triangle of possible colors, which explains why the sections of color outside the triangle don't really look different than the color inside.

We don't actually know the wavelengths of the LEDs in this LED because we don't have a datasheet, but it's probably close to the above numbers.

Controlling LED brightness
So we want to make a certain color in the CIE colorspace, lets say a bright light pink.That means we probably want something like 60% blue, 100% red and 30% green. Turning on red 100% is easy: just turn it on all the way. But how does one turn blue on only 60%? One way is to change the resistance...a larger resistor means less current means less power means less light. But thats a pain and hard to calibrate. Instead we'll turn on the blue light on and off really fast: so its on all the way, 60% of the time and all the way off 40% of the time. If we do it fast enough, our optic nerve 'averages' out the on time and off time and we see it as if its just dimmer. This sort of technique is called Pulse Width Modulation. Basically the fast on/off stuff is like 'pulsing' the LED and the width modulation is what makes it appear brighter (say if the width is 90%) or dimmer (say if its only 10%)
First PWM
For the sake of space, we don't include all off the common code, but you are free to read it all in the source file.
00029 int main(void) {
00030   // initialize the direction of the B port to be outputs
00031   // on the 3 pins that have LEDs connected
00032   set_output(DDRB, RED);  
00033   set_output(DDRB, GREEN);
00034   set_output(DDRB, BLUE);
00035 
00036   // start with all the LEDs off
00037   output_low(PORTB, RED);
00038   output_low(PORTB, GREEN);
00039   output_low(PORTB, BLUE);
00040 
00041   // simple pulse width modulation
00042   while (1) {
00043     // red led is 'off' for 3x longer than it is on...a PWM duty cycle of 25%
00044     output_high(PORTB, RED);
00045     delay_ms(1);
00046     output_low(PORTB, RED);
00047     delay_ms(3);
00048   }
00049 }

OK so this is sort of like ledblink.c except now we're blinking the LED much faster and we're not blinking it evenly: the led is on for 1ms and off for 3. In other words, the positive pulse width is 25% (1ms out of 4ms) and the negative pulse width is 75% (3ms out of 4ms). The period of the pulse is 4ms, thats the total time for one cycle of on/off.

Compile and upload this code.
Exercises
Experiment with the PWM code above
  1. Try to create PWM waveforms of 25%, 50%, 75% for green and blue LEDs also
  2. Adapt the code so that, with a 4ms PWM period, you have red on for 25%, green on for 50% and blue on for 75%
  3. Adjust the period to be 10ms, 20ms, 50ms, etc. At what point does the pulsing become obvious?

After each exercise, (gently) shake the board, to examine the PWM 'trails'

PWM Fading

We've observed that we can make the red LED appear 'dimmer' by PWMing it. For our next trick, we will make the LED 'pulse,' a common trick used on consumer electronics. To do this, we will ramp up the PWM from 0% to 100% over the course of a second or so.

00030 int main(void) {
00031   int8_t i;
00032 
00033   // initialize the direction of the B port to be outputs
00034   // on the 3 pins that have LEDs connected
00035   set_output(DDRB, RED);  
00036   set_output(DDRB, GREEN);
00037   set_output(DDRB, BLUE);
00038 
00039   // start with all the LEDs off
00040   output_low(PORTB, RED);
00041   output_low(PORTB, GREEN);
00042   output_low(PORTB, BLUE);
00043 
00044   // simple pulse width modulation
00045   while (1) {
00046     // fade
00047     for (i=0; i <= 25; i++) {
00048       output_high(PORTB, RED);
00049       delay_ms(25-i);
00050       output_low(PORTB, RED);
00051       delay_ms(i);
00052     }  
00053     // brighten
00054     for (i=25; i >= 0; i--) {
00055       output_high(PORTB, RED);
00056       delay_ms(25-i);
00057       output_low(PORTB, RED);
00058       delay_ms(i);
00059     } 
00060   }
00061 }

Note that, here, we have two subloops in the main loop. The first one starts with the LED all the way on, and then reduces the brightness a 1/25th at a time, until the led is off. Then it ramps up again, turning the LED on more and more until its on all the way, then it continues.

Exercises
  1. Take the PWM fading code and modify it so that it starts with red on all the way on and blue all the way off and then fades to red being all the way off and blue all the way on.
May 17, 2011 20:07