Pulse width modulation is a very useful technique for controlling things with Arduino. You can control LED brightness, the speed of the DC Motor, the direction of the Servo Motor, etc. using PWM.

In this tutorial, we will explore Pulse Width Modulation (PWM), and how to use it to control the brightness of an LED. 

What is Pulse Width Modulation (PWM)?

Many Arduino boards have digital output pins that can only provide two states: HIGH (5V) or LOW (0V). However, many devices require analog signals with varying voltage levels to control their behaviour, such as dimming an LED. 

As Arduino UNO doesn’t have a Digital to Analog converter to produce an analog signal hence PWM is required. By using PWM, we can simulate any voltage between 0V to 5V by changing the width of the pulses.

This technique switches a square wave between ON and OFF states. This on-off pattern can simulate voltages between the board’s Vcc (e.g. 5V on UNO) and OFF (0V) by changing the portion of the time the signal remains ON versus the time that the signal remains OFF. The duration of “ON time” is called the pulse width. So, to get varying analog values, we change or modulate that pulse width.

What is the Duty Cycle of PWM Signal?

The duty cycle of a PWM (Pulse Width Modulation) signal refers to the percentage of time the signal is ON (high) divided by the total time of the signal’s period. It represents how much of the time the signal remains high in the total time period.

Duty Cycle = (ON Time / Time period) * 100

e.g., A pulse with a period of 20ms will remain ON (HIGH) for 5ms. Therefore, duty cycle will be

D = 2ms / 10ms = 25%

If a digital signal spends half of the time ON (High state) and the other half OFF (Low state), we call it a square wave with a 50% duty cycle. If the duty cycle is more than 50%, it means the signal is spending more time ON than OFF. And if it’s less than 50%, it’s spending more time OFF than ON. Here is an image that illustrates these three scenarios: 

Relation between Duty Cycle, Time Period and Frequency

100% duty cycle means setting the voltage to 5 volts (high). 0% duty cycle represents the lowest voltage level (e.g., 0 volts).

Amplitude of a PWM

The amplitude of a PWM signal refers to the difference between its maximum and minimum voltage levels. In simpler terms, it represents the range of voltage values that the PWM signal can produce.

Amplitude =  Vmax – Vmin

For example, if a PWM signal can vary between 0 volts (minimum) and 5 volts (maximum), then its amplitude would be 5 volts.

Duty Cycle to Analog Conversion

Analog Output Voltage = ( Duty cycle / 100 ) * Amplitude of the pulse

What is the Frequency of PWM Signal?

The frequency of a PWM signal refers to the number of times the signal repeats its cycle within one second. It is typically measured in Hertz (Hz), which represents cycles per second.

In simpler terms, the frequency indicates how fast the PWM signal switches between its ON and OFF states. A higher frequency means the signal switches more rapidly, while a lower frequency means it switches more slowly.

For example, if a PWM signal has a frequency of 100 Hz, it completes 100 cycles in one second. 

Arduino Pins Capable of PWM

In Arduino boards, several pins are capable of generating PWM signals. These pins are marked with a tilde (~) symbol on the board, such as digital pins 3, 5, 6, 9, 10, and 11 in Arduino Uno. This feature allows for easy implementation of PWM-based applications without the need for additional hardware.

PWM pins on Arduino UNO

BoardPinsFreqeuncy
UNO (R3 and earlier), Nano, Mini3, 5, 6, 9, 10, 11490 Hz (pins 5 and 6: 980 Hz)
UNO R4 (Minima, WiFi) *3, 5, 6, 9, 10, 11490 Hz
Mega2 - 13, 44 - 46490 Hz (pins 4 and 13: 980 Hz)
GIGA R1 **2 - 13500 Hz
Leonardo, Micro3, 5, 6, 9, 10, 11, 13490 Hz (pins 3 and 11: 980 Hz)
UNO WiFi Rev2, Nano Every3, 5, 6, 9, 10976 Hz
MKR boards *0 - 8, 10, A3, A4732 Hz
MKR1000 WiFi **0 - 8, 10, 11, A3, A4732 Hz
Zero **3 - 13, A0, A1732 Hz
Due ***2-131000 Hz

Some Useful Arduino Functions Related to Analog Pins

analogWrite() Function

The Arduino analogWrite() function is used to generate a Pulse Width Modulation signal on a digital pin of the Arduino board. 

Syntax: analogWrite(pin, value);

Parameters: It takes two parameters:

  • Pin: It specifies the digital pin number where the PWM signal will be generated.
  • Value: This parameter specifies the duty cycle of the PWM signal, ranging from 0 to 255.

The PWM frequency produced by analogWrite() is fixed and depends on the specific Arduino board. For Arduino Uno and similar boards, the PWM frequency is approximately 490 Hz for pins 3, 9, 10, and 11 and 980 Hz for pins 5 and 6.

Pulse Width Modulation Duty Cycle Waveform

analogRead() Function

This function is used to read the value of analog signal given to pin A0 to A5. Arduino UNO has 10-bit ADC hence this function returns 0 – 1023 based on the signal applied 0 to 5V.

Syntax: analogRead(pin);

Parameters:

  • Pin: name of the analog input pin to read. It can be A0, A1, A2, A3, A4, A5.
  • Returns: This function returns the analog reading on the Analog input pin min 0, max 1023.

map() function

This function is used to convert one range of values into another.

Syntax: map(inputValue, currentLow, currentHigh, targetLow, targetHigh)

Parameters:

  • inputValue: the input value which needs to be mapped.
  • currentLow: min input value.
  • currentHigh: max input value.
  • targetLow: min output value for min input.
  • targetHigh: max output value for max input.

The data type of all input parameters is signed long. It can handle negative values as well.

Returns: It returns the mapped value against inputValue. Data type: long.

      💡Must Read

Arduino Core Library Functions

Arduino Core Library Functions

This article will give you information about some commonly used pre-built functions in Arduino.

Controlling the Brightness of an LED using the PWM on Arduino UNO

In this section, we will write a program for Arduino to control the brightness of LED using the PWM pin. The duty cycle can be varied using a POT connected at analog input pin A0.

The analog value is read from the analog input A0 and this value will always be in the range of 0 to 1023. This value is mapped to the range of PWM value in the range of 0 to 255. This PWM value will be provided to the PWM pin which is connected to the LED. Later this PWM value is converted to duty cycle and is displayed on the 16×2 LCD.

PWM using Arduino Uno

      💡Must Read

Arduino Core Library Functions

Interfacing 16×2 LCD with Arduino

In this article, you will learn about how to interface a 16×2 LCD with an Arduino UNO and how to display custom characters on the LCD. 

Hardware and Software Requirements

Hardware Requirements

Sr. No.Component NameQuantityRemarksWhere to Buy
1Arduino UNO R31Revision R3Amazon
2LED15mm diameterAmazon
3Resistance1220 ohm, ¼ watt for connection with LCDAmazon
4Resistance1100 ohm, ¼ watt for connection with LEDAmazon
5POT210k-ohm, one for connection with LCD and one for controlling the duty cycleAmazon
6Bread-board1Big sizeAmazon
7Connection wires25For breadboard and Arduino connectionsAmazon

Connections

The connections between Arduino Uno and LCD is as follows:

LCD Side PinArduino Side/ Bread-board Connection
VSS/GND (Pin 1)Connected to Ground
VDD/VCC (Pin 2)Connected to 5V
VEE/Vo (Pin 3)Connected to Variable pin of 10k POT to Control Contrast of LCD
RS (Pin 4)12
R/W (Pin 5)Connected to Ground
Enable (Pin6)11
D0 (Pin 7)Pulled to Ground, No connection with Arduino
D1 (Pin 8)Pulled to Ground, No connection with Arduino
D2 (Pin 9)Pulled to Ground, No connection with Arduino
D3 (Pin 10)Pulled to Ground, No connection with Arduino
D4 (Pin 11)6
D5 (Pin 12)7
D6 (Pin 13)8
D7 (Pin 14)9
LED(+) (Pin 15)Connected to Vcc via 220 ohm resistor
LED(-) (Pin 16)Connected to Ground

Software Requirement

Arduino IDE, Version 2.1.1 or above installed on your PC.

Code

/*
Controlling the Brightness of an LED using the PWM on Arduino UNO
by www.PlaywithCircuit.com 
*/
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 6, 7, 8, 9);

#define DUTYCYCLE_PIN A0
#define LED_PIN 3

void setup() {
  // Set up the LED pin as an output
  pinMode(LED_PIN, OUTPUT);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // set the cursor to (column = 0,row = 0)
  lcd.setCursor(0, 0);
  lcd.print("Duty Cycle :");
}

void loop() {
  // Read the value from the potentiometer
  int potValue = analogRead(DUTYCYCLE_PIN);

  // Map the potentiometer value to the range of PWM (0-255)
  int PWM_Value = map(potValue, 0, 1023, 0, 255);

  // Update the LED brightness (duty cycle)
  analogWrite(LED_PIN, PWM_Value);

  // Map the PWM_Value value to the range of DutyCycle (0-100)
  int dutyCycle = map(PWM_Value, 0, 255, 0, 100);

  // Print the Duty Cyle on the LCD
  lcd.setCursor(0, 1);
  lcd.print(dutyCycle);
  lcd.print(" %   ");

  // Delay to stabilize readings
  delay(100);
}

Output:

Controlling the brightness of an LED using the PWM on Arduino UNO

Code Explanation

In this code we are using LCD hence the Library of the LCD is included and input and output pins are defined using below lines:

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 6, 7, 8, 9);

#define DUTYCYCLE_PIN A0
#define LED_PIN 3

In the setup() function the LED pin is set as output pin and LCD is initialized using below lines of code.

void setup() {
  // Set up the LED pin as an output
  pinMode(LED_PIN, OUTPUT);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // set the cursor to (column = 0,row = 0)
  lcd.setCursor(0, 0);
  lcd.print("Duty Cycle :");
}

In the loop() function first the analog value is read from the analog input pin A0.

  // Read the value from the potentiometer
  int potValue = analogRead(DUTYCYCLE_PIN);

Then this value is mapped to PWM value using the map function and this PWM value is given to the PWM pin which is connected to the LED.

  // Map the potentiometer value to the range of PWM (0-255)
  int PWM_Value = map(potValue, 0, 1023, 0, 255);

  // Update the LED brightness (duty cycle)
  analogWrite(LED_PIN, PWM_Value);

In the later part of loop() function, the PWM value is mapped to the duty cycle which is displayed on the LCD.

  // Map the PWM_Value value to the range of DutyCycle (0-100)
  int dutyCycle = map(PWM_Value, 0, 255, 0, 100);

  // Print the Duty Cyle on the LCD
  lcd.setCursor(0, 1);
  lcd.print(dutyCycle);
  lcd.print(" %   ")