# Arduino Digital Voltmeter 0V to 30V

Here is a useful circuit for Arduino lovers and experimenters. It is a simple digital voltmeter, which can safely measure input dc voltages in 0 to 30V range. The Arduino board can be powered from a standard 9V battery pack, as usual.

As you may well know, Arduino’s analog inputs can be used to measure DC voltage between 0 and 5V (when using the standard 5V analog reference voltage) and this range can be increased by using two resistors to create a voltage divider. The voltage divider decreases the voltage being measured to within the range of the Arduino analog inputs. Code in the Arduino sketch is then used to compute the actual voltage being measured.

The analog sensor on the Arduino board senses the voltage on the analog pin and converts it into a digital format that can be processed by the microcontroller. Here, we are feeding the input voltage to the analog pin (A0) using a simple voltage divider circuit comprising resistors R1 (100K) and R2 (10K). With the values used in the voltage divider it is possible to feed voltage from 0V to 55V into the Arduino board. The junction on the voltage divider network connected to the the Arduino analog pin is equivalent to the input voltage divided by 11, so 55V ÷ 11 = 5V. In other words, when measuring 55V, the Arduino analog pin will be at its maximum voltage of 5V. So, in practice, it is better to label this voltmeter as “0-30V DVM” to add a safety margin!

Notes

• If the display reading didn’t match when comparing with your lab DVM, use a precision DMM to find the actual resistance of R1 and R2, and replace R1=100000.0 and R2=10000.0 in the code with that values. Next check the 5V supply with the lab DVM at GND and 5V pins on the Arduino board. It might give you less (for instance 4.95V), replace the value into the code vout = (value * 5.0) / 1024.0 (ie replace the 5.0 value to the actual V reading, in this case 4.95V). Further,always try to use precision 1% tolerance resistors for R1 and R2.
• The resistor values (R1&R2) in the circuit diagram provide some over-voltage protection then measuring low voltages. Keep it in mind that any input voltage higher than about 55V could fry the Arduino. No other protection (for voltage spikes, reverse voltages or higher voltages) is incorporated in this circuit!

Arduino Digital Voltmeter Sketch

```/*
DC Voltmeter
An Arduino DVM based on voltage divider concept
T.K.Hareendran
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K) -see text!
float R2 = 10000.0; // resistance of R2 (10K) - see text!
int value = 0;
void setup(){
lcd.begin(16, 2);
lcd.print("DC VOLTMETER");
}
void loop(){
vout = (value * 5.0) / 1024.0; // see text
vin = vout / (R2/(R1+R2));
if (vin<0.09) {
vin=0.0;//statement to quash undesired reading !
}
lcd.setCursor(0, 1);
lcd.print("INPUT V= ");
lcd.print(vin);
delay(500);
}
```

## Schematic of the Arduino DVM Circuit

Parts

• Arduino Uno Board
• 100K Resistor
• 10K Resistor
• 100R Resistor
• 10K Preset Pot
• 16×2 Parallel LCD ( Hitachi HD44780 driver compatible)

• coltoncub3d

Sorry if the answer to this question is completely obvious, I am new to arduino and coding in general. So, the equation used to “decode” the input voltage to the A0 port on the arduino results in 0.0959 (about) from running it through a calculator with value = 1.8v (from 12v source) and R1 + R2 at the default values. Now, being that I don’t plan to use this code hooked up to an LCD display, I can’t really test this code for myself (though I assume it would work as advertised), though if it’s outputting variable vin, I would assume it would display “Input V = 0.0959.” How does it convert that number to the input voltage as shown in the pictures instead of the above value?

The reason I ask this is because I would like vin to equal the output voltage after the calculations as I plan to break the given number into 3 separate digits (using modulo). Would just multiplying the value variable by about 6.67 work instead, as this would essentially equal the input variable? (6.67 because the input to the A0 port = 1.8v, which 1.8*6.67 = the initial input voltage of 12)

• hemanth7787

Precision voltage measuremt is still an issue if we dont have a precise voltage reference
http://www.skillbank.co.uk/arduino/measure.htm

• goran-gustafssongmail-com

An extension of this project would be to divide the measuring range into smaller segments to better use the resolution in Arduino ADC. One can use a number of FET switches to automatically connect different resistances in the voltage divider. Starting with the largest area, eg 0-30 V. If this shows a very low measured value indicating, for example a voltage <3V, you can activate a smaller resistance in the voltage divider. The FET switches are controlled by Arduino's digital I / O pins.

• TCPMeta

Here is the modified code for the Voltmeter to give your project a nice analog retro feel. I used the TVoutBeta1 library. All you need is are two resistors for the video and sync. I used 1K and 470ohm resistors like what the library examples on.

/*
DC Voltmeter
An Arduino DVM based on voltage divider concept
T.K.Hareendran
TVout port code by TCPMeta
Use a 1K resistor on pin 7
Use a 470 ohm resistor on Pin 9
Just follow the typical pinout for the TVout Library found everwhere on the net.
*/
#include
#include

TVout TV;
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K) -see text!
float R2 = 10000.0; // resistance of R2 (10K) – see text!
int value = 0;
void setup(){
TV.begin(NTSC,120,96);
TV.select_font(font6x8);
TV.println(“//////////////////”);
TV.println(“// DC VOLTMETER //”);
TV.println(“//////////////////”);
}
void loop(){
vout = (value * 5.0) / 1024.0; // see text
vin = vout / (R2/(R1+R2));
if (vin<0.09) {
vin=0.0;//statement to quash undesired reading !
}
TV.select_font(font8x8);
TV.print(9,40,"Volts=");
TV.println(vin);
TV.select_font(font4x6);
TV.println(9,85,"TVOut Port By TCPMeta");
delay(500);
}

• TCPMeta

Since I live in the USA we only have NTSC. However from what I can tell if I put the TVout demos of the NTSC and PAL together side by side it’s pretty much the same. Just switch out the NTSC to PAL.
TV.begin(PAL,120.96);

Looking at what I posted it seems the include section of the code got screwed up. Need to add the TVout.h and fontALL.h

I posted this over at my blog. https://tcpmeta.wordpress.com/2016/07/26/quick-and-easy-voltmeter-with-a-arduino-and-a-tv/

• T.K.Hareendran

Nice, I just saved this code, and will try it out when I’ve spare time. Although my test tv have PAL/NTSC auto detection feature, hope you may come up with a tweak (TV.begin(NTSC,120,96);) for PAL televisions. I regret, I don’t have rich experience with the TVout library!

• TCPMeta

I modified the code to use the TVOut library since I don’t have a extra Liquid Crystal Display handy. Kinda tempted just for giggles to go buy one of those small portable B&W TVs from goodwill and slap the Arduino in it for a retro looking bench voltmeter.

• TCPMeta

I’ll pull it out this Tuesday. Trying to remember what system I saved the sketched to.
I was wondering if this could be modified even further to show a peek to peek voltage and maybe add a LM8118 into the mix to add a overlay to a analog O-Scope to give the O-scope a digital like readout of the peek to peek voltage of a wave form.

• T.K.Hareendran

Thanks! I’m glad you’re finding it useful,and really impressed by your idea. If possible,share the code here for the benefit of other visitors.

• cmdgr

Great job! I am facing a great problem, so any advice or answer is needed. My project is almost identical with this one, however I need my results to be shown on the serial monitor. And if is it possible to have two voltmeter on one Arduino. I failed to have my results on the serial monitor and that’s the most important for me. Please anyone who has an idea answer me!!!!!

• Mike Dodd

secondcitysaintsamigmail,

I don’t think that this is a 328 offset issue. I’m wondering if you have ripple on your power supply that’s confusing the ADC and the sample/hold circuitry inside the 328.

What’s the reading with the input tied to ground (i.e. 0V) If that’s 0, or as close as makes no difference, then it’s not an offset.

What’s the reading with a new(ish) 9V battery connected to the input? Let’s take the power source out of the equation as a currently unknown (to me, at least) entity.

Alternative, you can connect the +5V supply on the Arduino to the input/R1 – you should get a value of 5/(25+5) = 1/6th of 5V, or 0.83V.

Do you have a DMM to verify the input voltage to the analogue inputs to the Uno?

• secondcitysaintsamigmail-com

I’m sorry. I should have explained my problem in details.

I am trying to make my Arduino to work as an online multimeter. At the beginning, I’m trying to make it a voltmeter.

I’ve done exactly the same as the tutorial, with three exceptions:

1) I’m not using an LCD monitor.

2) I’m using R1 = 25 kilo-ohms and R2 = 5 kilo-ohms.

3) I’m trying to make it an online voltmeter, so there is an Ethernet shield attached to it.

The problem is, whenever I’m giving about 3-4 volts DC input to the circuit, I’m watching on the serial monitor that the Arduino has measured 10-11 volts! When the input voltage is 10-11 volts, the serial monitor shows 16-17 volts. Whenever I give the maximum input of 27 volts (my power source is old, so does not reach the 30 volts maximum), the serial monitor is showing 28 volts!

So, I think that there is an offset in the ATmega328 which I need to remove.

• Mike Dodd

The Ardunio ground should be tied to the analogue ground of the circuit under test. If it is, then you shouldn’t have any significant offset.

Your question, related to 10k is a bit ambiguous, I’m assuming you’ve got a 10k potentiometer between AREF and GND, with the wiper connected to an analogue input?, if so, then measure with an accurate meter the wiper voltage – you might well find that it doesn’t sweep completely between GND and AREF (most pots should do – a few specialist ones won’t) – just make sure you’re not chasing a ghost. But, if the wiper hits 0V, and the analogue ground is connected to Arduino GND, then you should be able to read 0 (+/- a couple of bits).

“exact voltage”. Define exact?, lets save +/-1 lsb at 5VDC nominal AREF, then with 10 bit ADC that’s +/- 5/1024 or around +/-5mV resolution / accuracy – that’s the limit you can expect, but parasitic effects on the circuitry will degrade that. you should expect to get within +/-20mV with no difficulty.

If you have an offset voltage (resulting in an offset reading) then you could simply remove the Arduino ADC reading at “0” position, from the actual reading – that would remove the offset in software.

• secondcitysaintsamigmail-com

Hello.

Thanks a lot for this useful post.

I have one question.

When 0 volt is applied on an analog pin of Arduino, still we get a value.

For this, I can’t get the exact voltage across 10K resistance.

What is the technique to remove this offset voltage?

Any help would really be highly appreciated.

Looking for the latest from TI?