Voltage metering circuit (with AVR)

No this is not a DIY multimeter... sorry fellows! :) But in a way it's much more useful for the electronic interventionist. This is a small circuit that allows you to measure any input voltage with an ATmega168 (although it can be adapted to any microcontroller that has analog inputs and a reference voltage).

It uses a simple resistor bridge to bring the input voltage between 0 and 1.1V (the reference voltage on the ATmega168).

The code of the VoltageMeter class is provided in attachment to this post.

Note: If you want to measure the voltage from the ATmega168 itself (ie. AVcc) you can use the following code instead (no need to build a circuit).

Circuit schematics

             R1             R2
   GND ----/\/\/\----*----/\/\/\---- Vin
                     | Vout
                ANALOG PIN
  • Vin : input voltage (the voltage we try to meter)
  • Vmax : the maximum value of the input voltage
  • Vout : the output voltage (the Vin remapped to 0 .. 1.1V)

Choose R1 and R2 CAREFULLY according to the following rule:

R1 = R2 x 1.1 / (Vmax - 1.1)
R2 = R1 x (Vmax - 1.1) / 1.1

A typical configuration is R1 = 1k and R2 = 4k. It assumes Vmax = 5.5V.

Important considerations

  1. It is recommended to test the circuit before, especially if Vmax > 6V, to make sure the voltage at the analog pin (Vout) does not get over 5V.
  2. '''You should not connect any external voltage source to the AREF pin''' since this system relies on the internal reference. Doing so might result in a short circuit.
  3. ATmega168 datasheet has the following notice "Note that VREF is a high impedance source, and only a capacitive load should be connected in a system." According to one of our readers (many thanks to Peter) "what it means is that when VREF is used as an output, you may not draw current from it. You may connect a capacitor to it to eliminate any ripple that might be caused by noise on adjacent circuits."

Example Arduino code

 #include "VoltageMeter.h"

 #define VOLTAGE_AIN 0

 VoltageMeter meter(VOLTAGE_AIN, 5.5);
 void setup() {
 void loop() {
   float voltage = meter.voltage();
   Serial.print((int)(voltage*1000), DEC); Serial.println(" mV");
analog_reference.h2.65 KB
prescaler.h3.34 KB
VoltageMeter.h3.02 KB


Arduino 1.0

Is this compatible with Arduino 1.0.

I get errors when compiling it.


Thanks for your article. I

Thanks for your article. I implemented it using a value of 15 for Vmax and found the following:

Voltage: - at 12V batt terminals: 12.50 - btw GND and Vin 11.94 - as measured by your circuit/code: 10.53

Is this normal?



The resolution of the meter

The resolution of the meter is only 10 bits, but that's not enough to explain such a variation.

Why are you setting Vmax to 15 since your Vmax is 12.50V in reality? Try to set Vmax = 12.50.

Are you running it on a Arduino board or on your own circuit?

Important fix

Klaus Kellermann suggested an important fix in the diagram (the GND and Vin were inverted). Thanks!

is correct now the scheme?

So, the showed diagram is ok now? or it still have inverted the GND and Vin??



Yes the diagram is ok now!

Thanks!! I will try soon!

Thanks!! I will try soon!