My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
SecretVoltmeter  
Accessing the secret voltmeter on the Arduino 168 or 328
Featured
Updated Aug 2, 2009 by cathed...@gmail.com

Introduction

It turns out the Arduino 168 and 328 can measure their own voltage rail.

Code

Copy, paste into Arduino and see what it returns. This works on an Arduino 168 or 328.

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println( readVcc(), DEC );
  delay(1000);
}

The voltage is returned in millivolts. So 5000 is 5V, 3300 is 3.3V.

Note the following:

  • This works on Arduinos with a 328 or 168 only. It looks like the same trick might be possible on the Arduino Mega - experiments are ongoing, and will be reported here.

How it works

The Arduino 328 and 168 have a built in precision voltage reference of 1.1V. This is used sometimes for precision measurement, although for Arduino it usually makes more sense to measure against Vcc, the positive power rail.

The chip has an internal switch that selects which pin the analogue to digital converter reads. That switch has a few leftover connections, so the chip designers wired them up to useful signals. One of those signals is that 1.1V reference.

So if you measure how large the known 1.1V reference is in comparison to Vcc, you can back-calculate what Vcc is with a little algebra. That is how this works.

See also

The SecretThermometer in the Arduino 328

Comment by bla...@bravo5.org, Nov 4, 2009

Isn't this comparing the 1.1V analog reference voltage to what's connected to AVcc? So you're only measuring Vcc if it's tied to AVcc, correct?

Comment by project member cathed...@gmail.com, Nov 4, 2009

@blalor Yes. AVcc is connected to Vcc on Arduinos. The processor spec sheet says AVcc must be within 300mV of Vcc at all times, so I can't see any circuit scenario where it wouldn't be near identical to Vcc.

Comment by bla...@bravo5.org, Nov 5, 2009

Man, I'm really on a roll, eh? :-( I got ARef and AVcc confused. I don't understand why you'd need a separate voltage source for the ADC, but I do see that note and get the difference, now. Sorry for the noise…

Comment by project member cathed...@gmail.com, Nov 5, 2009

@blalor No problem. AVcc is separate from Vcc so you can add power supply filters to keep the digital noise away, or even use separate voltage regulators. But the interface between analog and digital sections breaks down unless you keep the voltages close.

Comment by dida...@gmail.com, Nov 22, 2009

Not having much progress with an Arduino Mega. It's spitting out ~1101 (1.101 volts), while displaying negative results every now and then.

Comment by project member cathed...@gmail.com, Nov 22, 2009

@didanix "This works on Arduinos with a 328 or 168 only."

Comment by davidk...@gmail.com, May 17, 2010

Thanks. Just found this through a link on the arduino forum: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1263440087

Very useful. I can confirm that it works on a ATMega328P-PU (arduino duemilanove).

:)

Comment by bla...@bravo5.org, May 28, 2010

Looking through the datasheet, it should be possible to measure ARef by setting

ADMUX =  _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

(ie. leaving REFS1 and REFS0 at 0). Is that correct? Instead of selecting AVcc I'd be selecting ARef. Both against Vbg. Or is there a danger there with switching the voltage reference with something attached to ARef?

Comment by project member cathed...@gmail.com, May 28, 2010

@blalor Sounds fine to me. Aref could then potentially be used as an extra analogue input by that method. (It can also be used as a digital output - but not a very good one). Try it out!

Comment by nasuka...@gmail.com, Aug 13, 2010

Hmmm.... great work! Can't you use this to obviate the need for any external reference voltage whatsoever?

If you know the precise Vcc then you can just use it as the ARef, even if you don't have a regulated power supply (aka just running it off AAs).

This is great for my little thermometer project, thanks!

robokaren

Comment by nat...@chantrell.net, Feb 19, 2012

Can confirm that this also works on the ATtiny84 (using the arduino-tiny core) if you change the registers to:

ADMUX = BV(MUX5) | BV(MUX0);

Nathan.

Comment by ddmi...@gmail.com, Apr 5, 2012

Is it possible to adapt the code for an ATmega32U4 based board? Did someone make it? What are the necessary changes? Thank you in advance for any advice on this isuue. Dimitar

Comment by ddmi...@gmail.com, Apr 8, 2012

Using trial and error approach, I found (I think so...) that it works on ATmega32U4 too and answered my own question. I used the following line:

ADMUX = BV(REFS0) | BV(MUX2);

And it seems that if you use:

ADMUX = BV(REFS0) | BV(MUX1);

you can measure the 1.1V line inside ATmega32U4. Is that correct? I experimented with my Olimexino-32U4, which is an Arduino Leonardo compatible board and posted the adapted code on my blog page: http://open-dc-ups-monitor.blogspot.com/ Best wishes, Dimitar


Sign in to add a comment
Powered by Google Project Hosting