The Arduino can only output two voltages – 0 volts and 5 volts. But many devices like LEDs, servos, and motors need to be powered by a range of voltages between 0 volts and 5 volts. Luckily, the Arduino is capable of pulse width modulation, which can be used to simulate any voltage between 0 volts and 5 volts.

In this article, we will learn how pulse width modulation works and how to generate pulse width modulation signals with an Arduino Uno.

Watch the video for this tutorial here:

The 3-in-1 Smart Car and IOT Learning Kit from SunFounder has everything you need to learn how to master the Arduino. It includes all of the parts, wiring diagrams, code, and step-by-step instructions for 58 different robotics and internet of things projects that are super fun to build!

Pulse Width Modulation

A pulse width modulation signal is made up of short, high frequency pulses of current. The signal looks like a square wave, with the voltage switching from 5 volts to 0 volts very quickly:

Pulse Width and Cycle Duration Diagram.png

On the Arduino, the pulse width modulation frequency is around 500 Hz, so there are 500 of these cycles happening every second. The duration of each cycle is only about 2 milliseconds.

The duration of the high part of the signal is called the pulse width. The duration of the high and low parts of the signal is called the cycle duration. The percentage of the pulse width duration to the cycle duration is called the duty cycle:

Duty Cycle Formula 3.png

By changing the duty cycle, we can change the apparent voltage to any value between 0 and 5 volts:

100% Duty Cycle Diagram with Voltage and analogWrite Values CROPPED.png

For example, with a duty cycle of 50%, the pulse width is 50% of the cycle, so the apparent voltage is 50% of 5 volts, or 2.5 volts. This corresponds to an analogWrite value of 127.

Pulse width modulation signals can only be generated from Arduino pins that have a “~” next to them:

Arduino Pulse Width Modulation Pins

Use analogWrite() to Generate Pulse Width Modulation Signals

The analogWrite() function can generate a pulse width modulation signal. It takes two arguments, pin and value:

analogWrite(pin, value);

The pin argument is the pin number where the pulse width modulation signal will be generated. The value argument is the analogWrite value that corresponds to the duty cycle of the pulse width modulation signal. To find the analogWrite value that will produce a pulse width modulation signal with a specific apparent voltage, use this formula:

Formula to Convert Voltage to analogWrite Value.png

Example Project

Let’s build an example project that uses pulse width modulation to increase and decrease the brightness of an LED automatically.

These are the parts you’ll need to build the project:

Follow this diagram to connect the LED and current limiting resistor to the Arduino:

PWM Wiring Diagram.png

The current limiting resistor can have any value from 220 Ohms to 1K Ohms.

Programming the Arduino for Pulse Width Modulation

This program will make the LED increase to 100% brightness then decrease to 0% brightness, in an infinite loop.

Once the circuit is connected, upload this code to the Arduino:

int ledPin = 6;
int brightness = 0;
int fadeAmount = 5;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  analogWrite(ledPin, brightness);

  brightness = brightness + fadeAmount;

  if (brightness <= 0 || brightness >= 255) {
    fadeAmount = -fadeAmount;
  }

  delay(30);
}

Explanation of the Code

At the top of the sketch, we declare an int variable called ledPin to store the pin number connected to the LED. Then we declare an int variable called brightness, which will store the analogWrite values as they cycle between 0 and 255. We also declare a variable called fadeAmount, which will be used to control how quickly the LED fades on and off.

In the setup() section, we use the pinMode() function to set the ledPin as an output.

In the loop() section, we have an analogWrite() function to generate the pulse width modulation signal. The first argument is the pin number that will generate the pulse width modulation signal, so we use the ledPin variable as the first argument. The second argument is the analogWrite value that sets the duty cycle. We declared a variable called brightness to store that value, so it’s used as the second argument.

The next line is brightness = brightness + fadeAmount;. This takes the brightness variable and adds the fadeAmount variable to it each time through the loop. We declared fadeAmount equal to 5, so this will make the brightness variable increase by 5 with each cycle of the loop.

Then we have an if statement with a condition that says “if brightness is less than or equal to 0, or brightness is greater than or equal to 255″, execute the code in the body. In the body of the if statement we have fadeAmount = -fadeAmount;.

How the Program Works

At the beginning of the program, brightness is set equal to 0:

int brightness = 0;

In the first cycle through the loop() section, brightness equals 0, so a pulse width modulation signal with a duty cycle of 0% will be sent to the ledPin (pin 6) and the LED will be completely off:

analogWrite(ledPin, brightness);

On the next line, the fadeAmount variable is added to the brightness variable. We declared fadeAmount equal to 5 at the top of the sketch, so brightness will now equal 5:

brightness = brightness + fadeAmount;

Now the condition of the if statement asks “is brightness less than or equal to 0, or greater than or equal to 255?”:

if (brightness <= 0 || brightness >= 255) {
  fadeAmount = -fadeAmount;
}

No it’s not, brightness is equal to 5. So the code inside the if statement is skipped, and the program jumps to the first line after the if statement, which is a delay of 30 milliseconds:

delay(30);

Now the program returns to the top of the loop() section. The brightness variable now equals 5, so the analogWrite() function writes an analogWrite value of 5 to the LED.

On the next line, fadeAmount is added to brightness again, so brightness equals 10. The if statement checks if 10 is less than or equal to 0, or greater than or equal to 255. It’s not, so the code inside the if statement is skipped again. The program keeps looping over and over, adding 5 to the brightness value with each iteration of the loop() section.

But the brightness value will quickly reach 255 and the LED will be at full brightness. At that point, the Arduino reaches the if statement and finds that yes, 255 is greater than or equal to 255, so it enters the body of the if statement:

fadeAmount = -fadeAmount;

This changes the value stored in fadeAmount from 5 to -5.

In the next cycle through the loop, when the program reaches brightness = brightness + fadeAmount, 5 will be subtracted from brightness since fadeAmount now equals -5. This decreases brightness from 255 to 250. The program keeps looping, subtracting 5 from brightness with every iteration of the loop until brightness reaches 0.

When brightness equals 0, the condition of the if statement will be true, so the program enters the body of the if statement. Since fadeAmount still equals -5, the expression will look like this:

fadeAmount = -(-5);

The negative of -5 equals positive 5, so fadeAmount will equal positive 5. Now 5 will be added to the brightness variable each time through the loop. This makes the value stored in brightness cycle up and down from 0 to 255, making the LED increase and decrease in brightness in an infinite loop.

Set this up on your own and see how the LED’s brightness changes by using different values for the fadeAmount variable. You can also change the range of the LED’s brightness by changing the values in the condition of the if statement.

Feel free to leave a comment below if you have any questions!