Stuck with only one multimeter/voltmeter ? But, sometimes you need to check 2 or 3 voltages as the same time. Then this is something you might consider making, a real DC voltmeter !

Designed with commonly available components and easy to understand code, can measure both positive and negative voltages simultaneously on 3 nodes in a single circuit or 3 separate circuits.


Measuring voltages across resistor and battery on 2 different circuits


Following hardware are used to build this device:-



Working Principle: AFE Explained

Normally, ATmega328P (Arduino Uno) can measure voltages between Gnd and AVCC range (i.e. 0 to 5V) without any voltage divider resistors network. If internal AREF is enable, it can measure voltages between Gnd and AREF range (i.e. 0 to 1.1 V). With some voltage divider, it is possible to measure higher voltages than 5V. These are all positive voltages with respect to Gnd.

But it can not measure any voltages below Gnd, meaning it can't measure negative voltages. The problem is that, ATmega328P has a single ended ADC, which by default makes measurement with respect to Gnd.

The solution is, don't make measurement with respect to Gnd anymore.

Real voltmeters have COM (Black) and V(Red) terminals, you connect COM to one node, V to another node on a circuit. The voltage reads on V node with respect to COM node.

You need to build an (AFE) Analog Front End, some sort of signal conditioning circuit to generate a COM like behavior. This COM node should have a voltage somewhere in between AVCC and Gnd. Ideally, half AVCC volts but for this design it's half AREF.

When external voltage measurements are taken with respect to COM, you can easily measure both positive and negative voltages !

Please check the following circuit carefully :

Differential measurement with 2 single ended ADC channels

Differential measurement with 2 single ended ADC channels

So, what's happening here ? Internal reference AREF is enabled on ATmega328P (from firmware/code in void setup). AREF pin has 1.1 V. Now, ADC measurement has an effective range of 0 to 1.1 volts.

Next, using a LM324 Opamp this 1.1 AREF voltage is buffered, meaning we still have 1.1 voltage from the first Opamp's output. A 10k multiturn trim pot is set exactly to 5k to produce 550mV (half AREF) volts. This 550 mV signal is buffered with the second Opamp. 550 mV signal is also connected to ADC Ch - 0. It should read 512 (half of 10 bit).

There is a voltage divider network consist of 5 Mega Ohms (two 10M in parallel) and 100 Kilo Ohms resistor, which is connected to the output of second Opamp.

I am defining, lower resistor end (100k) as COM and higher resistor (5M) end as V on this voltage divider network. The mid point of this divider is connected to ADC Ch - 1. When no external voltage is applied to this divider, ADC Ch - 1 should read 512 (because of 550 mV)

When an external voltage is applied, the voltage divider mid point voltage will shift above or below 550 mV. If external voltage on V is higher (positive voltage) with respect to COM, it will shift above 550 mV, If external voltage on V is lower (negative voltage) with respect to COM, it will shift below 550 mV. The ADC Ch - 1 reading will change accordingly. Using this change in ADC reading we can calculate external voltages.

Why use AREF instead of AVCC ?

This design is LiPo battery powered, a full charge LiPo will start from 4.2 Volts and gradually the voltage will drop. So, AVCC will also change. But internal reference AREF has constant 1.1 Volts. That's why I chose AREF.

If other microcontrollers are used, which do not have AREF, you can use TL431 IC to generate reference voltage !

Why use LM324 Opamp ?

LM324 IC has 4 Opamps in a single package, widely available and it's output can go (very close) to Gnd. It also works with any supply voltage between 3 to 32 volts.

You can always use better Opamps (Precision, Low Noise, Rail-to-Rail)

Voltage Calculation Formula

Measured voltage with ADC will be a tiny fraction of actual voltage applied. That's why following formula is used inside the firmware to calculate back the actual voltage:-



Voltage Divider Resistor: Range vs Resolution

+/- V = (R_High / R_Low) / 2

V < sqrt ((R_High + R_Low) * P)

R_High + R_Low > hundreds of kOhms to few MOhms

For this project, this voltmeter can measure +/- 25 volts with R_High = 5M (or 5000k) and R_Low = 100K with 1/10 watt rating, which satisfy above 3 conditions

Measurement Resolution = Measurement Range / ADC Resolution

Example : Suppose a fresh AA battery reads 1.627 volts with a Fluke voltmeter, but this voltmeter may read only 1.5 or 1.6 or 1.7 volts

Accuracy : How Hardware & Software Design Helps

Accuracy depends on many things. Some of the following tips are implemented in this project.

Implementing following action in firmware will improve accuracy :-

Although the AREF pin of Arduino UNO or Atmega328P can be set to 1.1 volts with following code


The actual AREF voltage may vary between 1.06 volts to 1.13 volts from chip to chip. It is recommended to measure AREF pin with a high accuracy multimeter and find the actual voltage. Then define that in code for better accuracy

#define AREF 1.097            // Aref pin voltage

Don't just copy paste 1.1 volt !

Input Protection: Safety Matters !

This is the bi-directional diode clamping for over voltage or surge protection you may use in parallel to R_Low. I left this part in my build due to lack of space !

Bi-directional voltage clamp

Bi-directional voltage clamp

Safety should never be taken lightly ! These diodes will start to clamp when the voltage across R_Low exceeds +/- 800 mV. This is just an example, use different diode types for a suitable clamping voltage as needed.

Programming & Soldering

Download IDE

Download IDE

Installing u8g library

Installing u8g library

install the u8glib (by Oliver) library for 1306 OLED display.

Remove Atmega328 after uploading code

Remove Atmega328 after uploading code

Voltmeter Schematic

1 / 3 • Voltmeter Schematic

Performing Voltage Calibration & Measurements


For best results, you need to calibrate this voltmeter with a regular multimeter/voltmeter. You will need any battery AA or LiPo. Measure the voltage of the battery with regular meter. Then measure that battery with this voltmeter. See some discrepancy in reading, now slightly trim/adjust the 10K pot (see schematic) to calibrate.

Do the same procedure by reversing the battery for negative voltage.

You can also do soft-calibration from code by adding/subtracting some offset value with the resistors defined values.


There are 3 Commons COM1, COM2, COM3 and 3 corresponding V1, V2, V3 probes for voltage measurement on 3 different channels.

For channel 1, voltage is measures on V1 with respect to COM1. If a circuit node probed with V1 has higher potential than a node probed with COM1, voltage reading will be positive. If both V1 and COM1 are swapped on those two circuit nodes, voltage reading will be negative.

Same goes for channel 2 with V2 & COM2 and for channel 3 with V3 & COM3.

When measuring three different voltages on 3 different circuits which don't share any electrical connections, use V1/COM1, V2/COM2, V3/COM3 pairs for 3 circuits.

3 different voltage measurements on 3 different circuits

3 different voltage measurements on 3 different circuits

When measuring three different voltages on a single circuit, DO NOT USE multiple COMs. Just connect ONLY ONE COM (for example just COM3, any COM will do !) to the Gnd or any node of that circuit. Then use V1, V2, V3 to measure 3 different voltages on 3 different nodes with respect to the Gnd or node where COM is connected.

3 different voltage measurements on single circuit

3 different voltage measurements on single circuit

Connecting multiple COMs on same circuit will screw up readings !

Conclusion & Future Works

I forgot to add something important, showing OL (Over Load) when voltage range exceeds measurement range. Hopefully, I will update the code with extra features.

Some voltage logging on the internal EEPROM could be handy, I will try to do that too. I want to add couple of buttons for REL (zeroing ghost voltage) and HOLD (freezing screen). I have already soldered a female header on the top for future extensions, stay tuned.

This design can be used to measure slow changing AC voltages/signals (assuming sinusoidal) without any change in hardware. It can also be used to design Shunt Ammeter (hint: replace voltage divider with very low value R). But you need to write a different code for that.

This concept will work with any microcontroller, feel free to build your own design and good luck.



ver 1.01