Analog to Digital Conversion (ADC)
Anand RamaswamiShare
Welcome Back, Maker!
In previous blog we learned how to read analog signals using analogRead(). We read the potentiometer, we read the LDR, and we got numbers between 0 and 1023.
But have you ever wondered — where does that number actually come from?
Why 0 to 1023? Why not 0 to 100 or 0 to 500?
In this blog we will look inside analogRead() and understand what is actually happening when the Arduino reads an analog pin.
What Is ADC?
ADC stands for Analog to Digital Conversion.
It is a circuit built inside the Arduino's microcontroller that takes a real-world voltage which can be any value between 0V and 5V and converts it into a whole number that the Arduino can work with.
The Arduino cannot store or process a voltage directly. It can only work with numbers. ADC is what bridges that gap.
Every time you call analogRead(), the ADC circuit inside the microcontroller is doing its job measuring the voltage and handing you a number.
That explains what ADC does. But it still leaves one important question: why does the number always fall between 0 and 1023?
Why 0 to 1023?
The Arduino Nano uses a 10-bit ADC.
The 10-bit part tells you how many steps the ADC divides the voltage range into.
10-bit means 2¹⁰ = 1024 possible steps.
So the full voltage range of 0V to 5V is divided into 1024 equal steps — numbered 0 to 1023.
|
ADC Value |
Voltage |
|
0 |
0V |
|
255 |
~1.25V |
|
511 |
~2.5V |
|
767 |
~3.75V |
|
1023 |
5V |
The more bits an ADC has, the more steps it has, and the more precisely it can measure voltage. A 10-bit ADC is standard for most beginner microcontrollers.
Now that we know the full range is split into 1024 steps, the next thing to understand is how much voltage each step represents.
Voltage Resolution
Since the ADC divides 5V into 1024 steps, each step represents a very small voltage change.
This is called voltage resolution — the smallest voltage change the ADC can detect.
Voltage Resolution = 5V ÷ 1023 = 0.00489V per step
This means the ADC can detect voltage changes as small as about 5 millivolts.
So if the voltage on the pin changes by less than 5mV, the ADC will not notice it. But for most beginner sensor projects this is more than precise enough.
Now that we understand where the ADC number comes from, we can use that knowledge in real projects.
Project 1: Display Actual Voltage on Serial Monitor
In this project we will read the potentiometer and display the actual voltage in volts on the Serial Monitor not just the raw 0 to 1023 number.
This shows you how to convert the ADC reading into a meaningful real-world value.
Code:
|
void setup() { Serial.begin(9600); } void loop() { int adcValue = analogRead(A6); // Read raw ADC value float voltage = (adcValue / 1023.0) * 5.0; // Convert to voltage Serial.print("ADC Value: "); Serial.print(adcValue); Serial.print(" Voltage: "); Serial.print(voltage); Serial.println(" V"); delay(300); } |
Converting ADC Value Back to Voltage
In previous blog, we read raw numbers from analogRead(). But sometimes you want to know the actual voltage on the pin — not just the number.
The formula to convert an ADC value back to voltage is:
| Voltage = (ADC Value ÷ 1023) × 5V |
Explanation:
analogRead(A6) reads the raw ADC value from the potentiometer. This is a number between 0 and 1023.
(adcValue / 1023.0) * 5.0 converts the ADC value into the actual voltage on the pin. Dividing by 1023.0 gives us the fraction of the full range. Multiplying by 5.0 scales it to the 0V–5V range.
float voltage stores the result as a decimal number so we can see values like 2.47V or 3.91V.
Serial.print() prints both the raw ADC value and the converted voltage side by side so you can see exactly how they relate to each other.
Turn the potentiometer knob and watch both values change together. When the knob is at maximum you should see ADC Value: 1023 and Voltage: 5.00V. At minimum you should see ADC Value: 0 and Voltage: 0.00V.
This first project helps us move from just reading numbers to understanding what those numbers mean physically.
Output:

Project 2: Potentiometer Controls LED Brightness Using Voltage Conversion
In this project we will use the potentiometer to control the brightness of an LED. But this time instead of using map() directly on the raw ADC value, we will first convert the ADC value into an actual voltage, and then convert that voltage into a PWM value for the LED.
This shows you how ADC values, real voltages, and PWM values are all connected.
Code:
|
void setup() { pinMode(9, OUTPUT); Serial.begin(9600); } void loop() { int adcValue = analogRead(A6); // Read raw ADC value float voltage = (adcValue / 1023.0) * 5.0; // Convert to voltage int brightness = (voltage / 5.0) * 255; // Convert voltage to PWM analogWrite(9, brightness); // Set LED brightness Serial.print("ADC: "); Serial.print(adcValue); Serial.print(" Voltage: "); Serial.print(voltage); Serial.print(" V Brightness: "); Serial.println(brightness); delay(100); } |
Explanation:
analogRead(A6) reads the raw ADC value from the potentiometer between 0 and 1023.
(adcValue / 1023.0) * 5.0 converts the ADC value into the actual voltage on the pin. For example if the knob is halfway the voltage will be around 2.5V.
(voltage / 5.0) * 255 converts the voltage into a PWM brightness value between 0 and 255. Since the maximum voltage is 5V, dividing by 5.0 gives us a fraction, and multiplying by 255 scales it to the PWM range.
analogWrite(9, brightness) sets the LED brightness based on the calculated PWM value.
The Serial Monitor prints all three values together — ADC value, voltage, and brightness — so you can see exactly how each one relates to the others as you turn the knob.
At 0V the LED is completely OFF. At 2.5V the LED is at half brightness. At 5V the LED is fully ON.
This project connects three important ideas together: analog input, voltage conversion, and PWM output.
Output:

Now let us take that same idea and apply it to a sensor instead of a knob.
Project 3: LDR Light Meter with LED Indicator
In this project the LED brightness is controlled by the amount of light falling on the LDR. The darker the environment, the brighter the LED glows — like an automatic night lamp that gets brighter as the room gets darker.
The LDR voltage drops when it gets dark. We use that dropping voltage to increase the LED brightness — so the two go in opposite directions.
Code:
|
void setup() { pinMode(9, OUTPUT); Serial.begin(9600); } void loop() { int adcValue = analogRead(A7); // Read LDR value float voltage = (adcValue / 1023.0) * 5.0; // Convert to voltage int brightness = 255 - (voltage / 5.0) * 255; // Invert for LED analogWrite(9, brightness); // Set LED brightness Serial.print("ADC: "); Serial.print(adcValue); Serial.print(" Voltage: "); Serial.print(voltage); Serial.print(" V Brightness: "); Serial.println(brightness); delay(100); } |
Explanation:
analogRead(A7) reads the LDR sensor on pin A7. In bright light the LDR gives a high ADC value and high voltage. In darkness it gives a low ADC value and low voltage.
(adcValue / 1023.0) * 5.0 converts the raw ADC reading into the actual voltage the LDR is producing.
255 - (voltage / 5.0) * 255 inverts the relationship between light and brightness. Without the inversion a bright environment would make the LED bright too. By subtracting from 255 we flip it — so when the voltage is high (bright light) the LED is dim, and when the voltage is low (darkness) the LED is bright.
analogWrite(9, brightness) sets the LED to the calculated brightness level.
The Serial Monitor prints the ADC value, voltage, and LED brightness together so you can see all three values changing in real time.
This project shows how ADC can be used not only for measuring values, but also for making the board react intelligently to the environment.
Output:

Now that we have used ADC in projects, let us put the full picture together.
ADC vs analogRead() :
Now that you understand ADC, here is what is actually happening every time you call analogRead():
- The Arduino measures the voltage on the analog pin
- The ADC circuit divides that voltage by the resolution (0.00489V per step)
- The result is a whole number between 0 and 1023
- That number is returned to your program
All of this happens in microseconds — faster than you can blink.
So analogRead() is the command you write, but ADC is the hardware system inside the microcontroller that does the real work.
Real-Life Examples of ADC
When you record your voice on a phone, the microphone produces a continuously changing voltage. The ADC inside the phone converts that voltage into millions of numbers per second — that is your audio file. That is ADC.
When a digital multimeter measures voltage, it uses an ADC to convert the measured voltage into a number shown on the display. That is ADC.
When a smartwatch measures your heart rate, the sensor produces a small changing voltage with every heartbeat. The ADC converts that into numbers the processor can analyse. That is ADC.
The common idea in all of these is simple — the real world produces voltages, and ADC converts those voltages into numbers that a digital system can understand and process.
Final Thoughts
You have been using ADC every time you called analogRead(). Now you know what is happening behind that one line of code.
A voltage comes in. The ADC divides it into 1024 steps. You get a number. That number represents something real — a knob position, a light level, a temperature.
And now you also know how to convert that number back into an actual voltage — which opens the door to building real measurement tools with your NanoMake Pro.
Keep experimenting, keep building, and keep making.
