PWM Analog Outputs on Arduino

Understanding how to use PWM to simulate analog outputs in Arduino.

Introduction

Sometimes, a simple digital output (ON/OFF) is not sufficient, and we need to generate an analog signal to control brightness, speed, or other variables. Arduino achieves this through Pulse Width Modulation (PWM).

How Does an Analog Output Work?

Arduino does not provide true analog outputs. Instead, it rapidly switches a digital output between HIGH and LOW, creating an average voltage over time.

This technique is called Pulse Width Modulation (PWM), where the proportion of time the signal remains HIGH within a cycle determines the perceived output voltage.

PWM Signal Representation

PWM is Not a True Analog Signal

It is crucial to understand that PWM does not generate a continuous analog voltage. Instead, it simulates one by varying the duty cycle.

For example, if we need a 3V output from a 5V system, a 60% duty cycle PWM signal is used (5V * 0.6 = 3V).

Arduino PWM Pins

Arduino has dedicated PWM-capable pins, marked with a ~ symbol:

Basic PWM Example

Below is a simple Arduino program that gradually increases the PWM output from 0 to 255:


const int analogOutPin = 5; 
byte outputValue = 0; 

void setup() {
}

void loop() {
  analogWrite(analogOutPin, outputValue);
  delay(10);
  outputValue++;
}
            

Using PWM to Control LED Brightness

A common use case for PWM is controlling LED brightness. The following circuit demonstrates this principle:

PWM LED Brightness Control

Using PWM to Control Motor Speed

DC motors can be controlled using PWM. The duty cycle determines the motor speed.


            const int motorPin = 9; 
            int speedValue = 128; 
                
            void setup() {
              pinMode(motorPin, OUTPUT);
                }
                
            void loop() {
                analogWrite(motorPin, speedValue);
                delay(1000);
                }
                            

Advanced PWM Control with Serial Input

We can control the PWM output using serial input. The code below reads a number (0-9) from the serial monitor and adjusts the PWM output accordingly:


const int analogOutPin = 11;
byte outputValue = 0;

void setup() {
   Serial.begin(9600);
   pinMode(analogOutPin, OUTPUT);
}

void loop() {
   if (Serial.available() > 0) {
      outputValue = Serial.read();
      if (outputValue >= '0' && outputValue <= '9') {
         outputValue = (outputValue - '0') * 25;
         analogWrite(analogOutPin, outputValue);
      }
   }
}