Overview

A potentiometer (often called a "pot") is a simple yet powerful analog input device. It's essentially a variable resistor that you can adjust by turning a knob, allowing you to control voltage levels in your circuits.

In this lesson, you'll learn how to read the potentiometer's position using the ATmega328P's ADC (Analog-to-Digital Converter) and create interactive projects that respond to your input.

Real-World Applications

Potentiometers are used in:

  • Volume controls on audio equipment
  • Brightness controls on displays
  • Throttle controls in robotics
  • Adjustable power supplies
  • Game controller joysticks
  • Industrial process controls

Prerequisites

Before starting, make sure you have completed:

Completed Lessons
  • Lesson 1: Blinking LED
  • Lesson 2: Push Button Input
  • Lesson 3: Buzzer Sound Generation
  • Understanding of Serial Monitor
Hardware Requirements
  • Vumbua Synapse Kit with potentiometer
  • USB Type-C cable
  • Computer with Arduino IDE
On Vumbua Synapse Kit

The potentiometer is pre-connected to the Vumbua board on Analog Pin A0. You can simply rotate the knob to adjust its value - no additional wiring needed!

Learning Objectives

By the end of this lesson, you will be able to:

  • Understand how potentiometers work as variable resistors
  • Read analog values using analogRead()
  • Use the map() function to convert values
  • Control LED brightness with PWM
  • Create interactive dials and sliders
  • Understand the ADC in ATmega328P
  • Display analog values on Serial Monitor
  • Build practical applications with analog input

What is a Potentiometer?

The Variable Resistor

A potentiometer has three terminals and acts as a variable voltage divider:

  • Terminal 1: Connected to ground (0V)
  • Terminal 2: The wiper (variable output)
  • Terminal 3: Connected to voltage source (5V)

As you turn the knob, the wiper moves along a resistive track, changing the resistance between the wiper and each end terminal.

Types of Potentiometers

Common types found in electronics:

  • Rotary: Knob you turn (like volume control)
  • Linear/Slide: Slider you move back and forth
  • Trimmer: Small screwdriver-adjustable pot
  • Digital: Uses digital signals instead of resistance
Specifications

Potentiometers are specified by:

  • Resistance Value: 10kΩ (10,000 ohms) is common
  • Taper: Linear (most common) or logarithmic
  • Power Rating: How much power they can handle
  • Tolerance: How accurate the resistance is

Potentiometer Connections

The potentiometer on Vumbua Synapse Kit has 3 pins:

Left Pin
Connected to Ground (0V)
GND
Middle Pin (Wiper)
Variable output to Arduino
Analog Pin A0
Right Pin
Connected to 5V
5V
Voltage Divider Configuration

The potentiometer is wired as a voltage divider:

  1. 5V applied to one end
  2. Ground connected to the other end
  3. Middle pin provides variable voltage (0-5V)
  4. Arduino reads this voltage on pin A0

Voltage Divider Principle

Understanding how a potentiometer works requires understanding voltage dividers:

Voltage Divider Formula

When two resistors are connected in series, the voltage at their junction is:

Vout = Vin × (R2 ÷ (R1 + R2))
5V
Input Voltage
→
R1
Variable Resistor
→
Vout
0-5V Output
→
R2
Variable Resistor
→
GND
0V

As you turn the potentiometer knob, R1 and R2 change (but R1 + R2 always equals total resistance), causing Vout to vary between 0V and 5V.

Potentiometer Positions
Knob Position Output Voltage Arduino Reading
Fully Counter-Clockwise 0V 0
Middle 2.5V 512
Fully Clockwise 5V 1023

Using analogRead() Function

The analogRead() function is key to reading potentiometer values:

Function Syntax
int sensorValue = analogRead(pin);

Where pin is the analog pin number (A0-A5 on Vumbua).

Return Values

analogRead() returns an integer between 0 and 1023:

  • 0 = 0V input
  • 512 = 2.5V input
  • 1023 = 5V input

This is because the ATmega328P has a 10-bit ADC (2¹⁰ = 1024 values).

Resolution

The ADC resolution determines the smallest voltage change it can detect:

Resolution = (5V ÷ 1024) = 0.0049V = 4.9mV

This means the Arduino can detect voltage changes as small as 4.9 millivolts!

Basic Potentiometer Reading

Let's start with a simple program to read and display potentiometer values:

potentiometer_basic.ino
/*
  Vumbua Synapse Kit - Lesson 4: Basic Potentiometer Reading
  Read analog values from potentiometer on pin A0
  Display raw value, voltage, and percentage
*/

const int potPin = A0;   // Potentiometer connected to analog pin A0

void setup() {
  // Initialize Serial communication
  Serial.begin(9600);
  
  // Note: No pinMode needed for analog input pins
  
  Serial.println("Potentiometer Reading Program");
  Serial.println("=============================");
  Serial.println("Turn the potentiometer knob to see values change");
  Serial.println();
}

void loop() {
  // Read the potentiometer value (0-1023)
  int rawValue = analogRead(potPin);
  
  // Convert raw value to voltage (0-5V)
  float voltage = rawValue * (5.0 / 1023.0);
  
  // Convert to percentage (0-100%)
  int percentage = map(rawValue, 0, 1023, 0, 100);
  
  // Display results in Serial Monitor
  Serial.print("Raw Value: ");
  Serial.print(rawValue);
  Serial.print("  |  Voltage: ");
  Serial.print(voltage);
  Serial.print("V  |  Position: ");
  Serial.print(percentage);
  Serial.println("%");
  
  // Wait before next reading (20 readings per second)
  delay(50);
}

Testing the Program

1. Upload the Code

Upload to your Vumbua Synapse Kit. The potentiometer is already connected to pin A0 on the board.

2. Open Serial Monitor

Go to Tools → Serial Monitor or press Ctrl+Shift+M. Set the baud rate to 9600.

3. Rotate the Potentiometer

Turn the potentiometer knob slowly from one end to the other. Watch the values change:

  • Raw Value: Should change from 0 to 1023
  • Voltage: Should change from 0.00V to 5.00V
  • Percentage: Should change from 0% to 100%
Note: Analog vs Digital Pins

Unlike digital pins, analog pins (A0-A5) don't require pinMode() setup for reading. They're automatically configured as inputs when you use analogRead().

Using map() Function

The map() function is incredibly useful for converting values from one range to another:

potentiometer_map.ino
/*
  Vumbua Synapse Kit - Lesson 4: Using map() Function
  Demonstrate different mapping applications
*/

const int potPin = A0;

void setup() {
  Serial.begin(9600);
  Serial.println("map() Function Demonstration");
  Serial.println("==========================");
}

void loop() {
  int rawValue = analogRead(potPin);
  
  // Example 1: Percentage (0-100%)
  int percentage = map(rawValue, 0, 1023, 0, 100);
  
  // Example 2: Angle (0-270 degrees)
  int angle = map(rawValue, 0, 1023, 0, 270);
  
  // Example 3: PWM Value (0-255 for analogWrite)
  int pwmValue = map(rawValue, 0, 1023, 0, 255);
  
  // Example 4: Temperature simulation (-10°C to 50°C)
  int temperature = map(rawValue, 0, 1023, -10, 50);
  
  // Example 5: Reverse mapping (1023 to 0)
  int reversed = map(rawValue, 0, 1023, 1023, 0);
  
  // Display all mapped values
  Serial.print("Raw: ");
  Serial.print(rawValue);
  Serial.print(" | %: ");
  Serial.print(percentage);
  Serial.print(" | Angle: ");
  Serial.print(angle);
  Serial.print("° | PWM: ");
  Serial.print(pwmValue);
  Serial.print(" | Temp: ");
  Serial.print(temperature);
  Serial.print("°C | Rev: ");
  Serial.print(reversed);
  Serial.println();
  
  delay(200);
}
How map() Works

The map(value, fromLow, fromHigh, toLow, toHigh) function linearly scales a value:

result = (value - fromLow) × (toHigh - toLow) ÷ (fromHigh - fromLow) + toLow

It's perfect for converting analog readings into meaningful values for your projects!

LED Brightness Control

Now let's combine potentiometer reading with LED control to create a brightness dimmer:

led_brightness_control.ino
/*
  Vumbua Synapse Kit - Lesson 4: LED Brightness Control
  Control LED brightness using potentiometer
  Uses PWM (Pulse Width Modulation) on pin 9
*/

const int potPin = A0;      // Potentiometer on A0
const int ledPin = 9;      // LED on pin 9 (PWM capable)

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  
  Serial.println("LED Brightness Controller");
  Serial.println("Turn potentiometer to adjust LED brightness");
}

void loop() {
  // Read potentiometer value (0-1023)
  int potValue = analogRead(potPin);
  
  // Map potentiometer value to PWM range (0-255)
  int brightness = map(potValue, 0, 1023, 0, 255);
  
  // Set LED brightness using analogWrite()
  analogWrite(ledPin, brightness);
  
  // Calculate percentage for display
  int percentage = map(brightness, 0, 255, 0, 100);
  
  // Display status
  Serial.print("Potentiometer: ");
  Serial.print(potValue);
  Serial.print(" | Brightness: ");
  Serial.print(brightness);
  Serial.print(" (");
  Serial.print(percentage);
  Serial.println("%)");
  
  // Small delay for readability
  delay(100);
}

Understanding PWM (Pulse Width Modulation)

What is PWM?

PWM rapidly switches a digital signal on and off to simulate an analog output. The percentage of time the signal is HIGH determines the "effective voltage."

PWM Values

analogWrite() accepts values from 0 to 255:

  • 0: Always OFF (0% duty cycle)
  • 127: Half brightness (~50% duty cycle)
  • 255: Always ON (100% duty cycle)
PWM Pins on Vumbua

On the ATmega328P, PWM is available on specific pins marked with ~:

  • Pin 3
  • Pin 5
  • Pin 6
  • Pin 9
  • Pin 10
  • Pin 11
Potentiometer Position
50%
LED Brightness
50%

Advanced Applications

Project 1: Volume Control with Buzzer

Combine potentiometer with buzzer from Lesson 3 to create a volume control:

volume_control.ino
/*
  Vumbua Synapse Kit - Volume Control System
  Use potentiometer to control buzzer frequency and volume
*/

const int potPin = A0;       // Potentiometer on A0
const int buzzerPin = 3;    // Buzzer on pin 3
const int ledPin = 9;       // LED on pin 9

void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  
  Serial.println("Volume Control System Active");
  Serial.println("Turn potentiometer to adjust tone");
}

void loop() {
  int potValue = analogRead(potPin);
  
  // Map to frequency range (100Hz to 2000Hz)
  int frequency = map(potValue, 0, 1023, 100, 2000);
  
  // Map to LED brightness (0-255)
  int brightness = map(potValue, 0, 1023, 0, 255);
  
  // Generate tone with current frequency
  tone(buzzerPin, frequency);
  
  // Control LED brightness
  analogWrite(ledPin, brightness);
  
  // Display status
  Serial.print("Position: ");
  Serial.print(map(potValue, 0, 1023, 0, 100));
  Serial.print("% | Frequency: ");
  Serial.print(frequency);
  Serial.println(" Hz");
  
  delay(100);
}

Project 2: RGB Color Mixer

Use potentiometer to cycle through colors on an RGB LED (if available):

rgb_color_mixer.ino
/*
  Vumbua Synapse Kit - RGB Color Mixer
  Cycle through colors using potentiometer
  Simulates RGB control using built-in LED
*/

const int potPin = A0;
const int redPin = 9;     // Simulated red channel
const int greenPin = 10;   // Simulated green channel
const int bluePin = 11;    // Simulated blue channel

void setup() {
  Serial.begin(9600);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  
  Serial.println("RGB Color Mixer");
  Serial.println("Turn potentiometer to cycle through colors");
}

void loop() {
  int potValue = analogRead(potPin);
  
  // Create a color cycle based on potentiometer position
  int red, green, blue;
  
  if (potValue < 341) {
    // Red to Yellow
    red = 255;
    green = map(potValue, 0, 340, 0, 255);
    blue = 0;
  } else if (potValue < 682) {
    // Yellow to Green
    red = map(potValue, 341, 681, 255, 0);
    green = 255;
    blue = 0;
  } else {
    // Green to Blue
    red = 0;
    green = map(potValue, 682, 1023, 255, 0);
    blue = map(potValue, 682, 1023, 0, 255);
  }
  
  // Set colors
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
  
  // Display color values
  Serial.print("RGB: (");
  Serial.print(red);
  Serial.print(", ");
  Serial.print(green);
  Serial.print(", ");
  Serial.print(blue);
  Serial.println(")");
  
  delay(100);
}

ATmega328P ADC - How It Works

The ATmega328P's built-in ADC is what makes analog reading possible:

10-bit Resolution

The ADC converts analog voltage (0-5V) to a 10-bit digital number (0-1023). This means it can distinguish 1024 different voltage levels.

Resolution = 5V ÷ 1024 = 0.0049V (4.9mV per step)

Conversion Process

When analogRead() is called:

  1. ADC connects to the selected pin
  2. Voltage is compared against internal reference (5V)
  3. Successive approximation algorithm determines digital value
  4. Conversion takes about 100 microseconds
  5. Result is stored and returned
ADC Channels

The ATmega328P has 6 ADC channels (A0-A5) that can be used for analog input:

  • A0: Potentiometer on Vumbua
  • A1-A5: Available for other sensors
  • Each can measure 0-5V with 10-bit precision
Reference Voltage

By default, the ADC uses the 5V power supply as reference. For more precise measurements, you can use the internal 1.1V reference or an external reference voltage.

To change reference voltage: analogReference(type);

Troubleshooting Common Issues

Common Potentiometer Problems

  • Solution: Add a small capacitor (10nF-100nF) between A0 and GND
  • Alternative: Use software smoothing (averaging)
  • Check: Make sure potentiometer is properly connected to A0
  • Try: Different sampling rates with delay()

  • Check: LED is connected to a PWM pin (3, 5, 6, 9, 10, 11)
  • Verify: Using analogWrite() not digitalWrite()
  • Test: Try different LED (some LEDs have minimum brightness threshold)
  • Consider: Using a transistor for higher power LEDs

  • Check: Potentiometer wiring (5V, GND, A0)
  • Test: Measure voltage at A0 pin with multimeter
  • Verify: Correct pin declaration: const int potPin = A0;
  • Try: Different potentiometer or test with known values

Software Smoothing Example

// Smoothing algorithm for stable readings
const int numReadings = 10;
int readings[numReadings];
int readIndex = 0;
int total = 0;
int average = 0;

void setup() {
  Serial.begin(9600);
  // Initialize all readings to 0
  for (int i = 0; i < numReadings; i++) {
    readings[i] = 0;
  }
}

void loop() {
  // Subtract the last reading
  total = total - readings[readIndex];
  // Read from sensor
  readings[readIndex] = analogRead(A0);
  // Add the reading to the total
  total = total + readings[readIndex];
  // Advance to the next position
  readIndex = readIndex + 1;
  
  // If at end of array, wrap around
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  
  // Calculate average
  average = total / numReadings;
  Serial.println(average);
  delay(1);
}

Video Demonstration

Video Tutorial Coming Soon!

We're preparing a detailed video walkthrough for this lesson.

Subscribe to our YouTube channel to be notified when it's available.

Subscribe to OLSPACE

What's Next?

Congratulations! You've successfully mastered analog input with potentiometers. Here's what you've accomplished:

  • ✓ Learned how potentiometers work as voltage dividers
  • ✓ Used analogRead() to read values from A0
  • ✓ Mastered the map() function for value conversion
  • ✓ Controlled LED brightness with PWM
  • ✓ Created interactive projects with analog input
  • ✓ Understood the ATmega328P ADC operation

In the next lesson, you'll explore light sensing:

Lesson 5: Light Sensor (BH170)

Learn to measure ambient light intensity using the BH170 light sensor. Create automatic lighting systems, daylight detectors, and light-activated projects that respond to environmental changes.

Resources & Downloads