Arduino Pulse Width Modulation

[blip.tv http://blip.tv/play/wkegzGEA width=”648″ height=”380″]

The digital pins on the Arduino board can be set (with code) to output either HIGH (5V) or LOW (0V) — essentially ON or OFF. This is great for applications like blinking LEDs or activating relays.

But what if we wanted an output voltage somewhere in between 0V and 5V? This might be useful in applications like controlling the speed of a DC motor, or “dimming” an LED.

Well, the digital pins cannot directly produce an analog voltage; as we’ve said, they’re either HIGH or LOW. But it turns out we can simulate these “in-between” voltages using a technique called Pulse Width Modulation, or PWM.

First off, don’t panic. PWM sounds complicated, but as we’ll see, the concept is very simple, and the implementation is even easier, especially on the Arduino.

Let’s say we want to make an LED shine with half of its normal intensity when supplied with 5 volts. Since we can’t use the Arduino’s digital pins to directly supply 2.5V, we’ll “pulse” the output pin on and off — really fast. You may have noticed this effect when you played with the Arduino’s “Blink” sketch. If you blink an LED fast enough — that is, if the delay between blinks is short enough — the LED will appear to be lit continuously, but just a little bit dimmer than it was originally.

It’s easy to visualize this concept using the graphs below. When you plot voltage over time, you can see that the pin is pulsing between HIGH and LOW at regular intervals. Since this on-off pulsing is happening so quickly, the connected LED will “see” the result as a 50% reduction in the normal voltage (in this example), and will glow at roughly half its normal intensity.

Image credit: Tom Igoe

Image credit: Tom Igoe

We can vary the output voltage percentage (the “effective voltage”) by regulating — or “modulating” — the width of the pulse. For example, if we make the HIGH pulse 25% as “wide” (in time) as the LOW pulse, the LED will appear to glow with 25% intensity.

Image credit: Tom Igoe

Image credit: Tom Igoe

“Okay, great,” you’re saying, “But how do I do this on the Arduino?” Well, there are a couple of ways. First, you could write a sketch that blinks the LED between HIGH and LOW really fast, as we discussed above. However, this approach requires the full attention of the Arduino all the time; that is, if you want the Arduino to do anything else, you’ll be interrupting the pulse loop.

Luckily, the Arduino designers have already solved this problem for us with three dedicated pins and the analogWrite() command.

Notice on the Arduino board there are three digital pins (9-11) which are labeled PWM. Devices (like LEDs) connected to these pins can employ continuous pulse width modulation using only the analogWrite() command like so:

/*
 * A simple PWM example
 */

int pin         =  11;     // LED connected to PWM pin 11
int pulsewidth  =  127;    // Any value between 0 and 255

void setup() {
  // None required for analogWrite!
}

void loop() {
  analogWrite(pin, pulsewidth);
}

The example above should cause the connected LED to glow at about 50% intensity (255/2 = 127ish). Play around with the value of the pulsewidth variable and note the changes in LED brightness.

Now, let’s take this concept one step further. What if we varied the effective voltage to the LED over time? If we could devise a way to “fade” the pulsewidth from zero to 255 and back again, then the LED would pulsate, as in the video above. Here’s the code for that, using three LEDs this time, connected to pins 9-11:

/*
 * Pulsating LEDs with Pulse Width Modulation
 */

int green   = 11;            // Digital pin 11 - Green LED
int red     = 10;            // Digital pin 10 - Red LED
int blue    = 9;             // Digital pin 9  - Blue LED
int time    = 5;             // define delay element
int pulsewidth;              // define pulsewidth (0-255)

void setup() {
  // None required for analogWrite!
}

void loop() {
  // slowly fade the LEDs to full brightness
  for (pulsewidth=0; pulsewidth = 0; pulsewidth--){
    analogWrite(green, pulsewidth);
    analogWrite(red, pulsewidth);
    analogWrite(blue, pulsewidth);
    delay(time);
  }
}

Cool, huh?

References

1. Tom Igoe, “Analog Output
2. Sebastian Tomczak, “PWM and You: A Quick Primer

Advertisements

9 responses to “Arduino Pulse Width Modulation

  1. FAR out! Can’t wait to get home to test it out. Maybe do a light house pattern or an airport beacon. Mix it up, you know? Does using the PWM require any change in the resistance I would normally use for the LED?

  2. Ooh I love the airport beacon idea! Also, if you have some of those clear tri-color LEDs, I think you can use PWM to color-fade with them. No change in resistor value is required; I used plain old brown-black-red-gold 1KΩ resistors for all LEDs.

  3. Awesome. That’s cool! From a newbie perspective, I’m wondering how many LEDs a single Arduino could control at once like that, possibly adding on shift registers of some sort? Time to do some more research… :)

  4. So how would I incorporate this with a larger number of leds? Wouldn’t I need a larger voltage source?

  5. Scott: If you’re trying to control large numbers of LEDs with Arduino, while using as few output pins as possible, you’ll need to use a technique like Charlieplexing. PWM should work there as well, but I haven’t tried it personally!

  6. Hi brian,

    I chanced upon your website. I’m currently trying to work on a CO gas sensor with the Arduino Mega. For the MQ7 CO Gas sensor (data sheet) to work, it requires a pulse of 1.4V for 60 seconds and 5V for 90 seconds.

    So, if i read your article properly and did my calculation correctly, the pulsewidth should be 255 for 90secs and and 71.4 for 60 seconds.Am I right?

    Thanks for the great article. I hope you reply soon.

  7. @Ray: Thanks for stopping by. I’m not sure I’m qualified to answer your question. If I were you, I’d contact the sensor manufacturer and explain your setup. If all else fails, the Adafruit Forums are a good place to ask Arduino project questions.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s