PWM

Learn to adjust LED brightness or an output with analogWrite and PWM.

LESSON COMPASS

What will you use this page for?

Core idea

PWM (Pulse Width Modulation) is a way to set the average power of a digital pin by switching it on and off very quickly, so we can dim an LED or change the speed of a motor.

Evidence to produce

Complete the page task with your own input, test conditions and reasoning.

Control trap

Choosing a pin without PWM If you call analogWrite() on a pin like 7 that has no ~ mark, the brightness control will not work. Always pick 3, 5, 6, 9, 10 or 11. Mixing up the map ranges analogRead gives 0–1023 and analogWrite wants 0–255. If you write it backwards, like map(reading, 0, 255, 0, 1023) , the values come…

Next connection

Button Debounce Logic: We will learn why a single button press is sometimes detected several times, and how to clean it up in software.

Module sources: Python Tutorial · Arduino Learn

LevelBeginner
Age10–16
Duration30–45 min
PrerequisiteThe Serial Monitor
ContentStandard lesson · 1,507 words
Last updated

One-sentence summary

PWM (Pulse Width Modulation) is a way to set the average power of a digital pin by switching it on and off very quickly, so we can dim an LED or change the speed of a motor.

Why it matters

An Arduino pin can normally do only two things: give 5 volts (HIGH) or give 0 volts (LOW). So a lamp is either fully on or fully off. But what if we want an LED to glow "half bright," or a fan to spin at "medium speed"?

This is exactly where PWM helps. We switch the pin on and off so fast that our eyes cannot notice the individual flickers; instead, we see an average brightness. The same idea is used to set the speed of robot wheels, the volume of a buzzer, and even the colour of an RGB LED.

This lesson takes the digital outputs you met earlier one step further: instead of only "on/off," you will now be able to answer "how much."

How does PWM work?

The fast on-and-off idea

PWM stands for Pulse Width Modulation. Don't worry about the long name; the idea is simple.

Imagine flipping a light switch hundreds of times per second. If the switch is on for half the time and off for the other half, the lamp looks "half bright" to you. If it stays on most of the time it looks brighter, and if it stays off most of the time it looks dimmer.

This "percentage of on-time" is called the duty cycle. 0% is fully off, 100% is fully on, and 50% means half power.

analogWrite and the 0–255 scale

To create PWM in Arduino we use the analogWrite() command. It expects a number between 0 and 255:

Why 255? Because Arduino stores this value as an 8-bit number, and with 8 bits we can count at most 256 different values (from 0 to 255). Even though the name is "analog," the pin still only turns on and off; it just does it very quickly.

Which pins give PWM?

Not every pin can do PWM. On the Arduino Uno, the pins that support PWM have a tilde sign (~) next to them. On the Uno these are pins 3, 5, 6, 9, 10 and 11.

If you look at the board and see a mark like ~3 next to a pin number, that pin can produce PWM. If you call analogWrite() on a pin without the mark, either nothing useful happens or it just behaves like fully on/fully off.

Small rule: for analogWrite, remember to set pinMode to OUTPUT, and choose only pins marked with ~.

Two everyday examples

Your phone screen brightness

When you change the brightness of your phone, the screen's backlight is actually dimmed using PWM. The light flickers so fast that you only see a brighter or dimmer screen. Dim in a dark room, full brightness in the sun; it is all just a change in duty cycle.

A computer or air-conditioner fan

The cooling fans inside your computer are also usually controlled with PWM. When the processor heats up the duty cycle rises and the fan spins faster; when it cools down the cycle drops and the fan slows. With the same idea we can gently speed a robot's wheel motor up and down.

Simple example: glow an LED

Let's first try a fixed half-brightness. Connect an LED to pin 9 (which supports PWM) through a resistor.

Circuit:

int ledPin = 9; // PWM pin (~9)

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

void loop() {
  analogWrite(ledPin, 64);  // about 25% brightness
  delay(1000);
  analogWrite(ledPin, 255); // full brightness
  delay(1000);
}

This sketch lights the LED dim for one second, then full for one second. Try different numbers instead of 64 and watch how the brightness changes.

Mini practice: LED brightness with a potentiometer

Now let's move to the real project. By turning a potentiometer we will set the LED brightness by hand. A potentiometer is an adjustable resistor that changes as you turn its knob.

Circuit:

Here is the catch: analogRead() gives us a number from 0 to 1023, but analogWrite() wants 0 to 255. To match these two scales we use the map() command.

int potPin = A0;  // potentiometer input
int ledPin = 9;   // PWM output (~9)

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int reading = analogRead(potPin);         // 0 - 1023
  int brightness = map(reading, 0, 1023, 0, 255);
  analogWrite(ledPin, brightness);          // 0 - 255
  Serial.println(brightness);               // watch the value
  delay(50);
}

As you turn the potentiometer the LED dims and brightens. If you open the Serial Monitor at the same time, you will see the brightness value changing between 0 and 255. The map() command converts the 0–1023 range proportionally into the 0–255 range.

Common mistakes

Choosing a pin without PWM

If you call analogWrite() on a pin like 7 that has no ~ mark, the brightness control will not work. Always pick 3, 5, 6, 9, 10 or 11.

Mixing up the map ranges

analogRead gives 0–1023 and analogWrite wants 0–255. If you write it backwards, like map(reading, 0, 255, 0, 1023), the values come out wrong. Think of the order as "from source → to target": map(value, 0, 1023, 0, 255).

Passing a value above 255

If you give analogWrite a number like 300, you get unexpected results. Keep the value in the 0–255 range.

Forgetting pinMode

If you forget to set the LED pin to OUTPUT, the output can be weak and unstable. Don't skip the pinMode(ledPin, OUTPUT); line inside setup().

Safety note

Lesson summary

Check questions

  1. What does PWM stand for and what does it basically do?
  2. What range of numbers does the analogWrite() command accept?
  3. How do you recognise the PWM pins on an Arduino Uno, and which ones are they?
  4. analogRead gives 0–1023, so how do we make it suitable for analogWrite?
  5. Why should we not drive a motor directly from an Arduino pin?

Answers

  1. PWM means Pulse Width Modulation. It sets the average power of a pin, its duty cycle, by switching the pin on and off very quickly.
  2. analogWrite() accepts a value between 0 and 255: 0 is fully off, 255 is fully on, and 127 is about half power.
  3. PWM pins have a tilde (~) sign next to them. On the Uno they are pins 3, 5, 6, 9, 10 and 11.
  4. We convert the scale with the map() command: map(reading, 0, 1023, 0, 255) pulls the value proportionally into the 0–255 range.
  5. Because a motor draws far more current than a pin can safely give; this can damage the board. A motor needs a separate power source and a motor driver.

Source and verification note

For “PWM”, verification focuses on whether the relationship between How does PWM work? and analogWrite and the 0–255 scale remains consistent across examples. Pin, voltage and current limits can differ between Arduino-compatible boards. Compiling code does not guarantee a safe circuit; loads such as motors and servos require a suitable driver and external power where appropriate.

Next lesson

Button Debounce Logic: We will learn why a single button press is sometimes detected several times, and how to clean it up in software.

Start QuizBack to Arduino
QUESTION POOL

Reinforce this lesson with 10 questions

This lesson has a pool of 20 questions. Each attempt selects 10 and reshuffles the choices.