Pulse Width Modulation (PWM) is a technique that simulates a variable analog voltage by rapidly switching a digital output between HIGH and LOW, where the ratio of ON time to the total cycle time dictates the average power delivered to the load. Unlike using a variable resistor to drop voltage—which burns the excess energy as heat—PWM changes the average power delivered to a circuit by time-slicing the full supply voltage, keeping efficiency near 100%.
Think of a light switch. If you want a bulb to glow at half brightness, you could wire a massive resistor in series to drop the voltage, but that resistor will get dangerously hot. Instead, if you flip the switch on and off a thousand times a second, the bulb's thermal mass (and your eye's persistence of vision) averages the rapid flashes into a steady half-brightness glow. The switch itself dissipates almost zero heat because it is either fully ON (low resistance) or fully OFF (infinite resistance).
The Core PWM Definition: What It Actually Does to Your Circuit
In embedded systems, microcontrollers cannot output true analog voltages natively (unless they have a dedicated Digital-to-Analog Converter, or DAC). When you call analogWrite() on an Arduino or use the LEDC peripheral on an ESP32, you are not outputting a smooth DC voltage. You are outputting a 3.3V or 5V square wave.
Because of this, PWM only works as an "analog" simulator for loads that naturally average the signal over time. DC motors average it via mechanical inertia and winding inductance. LEDs average it via human persistence of vision. Heating elements average it via thermal mass.
Duty Cycle vs. Frequency: The Numeric Breakdown
To use PWM effectively, you must separate the two independent variables: Duty Cycle and Frequency.
- Duty Cycle: The percentage of one complete cycle that the signal spends in the HIGH (ON) state. This controls the average power.
- Frequency: How many complete cycles occur per second, measured in Hertz (Hz). This controls how smoothly the load responds and dictates switching losses in your driver circuit.
Worked Numeric Example: Driving a 12V DC Motor
Let's say you are using an ESP32-WROOM-32 to drive a 12V, 2A DC motor through an IRLZ44N logic-level MOSFET. You want the motor to run at roughly 60% speed.
- Set the Frequency: We choose 5 kHz (5,000 cycles per second). This is above the range of human hearing, preventing the motor windings from emitting an audible, annoying whine. At 5 kHz, one complete cycle (the Period) takes exactly 200 microseconds (µs).
- Set the Duty Cycle: We command a 60% duty cycle.
- Calculate the Timing: 60% of the 200 µs period is 120 µs. The ESP32 drives the MOSFET gate HIGH for 120 µs, then LOW for the remaining 80 µs.
- Calculate the Average Voltage: The motor's inductance smooths the current. The effective average voltage applied to the motor terminals is 12V × 0.60 = 7.2V.
According to foundational power electronics theory outlined by All About Circuits, the RMS (Root Mean Square) voltage of this square wave is actually 9.29V, which is what dictates the heating effect in the motor windings, while the 7.2V average dictates the mechanical torque and speed.
Where You Meet PWM in Practice (And When It Fails)
You will encounter PWM in almost every embedded project, but choosing the wrong frequency will cause immediate, visible (or audible) failures.
1. LED Dimming and Camera Banding
If you dim an LED strip using the default Arduino Uno PWM frequency (~490 Hz), it will look perfectly smooth to the naked eye. However, if you record that LED with a smartphone camera at 60fps, you will see severe rolling banding or flicker. The fix: Push the PWM frequency above 1 kHz (ideally 3 kHz to 5 kHz) to outpace the camera's shutter sampling rate.
2. DC Motor Audible Whine
When driving DC motors or piezo buzzers, any PWM frequency between 1 kHz and 15 kHz will cause the physical components to vibrate at that exact acoustic frequency, creating a loud, high-pitched whine. The fix: Use a frequency of at least 16 kHz to push the switching noise above the upper limit of human hearing. Beware: pushing it past 50 kHz increases MOSFET switching losses, requiring heatsinks on your motor driver.
3. RC Servo Positioning
Standard hobby servos (like the SG90 or MG996R) do not use PWM to control power; they use it to decode a positional command. They strictly require a 50 Hz frequency (a 20 ms period). The duty cycle (specifically, a pulse width between 1 ms and 2 ms) tells the servo's internal potentiometer where to move the output shaft. If you feed a servo a 1 kHz signal, it will jitter violently or ignore the command entirely.
Decision Tree: Picking the Right PWM Hardware and Frequency
Do not just rely on the default analogWrite() function. Modern microcontrollers have dedicated hardware peripherals for specific PWM tasks. Use this decision matrix to select the correct hardware and part number for your 2026 workbench.
| If Your Load Is... | Required Frequency | Best Microcontroller Peripheral | Default Hardware / Driver Pick |
|---|---|---|---|
| Standard 5V RC Servos | 50 Hz (Strict) | ESP32 LEDC / Arduino Servo.h | PCA9685 (I2C 16-channel board) |
| High-Power LED Strips | 1 kHz - 5 kHz | ESP32 LEDC (High-speed channel) | TLC5940 (16-ch constant current sink) |
| DC Brushed Motors | 16 kHz - 20 kHz | ESP32 MCPWM (Motor Control) | DRV8871 or BTS7960 H-Bridge |
| BLDC / Stepper Motors | 20 kHz+ (with dead-time) | ESP32 MCPWM with Dead-zone | TMC2209 (Stepper) / SimpleFOC shield |
If you are building a complex robotics project with more than 4 motors or servos, offload the timing from your microcontroller entirely. The Adafruit PCA9685 breakout board handles up to 16 channels of 12-bit PWM over I2C, freeing your ESP32 or Raspberry Pi to handle kinematics and Wi-Fi without interrupt jitter ruining your pulse widths.
Frequently Asked Questions
Why does my ESP32 PWM stutter or glitch at high duty cycles?
The ESP32's LEDC peripheral uses a timer to calculate duty cycles. If you set the frequency very high (e.g., 40 kHz) and the resolution very high (e.g., 14-bit), the base clock cannot divide evenly, causing jitter. For frequencies above 10 kHz, drop the resolution to 8-bit or 10-bit. Alternatively, switch to the MCPWM peripheral, which operates independently of the LEDC timer matrix.
Can I use PWM to charge a lithium battery?
No. Feeding raw PWM into a lithium cell will cause severe voltage spikes that can trip the BMS (Battery Management System) or degrade the cell chemistry due to high ripple current. If you are building a solar charge controller, the PWM signal must drive a buck converter topology (an inductor and a Schottky diode) to smooth the square wave into a true, regulated DC charging current.
What happens if I measure a PWM pin with a multimeter on AC mode?
A multimeter in AC mode blocks the DC component and measures the AC ripple of the square wave. For a 5V pin at 50% duty cycle, the DC average is 2.5V, but the AC RMS reading will show roughly 2.5V as well, representing the magnitude of the voltage swinging above and below the average. Always use an oscilloscope to verify PWM signals; multimeters only tell half the story.






