Faking Analog: Master PWM to Fade LEDs and Control Motors

Faking Analog: Master PWM to Fade LEDs and Control Motors


📑Table of Contents
What You'll Need 5 items
Arduino Uno R3
Buy
Breadboard
Buy
5mm LED
Buy
220Ω Resistor
Buy
Jumper Wires
Buy

Affiliate links help support this site at no extra cost to you.

Welcome to Day 15. Yesterday, we learned how to Read analog values (0 to 1023) using the ADC. Today, we ask the opposite question: Can the Arduino Write analog values?

If you check the specs of the ATmega328P chip, the answer is a hard NO. It is a digital chip. It can output 0V or 5V. That is it. There is no “2.5V” setting.

So… how do we dim an LED? How do we make a robot move at “Half Speed”? How do we make an RGB light turn purple?

We cheat. We use a technique called Pulse Width Modulation (PWM). We switch the pin ON and OFF so fast that the human eye (or the motor) gets tricked into thinking it sees a lower voltage.

PWM Spectrum Intro Art

The Theory: Duty Cycle

Imagine you have a light switch.

  1. You turn it ON. Room is bright (5V).
  2. You turn it OFF. Room is dark (0V).
  3. Now, flip the switch ON and OFF 500 times a second.
  4. If you keep it ON for 50% of the time, and OFF for 50% of the time, your brain averages it out.
  5. The room looks like it is at 50% Brightness.

This percentage of “ON Time” is called the Duty Cycle.

  • 0% Duty Cycle: Always OFF (0V).
  • 25% Duty Cycle: ON for 1ms, OFF for 3ms. (Effective 1.25V).
  • 50% Duty Cycle: ON for 2ms, OFF for 2ms. (Effective 2.5V).
  • 100% Duty Cycle: Always ON (5V).

Duty Cycle Chart Square Waves

The Code: analogWrite()

To control this, we use the command analogWrite(pin, value). Wait, why is it called analogWrite if it’s actually digital switching? Because Arduino likes to keep things simple. It behaves like analog writing.

The Resolution (0-255)

Unlike analogRead (which is 10-bit, 0-1023), analogWrite is 8-bit. It accepts a value between 0 and 255.

  • 0 = 0% (OFF)
  • 64 = 25%
  • 127 = 50%
  • 255 = 100% (ON)

The Magic Pins (~)

You cannot use PWM on just any pin. Look closely at your Arduino board. Next to pins 3, 5, 6, 9, 10, 11, you will see a tiny wiggle symbol: ~ (Tilde). These are the PWM-capable pins. If you try analogWrite(2, 127), nothing will happen (or it will just turn fully ON). Rule: Always plug fading LEDs into Tilde pins.

Deep Dive: Software PWM (Breaking the Rules)

What if you run out of PWM pins? Can you use Pin 2? Yes, but you have to do the work yourself. You can write code that manually toggles the pin very fast.

void loop() {
  digitalWrite(2, HIGH);
  delayMicroseconds(500); // ON time
  digitalWrite(2, LOW);
  delayMicroseconds(1500); // OFF time
}

This mimics a 25% duty cycle. The downside? Your code cannot do anything else. This is why hardware PWM (handled by the chip’s internal timers) is superior. It runs in the background while your code calculates other things.

Tilde Pin Zoom Macro

Project 1: The Breathing LED

Let’s recreate the classic “Sleep Mode” light from MacBook laptops. It gently fades in and out, like it is breathing.

The Wiring

  1. LED on Pin 9 (PWM).
  2. 220Ω Resistor to Series.
  3. Cathode to GND.

The Code

We need two loops. One to count UP, one to count DOWN.

int ledPin = 9;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Fade IN (0 to 255)
  for (int brightness = 0; brightness <= 255; brightness++) {
    analogWrite(ledPin, brightness);
    delay(10); // Wait 10ms for the eye to see it
  }

  // Fade OUT (255 to 0)
  for (int brightness = 255; brightness >= 0; brightness--) {
    analogWrite(ledPin, brightness);
    delay(10);
  }
}

Math check: 255 steps * 10ms = 2550ms (2.5 seconds) to fade up. Total cycle = 5 seconds. A slow, relaxing breath.

Breathing Effect Sine Wave

Project 2: RGB Color Mixing

Now that we can dim, we can Mix Colors. An RGB LED is just 3 LEDs (Red, Green, Blue) stuffed into one plastic shell. By fading them at different levels, we can create any color in the rainbow.

  • Red + Green = Yellow.
  • Red + Blue = Magenta.
  • Green + Blue = Cyan.
  • Red + Green + Blue = White.

Wiring the RGB LED

It has 4 legs. The Longest Leg is the Common. Check if yours is Common Cathode (connect to GND) or Common Anode (connect to 5V). Most kits have Common Cathode.

  1. Pin 9 -> Resistor -> Red Leg.
  2. Pin 10 -> Resistor -> Green Leg.
  3. Pin 11 -> Resistor -> Blue Leg.
  4. GND -> Long Leg.

RGB LED Pinout Render

The Code

int redPin = 9;
int greenPin = 10;
int bluePin = 11;

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
}

void loop() {
  // Make PURPLE (Red + Blue)
  analogWrite(redPin, 255);
  analogWrite(greenPin, 0);
  analogWrite(bluePin, 255);
  delay(1000);

  // Make ORANGE (Full Red + Half Green)
  analogWrite(redPin, 255);
  analogWrite(greenPin, 128); // 50% Green
  analogWrite(bluePin, 0);
  delay(1000);
}

Color Mixing Wheel

The Trap: The Blocking Delay

Look at our breathing code again. delay(10); It runs 512 times per breath cycle. That means for 5 seconds, your Arduino is effectively coma-tose. It cannot read a button. It cannot check a sensor. It is stuck in the delay(). This is fine for simple toys, but terrible for robots. The Solution: Later (Day 21), we will learn millis(). It is like checking a watch (“Is it time to change brightness yet?”) instead of sleeping (“Wake me up in 10ms”). For now, enjoy the simplicity of delay(), but know that it is a bad habit.

Challenge: The Electronic Candle

Fading is cool. But Randomness is better. Can you make an LED flicker like a candle in the wind? Hardware: Yellow LED on Pin 9. Code:

void loop() {
  analogWrite(9, random(100, 255));
  delay(random(10, 100));
}

random(min, max) picks a random number. This creates a jittery, organic light. Put it inside a translucent cup. You have a safe flameless candle.

Challenge: The Mood Lamp

You built a breathing light. Now build a Mood Lamp. Goal:

  • Start at Red.
  • Fade seamlessly to Green.
  • Fade seamlessly to Blue.
  • Fade back to Red. Hint: You will need nested loops or a long sequence of loops. Red -> Green means: Red goes Down, Green goes Up (at the same time).
for (int i=0; i<255; i++) {
   analogWrite(redPin, 255-i);
   analogWrite(greenPin, i);
   delay(10);
}

If you put this inside a paper lantern, you have a 50PhilipsHuebulbfor50 Philips Hue bulb for 2.

Hardware Deep Dive: 490Hz vs 980Hz

Not all PWM pins are created equal.

  • Pins 3, 9, 10, 11: Run at 490 Hz.
  • Pins 5, 6: Run at 980 Hz (Double speed). Why? Because Pins 5/6 are connected to the internal Timer0, which also controls millis() and delay(). This is why messing with PWM frequencies (advanced hacking) can sometimes break your timing functions. For LEDs, you won’t notice. For DC Motors, 980Hz is often smoother and quieter!

The Bill of Materials (BOM)

ComponentQuantityValueNotes
Arduino Uno1R3 or R4The Brain
RGB LED1Common CathodeThe Output
Resistors3220Ω - 330ΩCurrent Limiting
Jumper Wires4M-MConnectivity
Breadboard1Half+Prototyping

Deep Dive: The Motor Connection

Why do we care about fading LEDs? Because the exact same logic controls Motors. If you connect a DC motor to a pin (via a Transistor!), analogWrite(127) makes it spin at half speed. This is how Drones stabilize themselves. They adjust the PWM of each propeller thousands of times a second. This is how your car’s fan adjusts speed. PWM is the language of power control.

Internal Switch Abstract

Advanced Academy: The Lie of Linearity (Gamma Correction)

If you run the fade code above, you might notice something weird. The LED seems to get bright REALLY fast, and then stays bright for a long time. Why? Because the human eye is Logarithmic (just like we learned with Potentiometers yesterday). Twice the power does NOT look like twice the brightness to us. To make a fade look “smooth” to a human, you actually need an Exponential curve. You have to increase brightness slowly at first (1, 2, 4, 8) and fast at the end (…, 64, 128, 255). This math fixes the “Gamma” of the LED. Professional lighting controllers use lookup tables to fix this. For now, just know your eyes are deceiving you.

Math Class: PWM Power Calculation

Here is a physics trick. If you run an LED at 50% Duty Cycle (2.5V effective), does it use 50% Power? Power = Voltage * Current. Or: P=V2/RP = V^2 / R. Since the Voltage is square-waved, the Average Power is indeed 50%. But the Peak Power is still 100% during the ON phase. This is important for resistors. Even if you dim an LED to 1%, you MUST still use a resistor that can handle 100% current. Because for that tiny 1% slice of time, the full 5V is hitting the LED. Rule: Calculate resistors based on Peak Voltage (5V), never Average Voltage.

Safety: The Heat Trap (MOSFETs)

When driving Motors with PWM (via a MOSFET), a dangerous thing happens. MOSFETs hate being “halfway” on. They love being Fully ON (0 Resistance) or Fully OFF (Infinite Resistance). During the transition (the rising edge of the square wave), they act like resistors and generate Heat. If you PWM a massive motor at 20kHz, the MOSFET spends a lot of time in that “transition zone”. It might get hot enough to melt your breadboard. Solution: Use a “Gate Driver” chip to snap the MOSFET on/off instantly, minimizing the transition time. Or just add a heatsink.

History: Where did PWM come from?

It wasn’t invented for LEDs. It was invented for Communication. In the 1940s, ITT engineers used Pulse Time Modulation to squeeze multiple phone calls onto a single wire. By shrinking the pulses, they could fit silence between them for other signals. Today, we use it to drive Class-D Audio Amplifiers (which are 90% efficient compared to old 50% Class-AB amps).

Challenges with PWM

  1. The Frequency Noise: Standard Arduino PWM runs at 490Hz or 980Hz. This is audible to some human ears (a faint whine) and definitely dogs.
  2. The Camera Flicker: If you film your project with a camera, the LEDs might flicker on video. This is because the camera’s shutter speed clashes with the PWM frequency.
  3. Not True Analog: If you need true smooth voltage (for audio), you need a “Low Pass Filter” (Capacitor + Resistor) to smooth out the square waves.

Troubleshooting Guide

SymptomCauseSolution
Colors look wrongCommon Anode LEDInvert your logic (255 is OFF)
Red is too brightEfficiency MismatchUse 330Ω for Red, 220Ω for others
LED just blinksWrong PinMove wire to Pin ~, 3, 5, 6, 9, 10, 11
Flickering VideoCamera ShutterReduce shutter speed or increase PWM freq

Nerd Corner: Why 255?

Why is the limit 255? Why not 100 or 1000? Because 255 is the maximum value of an 8-bit byte. 28=2562^8 = 256. (0 to 255). The ATMega328 registers are 8 bits wide. To store a value like 256, it would need TWO registers (16 bits). Using 8 bits makes the PWM incredibly fast and memory efficient. We live within the limits of the hardware.

Optimization: The Bitwise Hack

If you want to divide a number by 2 very fast: don’t do x / 2. Do x >> 1. This shifts the bits to the right. 0000 1000 (8) becomes 0000 0100 (4). This is how the internal timers handle PWM scaling.

The Engineer’s Glossary (Day 15)

  • PWM: Pulse Width Modulation. Tricking the eye with fast switching.
  • Duty Cycle: The percentage of time the signal is HIGH.
  • RGB: Red Green Blue color model.
  • Common Cathode: All LEDs share a Ground connection.
  • Tilde (~): The symbol indicating PWM capability on Arduino.

Advanced Application: Servo Motors

We said PWM controls “Speed”. But for Servo Motors, it controls Position. A Servo expects a pulse every 20ms.

  • A 1ms pulse means “Go to 0 degrees”.
  • A 1.5ms pulse means “Go to 90 degrees”.
  • A 2ms pulse means “Go to 180 degrees”. This is a specific type of PWM. The Arduino Servo library handles it for you, but under the hood, it is just analogWrite logic running with very precise timing.

Advanced Application: The Fan Controller

If you want to control a PC Fan (12V):

  1. You CANNOT plug it into the Arduino (5V).
  2. You CAN plug it into a 12V supply.
  3. You CAN put a MOSFET Transistor (Day 25) between the Fan and Ground.
  4. You CAN connect the Arduino PWM pin to the MOSFET Gate. Now, when you analogWrite(128), the MOSFET flickers the Fan’s power 490 times a second. The fan spins at 50% speed. This is how every variable-speed drill, fan, and drone works.

Hack: Creating “True” Analog (RC Filter)

If you really need a steady 2.5V line (not flickering):

  1. Add a Resistor in series with the PWM pin.
  2. Add a Capacitor from the resistor to Ground. This creates an RC Low Pass Filter. The Capacitor stores the charge during the ON pulse and releases it during the OFF pulse. It smooths out the square waves into a wobbly line. If your PWM is fast enough, the line becomes flat. This is how Arduinos can “Talk” (play audio files) by faking sound waves.

Conclusion

You have mastered the art of the fake. You can now create smooth transitions, organic pulsing lights, and unlimited colors. Between digitalWrite (Day 11), analogRead (Day 14), and analogWrite (Day 15), you have complete control over the input and output of energy.

Tomorrow, on Day 16, we combine everything. We will take the LDR (Light Sensor) and the Piezo Buzzer (Sound). We will build a Theremin—a musical instrument you play without touching, manipulating sound waves with light.

See you on Day 16.

Comments