PWM (Pulse Width Modulation) Explained: How It Works

Learn what PWM (Pulse Width Modulation) is and how it works in motor control, LED dimming, and more. Includes Arduino code examples.

ROBOTICSGADGETSELECTRONIC AND HARDWARETECHNOLOGY

3/23/20265 min read

You want to dim an LED using Arduino. But a digital output pin can only be fully ON (5V) or fully OFF (0V) — there is no middle ground, right? Wrong. Using a technique called Pulse Width Modulation (PWM), you can make a digital pin simulate an analogue output, allowing smooth control of LED brightness, motor speed, servo position, audio volume, and much more.

PWM is one of the most important and widely used techniques in electronics. This guide explains how it works from first principles, the key terminology you need to know, and how to implement it in Arduino with practical examples.

What Is Pulse Width Modulation?

Pulse Width Modulation is a technique for encoding information or controlling power by rapidly switching a digital signal between ON and OFF states, varying the proportion of time it spends in the ON state.

The key insight is this: if you switch something on and off fast enough, the device being controlled 'sees' only the average power level — not the individual pulses. An LED switched on and off 1000 times per second at 50% duty cycle appears to glow at half brightness, because your eye cannot detect individual flickers at that frequency.

Key PWM Terminology

Frequency

PWM frequency is how many complete on-off cycles occur per second, measured in Hertz (Hz). Arduino's analogWrite() function operates at 490 Hz on most pins (980 Hz on pins 5 and 6 of the Uno). Higher frequencies create smoother perceived output — important for motor control (lower frequencies can cause audible whining) and LED dimming (very low frequencies cause visible flicker).

Period

The period is the time for one complete on-off cycle. Period = 1 / Frequency. At 490 Hz: Period = 1/490 = approximately 2.04 milliseconds. The ON time and OFF time within this period sum to the total period.

Duty Cycle

Duty cycle is the percentage of the period that the signal spends in the HIGH (ON) state. This is the primary control variable in PWM.

  • 0% duty cycle: Signal is always LOW. Zero power delivered.

  • 50% duty cycle: Signal is HIGH half the time. Half average power.

  • 100% duty cycle: Signal is always HIGH. Full power delivered.

  • 25% duty cycle: Signal is HIGH one quarter of the time. Quarter average power.

Average voltage = Supply Voltage x (Duty Cycle / 100%). At 5V supply and 50% duty cycle: 5V x 0.5 = 2.5V average.

Resolution

Resolution describes how many discrete steps are available between 0% and 100% duty cycle. Arduino's analogWrite() uses 8-bit resolution: 256 steps (0 to 255). A value of 0 = 0%, 127 = ~50%, 255 = 100%. Higher resolution (10-bit, 12-bit) gives finer control — important for precision servo control and audio applications.

How PWM Works in Hardware

On most microcontrollers, PWM is generated by a dedicated hardware timer — not by the CPU toggling a pin in software. A timer counter increments on every clock tick. When the counter reaches a compare value, the output pin changes state. When the counter reaches the maximum value (255 for 8-bit), it resets and the cycle repeats.

This hardware implementation means PWM runs at the exact specified frequency without consuming CPU time. Your Arduino sketch can be doing other things while PWM outputs run independently on their dedicated timer channels.

On the Arduino Uno, PWM-capable pins are marked with a tilde (~): pins 3, 5, 6, 9, 10, and 11. The Nano has the same pins available. Not all GPIO pins can do PWM — only those connected to timer output channels.

Implementing PWM on Arduino

analogWrite()

The Arduino function analogWrite(pin, value) sets a PWM output. 'pin' must be a PWM-capable pin, and 'value' ranges from 0 (always off) to 255 (always on).

LED dimming example: Connect an LED (with appropriate resistor) to pin 9. In setup(), set pin 9 as OUTPUT. In loop(), use analogWrite(9, 127) for 50% brightness, analogWrite(9, 64) for 25%, analogWrite(9, 255) for full brightness. Fade the LED by incrementing the value in a loop with a small delay.

Servo Control

The Arduino Servo library uses PWM to control servo motor position. A standard servo expects a 50 Hz PWM signal (20ms period) with pulse width between 1ms (0 degrees) and 2ms (180 degrees). The Servo library manages this automatically.

Servo myservo; myservo.attach(9); myservo.write(90); — this positions the servo at 90 degrees using PWM on pin 9.

DC Motor Speed Control

A DC motor connected through an L298N or L293D motor driver can have its speed controlled by a PWM signal. Higher duty cycle = higher average voltage = faster motor. Lower duty cycle = lower average voltage = slower motor.

This is how robot projects, electric scooters, and variable-speed fans control speed without wasteful resistive speed reduction.

PWM for Audio Generation

By rapidly varying the PWM duty cycle according to an audio waveform, a microcontroller can synthesise audio signals. The tone() function on Arduino does a simplified version of this for single-frequency tones. More sophisticated audio synthesis uses high-frequency PWM (typically 44.1–62.5 kHz) with a low-pass RC filter to smooth the output into an analogue audio signal.

PWM in Power Electronics

PWM is the fundamental operating principle of switch-mode power supplies (SMPS), buck and boost converters, and inverters. A buck converter uses a transistor switching at high frequency (typically 100 kHz–2 MHz) to step voltage down efficiently. The switching ratio (duty cycle) determines the output voltage. This is far more efficient than a linear regulator that simply dissipates excess voltage as heat.

Solar MPPT charge controllers, battery chargers, motor drives, and DC-DC converters all rely on PWM switching at their core.

Changing PWM Frequency on Arduino

The default analogWrite() frequency (490 Hz or 980 Hz) is suitable for LED dimming but may not be ideal for motor control (can cause audible buzzing) or other applications. Arduino's Timer registers can be modified directly to change the PWM frequency, though this requires manipulating hardware registers and can affect millis() and delay() if Timer 0 is modified.

For most beginner applications, the default frequency is fine. For motor control, if you hear buzzing from the motor, try increasing the PWM frequency — many motor driver libraries include options to set higher frequencies.

Common PWM Applications Summary

  • LED brightness control: analogWrite() for smooth dimming effects and RGB LED colour mixing.

  • Servo motor position control: Standard RC servos use 50 Hz PWM with pulse width varying between 1ms and 2ms.

  • DC motor speed control: Via motor driver ICs (L298N, DRV8833), PWM controls average voltage to motor.

  • Buzzer and audio: tone() generates fixed frequency PWM for simple musical notes.

  • Power supply regulation: Buck/boost converters use PWM switching to convert voltages efficiently.

  • Fan speed control: Computer fans (4-pin PWM fans) accept a PWM signal directly to control speed.

PWM vs True Analogue Output

PWM is not the same as a true analogue output — it is a digital signal rapidly switching between 0V and 5V. For most control applications (LED brightness, motor speed), the target device responds to average power and this distinction does not matter.

For applications requiring true analogue voltage output (audio line level, precise reference voltages), a DAC (Digital to Analogue Converter) is needed. Some microcontrollers like the ESP32 and Arduino Due have built-in DAC outputs. The Arduino Uno does not — it can only simulate analogue via PWM.

Conclusion

Pulse Width Modulation is a powerful technique that lets digital microcontrollers control power and create smooth analogue-like effects. By varying the duty cycle — the on-time fraction of a repeating signal — PWM controls LED brightness, motor speed, servo position, and enables efficient power conversion.

On Arduino, analogWrite() makes PWM simple to implement. Understanding what is happening at the signal level helps you troubleshoot, optimise, and extend your PWM-based projects.

For project guides that use PWM in practice, visit the Circuit Diary Projects page. Explore more electronics theory and tutorials on the Circuit Diary Blog.