Pulse-Width Modulation

Making an LED "Breathe"

Pulse-Width Modulation

Introduction

This project discusses pulse-width modulation (PWM) and how to use it to make an LED “breathe.” The term “breathing” is used to describe the action of an LED repeatedly growing brighter (until it is completely on) and dimmer (until it is completely off).

Before you begin, you should:
  • Understand how to wire LEDs.
  • Understand the difference between digital and analog signals.
After you're done, you should:
  • Have a better understanding of pulse-width modulation and how it is implemented by hardware.
  • Understand the use of the setup(), loop(), and analogWrite() functions.

Inventory:

Qty Description Typical Image Schematic Symbol Breadboard Image
1 LED
1 Resistor

(10 kΩ)

Defining Pulse-Width Modulation

Pulse-width modulation (PWM) is a method of converting digital signals to analog signals. Due to the strictly HIGH/LOW nature of digital signals, it is not possible to set a pin to any desired voltage. Despite this, we can approximate a voltage over time using PWM. We can accomplish this by switching between HIGH and LOW very quickly to establish an average voltage that is between 0 and 3.3V.

PWM, as it's name indicates, modulates the pulse width, or more simply, it changes how long the signal is HIGH compared to when it is LOW. When working with PWM, a duty cycle is used to control the average voltage. The duty cycle is the ratio of the signal length to the period of the signal. The duty cycle determines the average voltage that the signal will produce.

Formally, the duty cycle is defined as the length of time of the pulse (the time the signal is HIGH), divided by the period of the signal (time from one rising edge to the next). Figure 2 displays the general equation to find the duty cycle. For more information on how PWM is implemented with the chipKIT™ hardware, click on the red button to the right.

Figure 1. PWM structure.

 

 

Figure 2. Equation for calculating duty cycle.

Step 1: Setting up the Circuit

The circuit we are going to build is very simple. It is basically the same setup as the one in the Blinking an External LED project, except that the pin connected to the LED will be pin 6 rather than pin 3. The circuit is a simple series circuit with the resistor and LED connecting the PWM pin to ground, as seen in Fig. 3.

Figure 3. Completed circuit for controlling an LED with PWM.
  1. Use a wire to connect pin 6 to the breadboard.
  2. Use the 10 kΩ resistor to connect the wire to another row on the breadboard.
  3. Place the LED across the valley with the anode (longer leg of the LED) on the same row as the end of the resistor.
  4. Use a second wire to connect the cathode of the LED (shorter end of LED) to one of the ground (GND) pins on the chipKIT board.

Pulse-Width Modulation in MPIDE

MPIDE has a function that allows us to set certain pins to output a PWM signal. Digital pins with an underlined number on the chipKIT board are PWM capable. The function we will use to enable PWM for these pins is analogWrite(). This function requires two inputs, the pin number, and the PWM value to set the PWM. The PWM value will be a number from 0 to 255.

The average voltage of a PWM pin is directly proportional to the PWM value inputted into analogWrite(). This relationship is shown in Fig. 4, and it should be noted that the value of the pin in PWM seems to max out at 3.2V.

Figure 4. Average voltage from analogWrite().

Remember, only a few pins support PWM. If analogWrite() is used on a pin that does not support PWM, it will always default to either HIGH (if the PWM value is above 128) or to LOW (if the PWM value is below 128).

Step 2: Writing the Program

We will use three variables to control the “breathing” LED. The first variable is the value that we will use to set the duty cycle. It will have the type int and will initially be set to 0. We will call it valuePwmGlb since it is the value of the PWM and a global variable.

The second variable will be used to increase the brightness of the LED. We will have the variable switch back and forth between +1 and -1 to brighten and dim the LED, respectively. It will be an int, and initially set to 1. Following the same naming convention, we will call this variable incGlb.

The last variable we will use keeps track of the PWM pin connected to our LED. It will be a const int, since we don't want the value to accidently change. We will call it ledGlb since it is a global variable that keeps track of what PWM pin we are using.

The setup() and loop() Functions

The setup() function is very short, considering that it only sets a single pin. If you need to see it, it is towards the bottom of the page in the completed code for the sketch.

The first thing we will do within the loop() function is to modify the LED's brightness by incrementing the PWM value. This can be done with the following line of code:

                  valuePwmGlb += incGlb;

We will then check to see if the value is still within the bounds of analogWrite(). The first boundary we will check is whether valuePwmGlb is greater than or equal to 255. If it is, we multiply incGlb by -1, and set valuePwmGlb to 255 to make the LED dim from its maximum brightness. The second boundary we will check is whether valuePwmGlb is less than or equal to 0. If it is we will multiply incGlb by -1, and set valuePwmGlb to 0 to make the LED brighten from its dimmest point. Finally, we will write valuePwmGlb to pin ledGlb and delay for 10 milliseconds so we have time to see the LED brighten and fade. The resulting code should look like this:

                  void loop()
                  {
                    valuePwmGlb += incGlb;
                    if(valuePwmGlb >= 255){
                      incGlb *= -1;
                      valuePwmGlb = 255;
                    else if(valuePwmGlb <= 0){
                      incGlb *= -1;
                      valuePwmGlb = 0;
                    }
                    analogWrite(ledGlb = 0);
                    delay(10);
                  }

Step 3: Compiling the Program

Now we have all of the information we need to make an LED “breathe.” The code for our sketch should look something like this:

// pwm state
int valuePwmGlb = 0;
// increment variable
int incGlb = 1;
// The external LED is on pin 6.
const int ledGlb = 6;

void setup()
{
  /* Set LED (pin 6) to output, pin 6 is one of the 
  *  pins that can be used with pulse width
  *  modulation.
  */
  pinMode(ledGlb,OUTPUT);
}

void loop()
{
  valuePwmGlb += incGlb;
  if(valuePwmGlb >= 255){     // If pwm state is at max. (means that incGlb was positive)
    incGlb *= -1;                // Make incGlb negative to dim LED.
    valuePwmGlb = 255;           // Set valuePwmGlb to max(255) in case it goes over.
  }else if(valuePwmGlb <= 0){ // if pwm state is at min. (means that incGlb was negative)
    incGlb *= -1;                // Make incGlb positive to brighten LED.
    valuePwmGlb = 0;             // Set valuePwmGlb to min(0) in case it goes under.
  }
  // write the pwm state to LED and wait 10 milliseconds.
  analogWrite(ledGlb,valuePwmGlb);
  delay(10);
}

Summary:

In this project, we used pulse-width modulation to make an LED “breathe,” a term which describes the action of an LED repeatedly growing brighter and dimmer. Pulse-width modulation is a method used to convert digital signals to analog signals, which is integral to utilize for this exercise since it is not possible to set a pin to any desired voltage, due to the HIGH/LOW nature of digital signals.

Core Concepts:
  • Pulse Width Modulation (PWM)
  • Duty Cycle
Functions Introduced:
  • analogWrite(pin, value)

  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.
  • Circuit and breadboard images were created using Fritzing.