Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.
  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.
Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.

Arduino PWM Tutorial: Analog Output Explained

When I first started working with microcontrollers in PCB design projects, one concept kept coming up: PWM. After years of implementing PWM in everything from LED dimming circuits to motor control systems, I’ve learned that understanding Pulse Width Modulation is fundamental to getting the most out of your Arduino projects.

This Arduino PWM tutorial will walk you through everything you need to know about generating analog-like outputs using digital pins, complete with practical examples and real-world applications.

What is PWM and Why Does It Matter?

PWM stands for Pulse Width Modulation. It’s a technique where we rapidly switch a digital signal on and off to simulate an analog voltage output. Think of it like rapidly flicking a light switch – if you do it fast enough, the light appears dimmed rather than blinking.

In practical terms, instead of outputting a constant 2.5V (which Arduino can’t do directly), PWM outputs a 5V signal that’s on 50% of the time and off 50% of the time. The average voltage delivered to the component is 2.5V, achieving our analog effect through digital means.

The key advantage? Microcontrollers like Arduino can only output HIGH (5V) or LOW (0V) digitally. PWM lets us effectively create any voltage between 0V and 5V without additional hardware like DACs.

Understanding PWM Fundamentals

The Duty Cycle Concept

The duty cycle determines what percentage of time the signal stays HIGH during each cycle. In this Arduino PWM tutorial, you’ll see duty cycle expressed as a value from 0 to 255 in Arduino code.

Here’s the relationship:

Duty Cycle (%)Arduino ValueEffective VoltageCommon Use
0%00VCompletely OFF
25%641.25VVery dim LED
50%1272.5VHalf brightness
75%1913.75VBright LED
100%2555VFull brightness

PWM Frequency Matters

Arduino boards typically generate PWM at approximately 490 Hz (on most pins) and 980 Hz (on pins 5 and 6 on Uno). From a PCB engineering standpoint, this frequency affects several things:

490 Hz is fast enough for:

  • LED brightness control (human eye can’t detect flicker above ~50 Hz)
  • Basic motor speed control
  • Heating element control

490 Hz might be too slow for:

  • Audio applications (creates audible whine)
  • High-performance motor control
  • Switch-mode power supplies

Arduino PWM Pin Configuration

Not all Arduino pins support PWM. This is a hardware limitation based on the timers built into the ATmega microcontroller.

Arduino Uno PWM Pins

On the Arduino Uno, you’ll find PWM capability on pins 3, 5, 6, 9, 10, and 11. These pins are marked with a tilde (~) symbol on the board.

Pin NumberTimer UsedDefault FrequencyNotes
3Timer 2490 HzShares timer with pin 11
5Timer 0980 HzAlso used for millis()
6Timer 0980 HzAlso used for millis()
9Timer 1490 Hz16-bit timer
10Timer 1490 Hz16-bit timer
11Timer 2490 HzShares timer with pin 3

Other Popular Arduino Boards

Arduino Mega 2560: Pins 2-13 and 44-46 support PWM (15 total pins) Arduino Nano: Same as Uno – pins 3, 5, 6, 9, 10, 11 Arduino Due: All digital pins support PWM with 12-bit resolution

Basic Arduino PWM Tutorial: Your First Program

Let’s start with the classic LED fading example. This demonstrates the fundamental analogWrite() function:

int ledPin = 9;  // PWM pin connected to LED

void setup() {

  pinMode(ledPin, OUTPUT);

}

void loop() {

  // Fade in

  for(int brightness = 0; brightness <= 255; brightness++) {

    analogWrite(ledPin, brightness);

    delay(10);

  }

  // Fade out

  for(int brightness = 255; brightness >= 0; brightness–) {

    analogWrite(ledPin, brightness);

    delay(10);

  }

}

In my workshop, I always connect a 220Ω resistor in series with the LED to protect both the LED and the Arduino pin (max 40mA per pin).

Practical PWM Applications

DC Motor Speed Control

One of the most common uses of PWM in my projects is controlling DC motor speed. Here’s a practical implementation:

int motorPin = 10;

int potPin = A0;

void setup() {

  pinMode(motorPin, OUTPUT);

}

void loop() {

  int potValue = analogRead(potPin);  // Read 0-1023

  int motorSpeed = map(potValue, 0, 1023, 0, 255);  // Convert to 0-255

  analogWrite(motorPin, motorSpeed);

  delay(10);

}

Important note from my experience: Always use a motor driver IC (like L298N or L293D) between Arduino and motors. Direct connection can damage your Arduino due to back-EMF.

RGB LED Color Mixing

PWM shines (literally) when controlling RGB LEDs:

int redPin = 9;

int greenPin = 10;

int bluePin = 11;

void setup() {

  pinMode(redPin, OUTPUT);

  pinMode(greenPin, OUTPUT);

  pinMode(bluePin, OUTPUT);

}

void setColor(int red, int green, int blue) {

  analogWrite(redPin, red);

  analogWrite(greenPin, green);

  analogWrite(bluePin, blue);

}

void loop() {

  setColor(255, 0, 0);     // Red

  delay(1000);

  setColor(0, 255, 0);     // Green

  delay(1000);

  setColor(0, 0, 255);     // Blue

  delay(1000);

  setColor(255, 255, 0);   // Yellow

  delay(1000);

}

Servo Motor Control

While servo control technically uses PWM, Arduino provides a dedicated Servo library. However, understanding PWM helps you grasp why servos need specific pulse widths:

Pulse WidthServo PositionDuty Cycle (20ms period)
1.0 ms~5%
1.5 ms90°~7.5%
2.0 ms180°~10%

Advanced PWM Techniques

Modifying PWM Frequency

Sometimes the default 490 Hz isn’t suitable. I’ve had projects where LED drivers created audible noise, or motors needed higher frequencies. You can modify timer prescalers to change PWM frequency:

void setup() {

  // Set PWM frequency for pins 9 and 10 to 31250 Hz

  TCCR1B = TCCR1B & 0b11111000 | 0x01;

}

Warning: Changing timer registers affects other functions. Timer 0 modifications will break millis() and delay().

TimerAffected PinsDefault FrequencyPrescaler Options
Timer 05, 6980 HzDon’t modify (breaks timing)
Timer 19, 10490 Hz31250 Hz to 122 Hz
Timer 23, 11490 Hz31250 Hz to 122 Hz

Software PWM for Non-PWM Pins

In some designs, I’ve needed PWM on pins without hardware support. Software PWM is possible but CPU-intensive:

unsigned long previousMicros = 0;

int period = 2000;  // 2000 microseconds = 500 Hz

int dutyCycle = 128;  // 0-255

void loop() {

  unsigned long currentMicros = micros();

  unsigned long elapsed = currentMicros – previousMicros;

  if(elapsed < (period * dutyCycle / 255)) {

    digitalWrite(LED_PIN, HIGH);

  } else {

    digitalWrite(LED_PIN, LOW);

  }

  if(elapsed >= period) {

    previousMicros = currentMicros;

  }

}

Common Pitfalls and Solutions

Problem 1: LED Not Dimming Smoothly

Issue: LED appears to flicker or doesn’t dim linearly. Solution: Human eye perception is logarithmic. Use gamma correction:

const byte gamma8[] = {

    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,

    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,

    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,

    2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5,

    5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10,

   10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,

   17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,

   25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,

   37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,

   51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,

   69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,

   90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,

  115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,

  144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,

  177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,

  215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };

analogWrite(ledPin, gamma8[brightness]);

Problem 2: Motor Runs at Full Speed with Low PWM

Issue: DC motor doesn’t respond to low PWM values. Solution: Motors have a minimum starting voltage. Implement a threshold:

int speed = map(potValue, 0, 1023, 0, 255);

if(speed < 50) speed = 0;  // Below minimum, turn off completely

analogWrite(motorPin, speed);

Problem 3: Servo Jitter with analogWrite()

Issue: Using analogWrite() for servo control causes erratic movement. Solution: Always use the Servo library for servos – analogWrite() PWM frequency is wrong for servo control.

Measuring and Debugging PWM Signals

As a PCB engineer, I rely on these tools for PWM debugging:

Oscilloscope: Essential for viewing actual waveforms, measuring frequency and duty cycle Multimeter (in frequency mode): Quick frequency checks Logic Analyzer: Excellent for multi-channel PWM timing analysis LED + Resistor: Simple visual confirmation that PWM is working

Hardware Considerations for PWM Projects

Current Limitations

Each Arduino pin can source/sink approximately 40mA maximum. For most PWM applications:

  • LEDs: Use current-limiting resistors (220Ω for 5V, standard LEDs)
  • Motors: Always use driver ICs (L298N, L293D, TB6612FNG)
  • High-current loads: Use MOSFETs or relays triggered by PWM

PCB Layout Tips

When designing PCBs with PWM outputs:

  1. Keep PWM traces short to minimize EMI
  2. Use ground planes for noise reduction
  3. Add decoupling capacitors (0.1µF) near driver ICs
  4. Separate analog ground from digital ground when using precision analog sensors
  5. Consider RC filters on PWM outputs if you need true analog voltage

Useful Resources and Tools

Official Documentation:

  • Arduino Language Reference: https://www.arduino.cc/reference/en/
  • ATmega328P Datasheet: Available from Microchip’s website

Software Tools:

  • Arduino IDE: Free download from arduino.cc
  • Fritzing: Circuit diagram and PCB design tool
  • PlatformIO: Advanced IDE for embedded development

Libraries:

  • Servo Library: Built into Arduino IDE
  • PWM Frequency Library: Search “PWM Frequency library” on GitHub
  • FastLED: Advanced LED control with gamma correction

Hardware Tools:

  • Digital Multimeter with frequency measurement
  • USB Logic Analyzer (Saleae or compatible)
  • Oscilloscope (even entry-level models work)

Learning Resources:

  • Nick Gammon’s Timer Tutorials: Comprehensive timer/PWM guides
  • Electronics Stack Exchange: Community troubleshooting
  • AVR Freaks Forum: Deep technical discussions

Real-World Project Examples

Home Automation Dimmer

I recently designed a room lighting controller using PWM:

#define PWM_PIN 9

#define BUTTON_PIN 2

int brightness = 128;

bool lastButton = HIGH;

void setup() {

  pinMode(PWM_PIN, OUTPUT);

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  analogWrite(PWM_PIN, brightness);

}

void loop() {

  bool buttonState = digitalRead(BUTTON_PIN);

  if(buttonState == LOW && lastButton == HIGH) {

    brightness += 51;  // Increment by ~20%

    if(brightness > 255) brightness = 0;

    analogWrite(PWM_PIN, brightness);

    delay(200);  // Debounce

  }

  lastButton = buttonState;

}

Temperature-Controlled Fan

Automatic fan speed based on temperature sensor:

#include <DHT.h>

#define DHT_PIN 4

#define FAN_PIN 10

#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

void setup() {

  pinMode(FAN_PIN, OUTPUT);

  dht.begin();

  Serial.begin(9600);

}

void loop() {

  float temp = dht.readTemperature();

  int fanSpeed;

  if(temp < 20) {

    fanSpeed = 0;  // Fan off

  } else if(temp > 30) {

    fanSpeed = 255;  // Full speed

  } else {

    fanSpeed = map(temp, 20, 30, 50, 255);  // Gradual increase

  }

  analogWrite(FAN_PIN, fanSpeed);

  Serial.print(“Temp: “);

  Serial.print(temp);

  Serial.print(“°C, Fan Speed: “);

  Serial.println(fanSpeed);

  delay(2000);

}

Frequently Asked Questions

Q: Can I use PWM to generate audio tones on Arduino?

A: Yes, but with limitations. The tone() function is better suited for audio as it can generate precise frequencies. PWM at 490 Hz creates audible humming in most applications. For music projects, use tone() or dedicated audio libraries with better frequency control and waveform shaping.

Q: Why does my motor make noise when using PWM control?

A: Motors produce audible noise when PWM frequency is below roughly 20 kHz. Arduino’s default 490 Hz is well within human hearing range (20 Hz – 20 kHz). You can reduce noise by increasing PWM frequency by modifying timer prescalers, though this requires direct register manipulation. Alternatively, use motor driver ICs with built-in high-frequency PWM.

Q: Can I damage my Arduino with PWM?

A: PWM itself won’t damage Arduino, but connecting high-current loads directly to PWM pins will. Each pin handles maximum 40mA. Always use appropriate drivers (MOSFETs, motor drivers, relay modules) for loads exceeding this limit. I’ve seen countless burned-out pins from direct motor connections – don’t learn this lesson the hard way.

Q: How many PWM devices can I control simultaneously?

A: Arduino Uno has 6 hardware PWM pins, so you can control 6 devices with hardware PWM. For more devices, use software PWM (less accurate, CPU-intensive), PWM expansion boards (like PCA9685 with I2C – controls up to 16 channels), or multiplexing techniques. I’ve successfully controlled 12 RGB LEDs (36 channels) using PCA9685 modules.

Q: What’s the difference between PWM and true analog output?

A: PWM rapidly switches between HIGH and LOW to simulate analog voltage through averaging. True analog (from a DAC) provides continuous voltage levels. PWM works perfectly for motors, LEDs, and heating elements where inertia smooths the signal. For precision analog requirements (like audio or sensitive analog circuits), use dedicated DAC modules. Arduino Due has built-in DACs on pins DAC0 and DAC1.

Conclusion

Understanding PWM is crucial for any Arduino project involving analog-like control. Throughout my years designing embedded systems and PCBs, I’ve found that mastering this Arduino PWM tutorial opens doors to countless applications – from simple LED dimmers to complex motor control systems.

The key takeaways: PWM simulates analog output digitally, duty cycle determines effective voltage, only specific pins support hardware PWM, and most applications need supporting hardware (drivers, filters, or protection circuits).

Start with simple LED fading projects to build intuition, then progress to motors and more complex applications. Pay attention to current limitations, use proper driver circuits, and don’t be afraid to experiment with different frequencies for your specific needs.

Whether you’re dimming LEDs, controlling motor speeds, or mixing RGB colors, PWM gives you precise analog-like control with minimal hardware complexity. Now go build something amazing!

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.

  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.

Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.