Skip to content

Arduino - Pulse Width Modulation

Arduino: Understanding Pulse Width Modulation (PWM)

Section titled “Arduino: Understanding Pulse Width Modulation (PWM)”

Pulse Width Modulation (PWM) is a powerful technique for controlling analog devices with a digital signal. Instead of outputting a continuous analog voltage, PWM rapidly switches a digital pin between HIGH and LOW. The percentage of time the signal is HIGH is known as the duty cycle, which creates an average voltage, allowing you to achieve effects like dimming an LED or controlling the speed of a DC motor.

HIGH |----------| |----------|
| | | |
LOW +----------+----------+----------+
<-- Ton ---><--Toff--><-- Ton --->
<------- Period ------>
  • On-Time (Ton): The duration the signal is HIGH.
  • Off-Time (Toff): The duration the signal is LOW.
  • Period: The total time for one cycle (Period = Ton + Toff). The inverse of the period is the PWM frequency.
  • Duty Cycle: The percentage of the period that the signal is HIGH. Duty Cycle = (Ton / Period) * 100%.

A 0% duty cycle means the signal is always LOW (0V average). A 100% duty cycle means it’s always HIGH (5V average). A 50% duty cycle means it’s HIGH for half the period, resulting in an average voltage of 2.5V.

Arduino provides the analogWrite(pin, value) function to easily generate a PWM signal. You don’t need to call pinMode() before using it on a PWM pin.

analogWrite(pin, value);
  • pin: The PWM-capable pin you want to use. On an Arduino UNO, these are marked with a tilde ~ (pins 3, 5, 6, 9, 10, 11). Always check your board’s documentation for its PWM pins.
  • value: The duty cycle, specified as an integer from 0 (0% duty cycle) to 255 (100% duty cycle).

The default PWM frequency on most Arduino boards is approximately 490 Hz, but some pins (e.g., 5 and 6 on the UNO) run at 980 Hz. More advanced boards like the ESP32 offer configurable PWM frequencies.

Example Project: Fading an LED with a Potentiometer

Section titled “Example Project: Fading an LED with a Potentiometer”

This classic example demonstrates how to read an analog value from a potentiometer and use it to control the brightness of an LED via PWM.

  • 1 × Arduino UNO
  • 1 × Potentiometer (any value, 10kΩ is common)
  • 1 × LED
  • 1 × 220Ω Resistor
// Potentiometer Wiring
Potentiometer Pin 1 --- Arduino GND
Potentiometer Pin 2 (Wiper) --- Arduino Analog Pin A0
Potentiometer Pin 3 --- Arduino 5V
// LED Wiring
Arduino PWM Pin ~9 --- [220Ω Resistor] --- [LED Anode (+)]
Arduino GND --- [LED Cathode (-)]

The analogRead() function returns a value from 0-1023, but analogWrite() needs a value from 0-255. We can use the handy map() function to scale the input range to the output range.

/**
* @file pwm_potentiometer_control.ino
* @brief Controls LED brightness with a potentiometer using PWM.
* @author Modernized Tutorial
*/
constexpr int LED_PIN = 9; // Must be a PWM pin (~)
constexpr int POT_PIN = A0; // Potentiometer input pin
void setup() {
// No pinMode needed for LED_PIN when using analogWrite.
// No pinMode needed for analog input pins.
Serial.begin(9600);
}
void loop() {
// 1. Read the value from the potentiometer (0 to 1023)
int potValue = analogRead(POT_PIN);
// 2. Map the 10-bit analog input range (0-1023) to the
// 8-bit PWM output range (0-255).
int pwmValue = map(potValue, 0, 1023, 0, 255);
// 3. Write the mapped value to the LED pin.
analogWrite(LED_PIN, pwmValue);
// Optional: Print values to Serial Monitor for debugging.
Serial.print("Potentiometer: ");
Serial.print(potValue);
Serial.print("\t PWM Value: ");
Serial.println(pwmValue);
delay(10); // Small delay for stability
}

PWM is incredibly versatile:

  • DC Motor Speed Control: By using a motor driver IC (like an L298N or TB6612), you can use PWM to control the effective voltage sent to a motor, thus controlling its speed.
  • Servo Motor Control: The Arduino Servo library uses PWM signals to tell a servo motor which angle to move to.
  • Generating Tones: The tone() function uses PWM to create sounds of different frequencies with a buzzer or speaker.