Table of Contents
KEY TAKEAWAYS
- PWM generates a square wave with variable duty cycle to control average power delivered to a load
- Applications include motor speed control, LED dimming, servo positioning, and audio generation
- Duty cycle (0-100%) determines the output level; frequency determines the switching rate
- Hardware PWM peripherals in microcontrollers generate precise waveforms without CPU overhead
What is PWM?
Pulse Width Modulation (PWM) is a technique that creates a square wave signal where the proportion of ON time (high) versus OFF time (low) is controlled precisely. This ratio is called the duty cycle. 100% Duty Cycle (Always ON):
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
75% Duty Cycle:
‾‾‾‾‾‾‾‾‾‾‾‾|____|‾‾‾‾‾‾‾‾‾‾‾‾|____|
50% Duty Cycle:
‾‾‾‾‾‾‾‾|________|‾‾‾‾‾‾‾‾|________|
25% Duty Cycle:
‾‾‾‾|____________|‾‾‾‾|____________|
0% Duty Cycle (Always OFF):
_________________________________Duty Cycle = (ON time / Total period) x 100%A GPIO pin can only be HIGH (3.3V/5V) or LOW (0V). It cannot output 1.5V directly. But by rapidly switching between HIGH and LOW, the average voltage equals the duty cycle percentage of the supply voltage.Average Voltage = Duty Cycle x V_supply
Examples (3.3V supply):
25% duty cycle = 0.825V average
50% duty cycle = 1.65V average
75% duty cycle = 2.475V averagePWM Parameters
Frequency
The PWM frequency determines how many ON-OFF cycles occur per second. It is measured in Hertz (Hz).| Application | Typical Frequency |
|---|---|
| LED dimming | 500 Hz – 5 kHz (above flicker perception) |
| Servo motors | 50 Hz (20ms period) |
| DC motor speed | 10 kHz – 50 kHz (above audible range) |
| Audio generation | Varies with tone |
| Switching regulators | 100 kHz – 2 MHz |
Resolution
PWM resolution determines how finely you can control the duty cycle. With 8-bit resolution, you have 256 steps (0-255). With 16-bit, you have 65,536 steps.Common PWM Applications
1. LED Brightness Control
// Arduino example
#define LED_PIN 9
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// Fade in
for (int brightness = 0; brightness <= 255; brightness++) {
analogWrite(LED_PIN, brightness);
delay(5);
}
// Fade out
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(LED_PIN, brightness);
delay(5);
}
}2. DC Motor Speed Control
PWM controls motor speed by varying the average voltage. A motor driver (like L298N or L293D) is needed between the MCU and the motor.// Motor speed control
#define MOTOR_PWM_PIN 5
#define MOTOR_DIR_PIN 6
void set_motor_speed(uint8_t speed, uint8_t direction) {
digitalWrite(MOTOR_DIR_PIN, direction);
analogWrite(MOTOR_PWM_PIN, speed); // 0 = stop, 255 = full speed
}
// Run motor at half speed forward
set_motor_speed(128, HIGH);
// Run motor at full speed reverse
set_motor_speed(255, LOW);3. Servo Motor Control
Servo motors expect a specific PWM signal:- Period: 20ms (50 Hz)
- Pulse width: 1ms (0 degrees) to 2ms (180 degrees)
Servo position is determined by pulse width:
0 degrees: |‾|_____________________| (1ms pulse in 20ms period)
90 degrees: |‾‾‾|___________________| (1.5ms pulse)
180 degrees: |‾‾‾‾‾|_________________| (2ms pulse)4. Buzzer / Tone Generation
By varying the PWM frequency, you can generate different musical tones:// Generate a 440 Hz tone (note A4)
tone(BUZZER_PIN, 440);
delay(500);
noTone(BUZZER_PIN);
// Simple melody
int notes[] = {262, 294, 330, 349, 392, 440, 494, 523};
for (int i = 0; i < 8; i++) {
tone(BUZZER_PIN, notes[i]);
delay(300);
}
noTone(BUZZER_PIN);5. PWM as a Poor Man’s DAC
With a low-pass filter (RC circuit), you can convert PWM to a smooth analog voltage: MCU PWM Pin ──[1K Resistor]──┬── Analog Output
|
[10uF]
|
GNDThe resistor and capacitor smooth out the rapid switching into a steady DC voltage proportional to the duty cycle. This is useful on MCUs without a built-in DAC.Hardware PWM vs Software PWM
| Feature | Hardware PWM | Software PWM |
|---|---|---|
| Implementation | Built-in timer peripheral | GPIO toggling in code/ISR |
| CPU usage | Zero (runs independently) | High (CPU must toggle pin) |
| Precision | Very precise, jitter-free | Can have jitter from interrupts |
| Pins | Only specific pins | Any GPIO pin |
| Channels | Limited by hardware timers | Unlimited (but CPU cost) |
PWM on Different Platforms
Arduino:analogWrite(pin, value); // value: 0-255 (8-bit)ESP32 (LEDC peripheral):
ledcAttach(pin, frequency, resolution); ledcWrite(pin, dutyCycle);STM32 (HAL):
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, pulse_value);
Summary
PWM is one of the most versatile tools in embedded systems:- Control LED brightness by varying the duty cycle
- Control DC motor speed through a motor driver
- Position servo motors with specific pulse widths
- Generate audio tones by varying frequency
- Approximate analog output when no DAC is available

Vivek Bhageria — Lead Firmware R&D Engineer, 12+ years. Ex-Bosch (automotive powertrain), MusicTribe (real-time audio), medical devices. M.Tech BITS Pilani. I write at NerdyElectronics — practical, register-level embedded systems for engineers who want to understand what’s actually happening under the hood.







