Measuring voltage accurately is one of the most fundamental tasks in electronics. Whether you’re debugging a circuit, monitoring a battery bank, or building a bench power supply, a reliable digital voltmeter is indispensable. In this project, we’ll build a DIY digital voltmeter using Arduino Nano and a 0.96″ OLED display that can measure DC voltages from 0 to 25V with high precision — all for under ₹300 in components.
This project is beginner-friendly, requires no PCB etching, and teaches you key concepts including analog-to-digital conversion, voltage dividers, and I2C communication with OLED screens.
Why Build Your Own Voltmeter?
Commercial multimeters are widely available, but building your own Arduino-based voltmeter offers several advantages that go beyond simple measurement:
- Custom display and logging: Display voltage in large fonts, change units, add min/max tracking, or even log data over serial/Bluetooth.
- Integration into projects: Embed the voltmeter directly into a battery charger, solar controller, or power supply.
- Learning experience: Understand the ADC limitations of the Arduino, voltage divider math, and I2C protocol in practice.
- Cost: A DIY unit costs ₹200–₹400 and can be made permanent for a specific voltage range, unlike a general multimeter.
The Arduino Nano’s ATmega328P has a 10-bit ADC with a 1.1V internal reference or 5V default reference. We’ll use the 5V reference with a resistor voltage divider to safely measure up to 25V DC.
Components Required
Here is everything you need to build the digital voltmeter:
| Component | Specification | Qty |
|---|---|---|
| Arduino Nano | ATmega328P, 5V logic | 1 |
| OLED Display | 0.96″ 128×64 I2C SSD1306 | 1 |
| Resistor R1 | 30kΩ (or 2×15kΩ in series) | 1 |
| Resistor R2 | 7.5kΩ | 1 |
| Breadboard | 400-tie or 830-tie | 1 |
| Jumper Wires | M-M and M-F | 10–15 |
| USB Mini Cable | For programming Nano | 1 |
Circuit Design & Voltage Divider Theory
The Arduino Nano’s analog input pin (A0) can safely handle a maximum of 5V. To measure voltages higher than 5V, we use a resistor voltage divider to scale down the input voltage proportionally.
The voltage divider formula is:
Vout = Vin × (R2 / (R1 + R2))
For our values (R1 = 30kΩ, R2 = 7.5kΩ):
Vout = Vin × (7500 / (30000 + 7500)) Vout = Vin × 0.2 At Vin = 25V: Vout = 25 × 0.2 = 5V ✓ (safe for Arduino)
So the maximum measurable voltage is 25V DC. In the Arduino code, we reverse this scaling factor to display the actual input voltage.
Important safety note: This circuit is designed for DC voltage measurement only. Never connect AC mains voltage to an Arduino analog pin under any circumstances. Always add a 100Ω series resistor between the voltage divider output and the A0 pin as extra protection against voltage spikes.
Wiring the Arduino Nano & OLED
Follow these connections carefully:
Voltage Divider to Arduino Nano:
- Vin (+) → one end of R1 (30kΩ)
- Junction of R1 and R2 → Arduino A0 pin
- Other end of R2 → Arduino GND
- Vin (–) → Arduino GND
OLED Display (I2C) to Arduino Nano:
- OLED VCC → Arduino 3.3V (most SSD1306 OLEDs accept both 3.3V and 5V)
- OLED GND → Arduino GND
- OLED SDA → Arduino A4
- OLED SCL → Arduino A5
Double-check polarity before applying any test voltage. A reverse polarity at the input will damage the Arduino’s ADC immediately.
Arduino Code Explained
Install the following libraries from the Arduino Library Manager before uploading:
- Adafruit SSD1306 — OLED driver
- Adafruit GFX — Graphics library
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int analogPin = A0;
const float calibrationFactor = 5.0 / 1023.0; // Vref / ADC steps
const float voltageDividerRatio = (30000.0 + 7500.0) / 7500.0; // = 5.0
float samples[10];
int sampleIndex = 0;
void setup() {
Serial.begin(9600);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 24);
display.setTextSize(2);
display.print("Voltmeter");
display.display();
delay(2000);
}
void loop() {
// Take 10 samples and average for stability
float rawADC = 0;
for (int i = 0; i < 10; i++) {
rawADC += analogRead(analogPin);
delay(5);
}
rawADC /= 10.0;
float measuredVoltage = rawADC * calibrationFactor * voltageDividerRatio;
// Display on OLED
display.clearDisplay();
display.setTextSize(1);
display.setCursor(15, 5);
display.print("DC Voltmeter");
display.drawLine(0, 15, 127, 15, SSD1306_WHITE);
display.setTextSize(3);
display.setCursor(10, 25);
display.print(measuredVoltage, 2);
display.print(" V");
// Bar indicator
int barWidth = (int)((measuredVoltage / 25.0) * 118);
display.drawRect(5, 54, 118, 8, SSD1306_WHITE);
display.fillRect(5, 54, barWidth, 8, SSD1306_WHITE);
display.display();
Serial.print("Voltage: ");
Serial.print(measuredVoltage, 3);
Serial.println(" V");
delay(200);
}
Key code concepts explained:
- 10-sample averaging: Reduces ADC noise and gives a more stable reading, especially important for low voltages.
- calibrationFactor: Converts the 10-bit ADC value (0–1023) to actual voltage at the pin (0–5V).
- voltageDividerRatio: Multiplies the pin voltage back to the original input voltage.
- Bar indicator: A visual graphical bar shows percentage of max range at a glance.
- Serial output: Allows you to log readings on your PC using the Serial Monitor or Serial Plotter.
Calibration & Accuracy Tips
A raw Arduino Nano voltmeter will typically have an error of ±2–5%. Follow these steps to improve accuracy significantly:
- Measure the actual Vref: Use a trusted multimeter to measure the exact voltage on the Nano’s 5V pin. Replace
5.0in thecalibrationFactorwith this actual value (e.g., 4.97). - Use 1% tolerance resistors: Standard 5% resistors can introduce significant divider error. Use metal film 1% resistors for R1 and R2, or measure actual resistance with a meter.
- Adjust the ratio in code: If your meter reads 12.0V on a known 12V source but your project shows 12.35V, calculate the correction factor:
12.0 / 12.35 = 0.972, then multiply your output by this factor. - Use the internal 1.1V reference: For measuring small voltages (0–5V range), use
analogReference(INTERNAL)for much higher resolution. Adjust the voltage divider ratio accordingly. - Decouple the ADC: Add a 100nF ceramic capacitor between A0 and GND right at the Arduino pin to filter high-frequency noise.
Project Upgrades & Ideas
Once your basic voltmeter is working, here are exciting ways to extend it:
1. Dual-channel voltmeter
Use A0 and A1 with two independent voltage dividers. Display both readings simultaneously on the OLED — ideal for comparing battery cells or monitoring dual-rail power supplies.
2. Min/Max tracking
Add variables to track the minimum and maximum voltage seen during a session. Display them below the main reading to catch transient spikes.
3. Battery percentage indicator
For Li-ion (4.2V full, 3.0V empty) or lead-acid batteries (12.7V full, 11.8V empty), map voltage to a percentage and show a battery icon on the OLED.
4. Bluetooth/WiFi logging
Add an HC-05 Bluetooth module or upgrade to the Nano 33 IoT for wireless data logging. Stream readings to a smartphone app or an online dashboard like ThingSpeak or Grafana.
5. Over-voltage alarm
Connect a buzzer to pin D8. If the measured voltage exceeds a threshold (e.g., 14.5V for a 12V lead-acid battery charger), sound an audible alert.
6. AC voltage measurement
For AC voltage measurement, use a dedicated AC-DC converter module (like ZMPT101B) to safely isolate the mains and provide a scaled DC signal to the Arduino. Never connect AC directly.
Frequently Asked Questions
Can I measure negative voltages with this circuit?
Not with this basic design. To measure negative DC voltages, you need a level-shifting circuit that adds an offset to bring the signal into the 0–5V range readable by the ADC. A simple op-amp bias circuit using a TL081 or MCP6001 can accomplish this. Alternatively, use an ADS1115 I2C ADC module which supports differential inputs and can measure negative voltages directly.
Why is my voltage reading fluctuating?
ADC noise is the most common cause. Add a 100nF ceramic capacitor between A0 and GND. Increase the number of samples in the averaging loop (try 20–50 samples). Also ensure your power supply is clean — a USB port with poor regulation can inject noise into the 5V reference line. Consider using the internal 1.1V reference for more stable readings on lower voltages.
What is the maximum voltage this circuit can safely measure?
With R1 = 30kΩ and R2 = 7.5kΩ, the maximum input voltage is 25V DC. Never exceed this. For higher voltages (e.g., 48V solar systems), recalculate the divider: to measure up to 50V, use R1 = 200kΩ and R2 = 10kΩ (ratio of 21:1, but verify the output stays under 5V at max input).
Can I use Arduino Uno instead of Nano?
Yes, absolutely. The circuit and code are 100% compatible with the Arduino Uno. The Nano is preferred for compact builds, but the Uno has the same ATmega328P chip, same 10-bit ADC, and the same pin assignments (A0, A4, A5). If you use the Uno, you can also add the TFT display shield directly.
How do I power the voltmeter independently (without a PC)?
Power the Arduino Nano via its VIN pin (6–12V DC) or its USB connector using a phone charger or power bank. A 9V battery with a DC barrel connector works well for a portable voltmeter. The entire circuit draws less than 30mA, so a 9V alkaline battery will run it for several hours.
Ready to build your Arduino voltmeter? Get all the components you need — Arduino Nano boards, OLED displays, resistors, and breadboards — from Zbotic’s Arduino & Microcontrollers store. Fast shipping across India with genuine components at competitive prices.
Add comment