Secret Arduino Voltmeter - Measure Battery Voltage
Secret Arduino Voltmeter - Measure Battery Voltage
Tech
Secret Arduino Voltmeter – Measure Battery
Voltage
By SCOTT | Published: JULY 9, 2012
Search
A little known feature of Arduinos and many other
To search, type and hit enter
AVR chips is the ability to measure the internal 1.1
volt reference. This feature can be exploited to
improve the accuracy of the Arduino function – Pages
analogRead() when using the default analog About Us
reference. It can also be used to measure the Vcc Articles
supplied to the AVR chip, which provides a means Checkout
of monitoring battery voltage without using a Contact Us
precious analog pin to do so. Home
Polls Archive
I first learned of this technique from these articles Privacy
– Making accurate ADC readings on the Arduino, Store
and Secret Voltmeter. In this article, I have Store Information
incorporated some additional improvements. Product Liability
Shipping
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both Blogroll
Documentation
long result = (high<<8) | low;
Plugins
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*10 Suggest Ideas
return result; // Vcc in millivolts Support Forum
} Themes
WordPress Blog
WordPress Planet
Usage RSS Links
All posts
Checking Vcc or Battery Voltage All comments
You can call this function – readVcc(), if you want to monitor your Vcc. One
example would be for checking your battery charge level. You could also use it to Meta
determine if you are connected to a power source or running from batteries.
Log in
One of the articles I cited earlier made the claim that this
function could be used to improve the accuracy of the analog
measurement in cases where Vcc wasn’t exactly 5.0 volts.
Unfortunately, this procedure will not provide that result. Why?
It is dependent on the accuracy of the internal voltage
reference. The spec sheet gives a nominal value of 1.1 volts,
but states that it can vary from 1.0 to 1.2 volts. That means that any
measurement of Vcc could be off by as much as 10%. Such a measurement could
be less accurate than our power supply for the Arduino!
Improving Accuracy
While the large tolerance of the internal 1.1 volt reference greatly limits the
accuracy of this measurement, for individual projects we can compensate for
greater accuracy. To do so, simply measure your Vcc with a voltmeter and with our
readVcc() function. Then, replace the constant 1125300L with a new constant:
where
Conclusion
You can do a lot with this little function. You can use a stable voltage reference
close to 5.0 volts without having to rely on your Vcc actually being 5.0 volts. You
can measure your battery voltage or even see if you are running on battery or A/C
power.
Lastly, the code provided will support all the Arduino variants, including the new
Leonardo, as well as the ATtinyX4 and ATtinyX5 series chips.
Save
108 Comments
Patrick Ball
Posted August 5, 2012 at 1:34 pm | Permalink
hey Scott, this is incredibly helpful. I’ve been struggling with measuring
voltage with the Arduino for a while, and I note that different boards and
different batteries lead to really different results on all my analog readings. I
have a few questions:
— As you can tell from the previous question, I don’t follow the code you’ve
posted, though I figure the variables IN CAPS are internal Arduino vars. Is
there a list of those vars you point me to?
— Can you give me a bit more detail on how this would be used to correct
analog references?
thanks! — wylbur.
Scott Daniels
Posted August 13, 2012 at 11:59 pm | Permalink
Yes – the first line of actual code (3 variants) does two things. 1) It sets
the analog ref to Vcc. 2) It sets the measurement to not a pin, but the
internal 1.1v reference. The rest of the code simply makes the analog
measurement (ADC conversion). The first line must come before the
rest. It can of course be changed for subsequent measurements.
As for the constants, those are standard AVR constants (not Arduino, but
more low level). You can peruse the documentation for the AVR LibC
here, or review the Atmel spec sheets.
The whole trick of this code (readVcc) is to figure out the supply voltage
(Vcc) by reading the internal 1.1 volt reference using Vcc as the
reference. With simple math, the real Vcc can then be calculated.
hary
Posted March 9, 2014 at 5:14 pm | Permalink
Hi.
Many thanks for your explanation. Really intersting and well done.
tytower
Posted August 15, 2012 at 11:15 pm | Permalink
Those Arduino boards I have measured give about 4.85 V or thereabouts .Put a
multimeter on the regulator output or stick it across the 5V out pinand ground
pin and use the voltage read in your adc conversion formula directly -accuracy
will be improved. Look at the chips datasheet and most of them have a
tollerance of +/-1 degree when measuring temperature so atm your temp
measurements can be up to 2 degrees out!
Daniel
Posted August 16, 2012 at 12:17 am | Permalink
Hihi,
Would it be possible to read the internal temperature sensor of the Arduino
Leonardo ( 32U4)
in a similar way ?
Scott Daniels
Posted August 17, 2012 at 12:32 am | Permalink
Yes. I haven’t written an article here yet that shows how, but I recently
posted an Instructable with the code to do exactly that, including
support for the 32U4 chip.
retrolefty
Posted August 18, 2012 at 11:05 am | Permalink
goebish
Posted August 16, 2012 at 4:22 am | Permalink
Nice trick, too bad the ATtinyx5 series can’t handle this, I love these small
chips
Scott Daniels
Posted August 17, 2012 at 12:45 am | Permalink
You can – thanks to Doug (below) for pointing that out. I have amended
the code in the article to support the ATtinyx5 series chips as well.
loopingz
Posted August 16, 2012 at 5:17 am | Permalink
Scott Daniels
Posted August 17, 2012 at 12:34 am | Permalink
Vcc ought to still be 5v
Harvey
Posted February 20, 2013 at 3:03 pm | Permalink
dylan
Posted January 16, 2016 at 5:53 pm | Permalink
John Morris
Posted August 28, 2016 at 12:54 am | Permalink
Akhlesh Kumar
Posted February 2, 2017 at 1:03 am | Permalink
Sir
how can I measure the value of zero to 3.3 volts on arduino board
for changing the value zero to FF.
Pl. suggest me.
retrolefty
Posted August 18, 2012 at 11:10 am | Permalink
When powered via USB then Vcc is whatever the PC’s USB voltage is and
can vary from I think 4.5 to 5.5vdc and still be in specification? If
powered via external power then the board’s Vcc will be whatever the
on-board 5 volt regulator voltage is with a similar specification tolerance.
So there is no true 5.00000 board voltage, rather it’s whatever actual
value within normal tolerance specs of whatever voltage source is being
used.
Doug
Posted August 16, 2012 at 8:03 am | Permalink
Maybe I’m missing something, but I don’t see why you can’t use this on an
ATTiny25/45/85.
Scott Daniels
Posted August 17, 2012 at 12:35 am | Permalink
You are absolutely right. I overlooked that entry in the Atmel spec sheet
for that series AVR chip. I will amend the code in the article.
Doug
Posted August 20, 2012 at 7:12 am | Permalink
Scott Daniels
Posted August 28, 2012 at 2:08 am | Permalink
John Honniball
Posted August 16, 2012 at 1:00 pm | Permalink
I used the 1.1V internal reference on an Arduino a few months ago. But I found
out (the hard way) that the tolerance on the 1.1V reference is really poor. It’s
specified to be between 1.0V and 1.2V, or roughly +/- 10%. In my case, this
made the reference useless. I added an external TL431 2.5V reference, with a
tolerance closer to 1%.
Scott Daniels
Posted August 17, 2012 at 12:39 am | Permalink
hary
Posted March 9, 2014 at 5:20 pm | Permalink
You wrote:
“You can even automatically calibrate for each chip automatically
as part of the programming process”
Could you give more details. I’ve no idea you can do this !
Wouldn’t you need to know at least the real and precise value of
the 1.1V reference do achive such a task ?
Vadim Ippolitov
Posted February 13, 2015 at 1:02 pm | Permalink
shiva kumar
Posted March 5, 2017 at 2:11 am | Permalink
This is very cool. After I call your function, should I set the reference back to
default with
analogReference(DEFAULT);
Just so I’m clear, this does not use any of the analog I/O pins, right?
As noted already, the 1.1 voltage reference is not very accurate. Is there a way
to measure that with a voltmeter so I can see what it is for a specific Arduino
device?
retrolefty
Posted August 18, 2012 at 11:18 am | Permalink
The internal 1.1 volt reference voltage does have a pretty wide
specification, however it is pretty stable for any specific chip within the
tolerance range, so the trick is to somehow calculate or measure the
actual 1.1 vdc reference for your chip. If you select the internal 1.1
reference voltage in a sketch, you can actually measure it on the Aref pin
of the chip. Also I have just tweeked the reference voltage in my
calculation until the results of a analog read using a known external test
voltage value agreed with the calculated/corrected value.
PR
Posted August 21, 2012 at 5:55 pm | Permalink
You can measure actual 1,1V reference voltage from Aref pin, after
you have muxed internal 1,1V there. You can connect a small
capacitor there, to make it more stable.
fab
Posted October 20, 2012 at 7:59 am | Permalink
Hi,
Could you please describe how to “mux the 1.1 ref to pin
AREF” ?
And do i need to switch it back after that ?
thks
Scott Daniels
Posted August 28, 2012 at 2:22 am | Permalink
Walt
Posted September 9, 2012 at 1:21 am | Permalink
Will
Posted October 16, 2012 at 2:29 am | Permalink
Occasionally, but not always, the statement “long result = (high<<8) | low;"
returns a zero. Why would this be and what can I do about it? This is a very
cool routine but this behaviour is driving me a little mad!
Thanks, Will
Will
Posted October 18, 2012 at 3:49 am | Permalink
Clarification on the above. This never happens on the first read following
a restart of the controller….so I just make sure I restart the controller
before I get my reading! In any case I have taken what I think I learned
from this post and applied it to my project. I then documented what I
did here. It should be noted that I am a software guy and this hardware
stuff confuses me! I get the answer that I want (e.g. a voltage reading
that matches my meter) but I am not sure I have done so in the ‘right’
manner.
Scott Daniels
Posted October 24, 2012 at 1:22 pm | Permalink
I am not sure why that is happening. I took the analog read code
straight from the Arduino library. Are both high & low zero as well
(should be obvious, but you never know)? Try adding a short delay
before reading the register values for high & low.
Seeing that it works the first time and then not afterward, check to make
sure the ADLAR bit is not being set somehow in the ADMUX register –
that could cause the data to be left shifted and possible read as zero.
A last thing to try is to check to make sure the ADIF bit is set in register
ADCSRA before reading the data registers. You may want to study up the
Analog to Digital Conversion in the datasheet if all this fails.
If you find the problem, please post the result. Good luck!
Will
Posted October 24, 2012 at 3:12 pm | Permalink
Scott:
Cheers,
Will
Martin
Posted October 23, 2012 at 11:55 am | Permalink
Thanks for posting the code with explanation! It was exactly what I was
looking for. I would like to be able to monitor how much life the battery has
left. I’m a total newbie when it comes to electronics and the Arduino so please
excuse if my question is a little naive: After uploading the sketch to my Uno
Rev 3 which was connected to my computer via USB and running from a 9V
battery (I connected the battery via VIN and GND) I checked the Serial output
and it reads a consistent 4855. I was assuming that it would read somewhere
between 8000 and 9000 since I was connected via a new 9V battery. Since the
Arduino uses 5V will it always read around 4855 until the battery is drained
and dips below that value?
Thanks in advance for your help.
Scott Daniels
Posted October 24, 2012 at 1:28 pm | Permalink
That is pretty close. What the function does is measure the voltage
supplied to the ATmega chip itself. The Uno has a 5 volt regulator which
provides the 4.855 volts your are reading (the actual voltage is probably
closer to 5 volts, but that is a limitation on the internal ref’s accuracy).
The regulator probably has around 1.2 to 2 volts of dropout, so the
voltage you read will stay the same until your power source drops to less
than 6 to 7 volts.
If you want to monitor your battery voltage before the regulator, you will
have to use an analog pin to do so. For monitoring battery voltage, this
function will only work when powering the IC directly and not using a
voltage regulator. Make sense?
Martin
Posted October 25, 2012 at 1:03 pm | Permalink
Hi Scott,
Best regards,
Martin.
Will
Posted October 24, 2012 at 3:11 pm | Permalink
Martin:
I think you also need to have a voltage divider to take the 9v to under
5v for the arduino to be able to read it. In my post right above yours
there is a link to what I have done that may help. I am a complete
hardware novice as well……..
Cheers, Will
Martin
Posted October 25, 2012 at 1:03 pm | Permalink
Ace
Posted November 27, 2012 at 6:41 pm | Permalink
Kind Thanks
Scott Daniels
Posted December 6, 2012 at 11:04 am | Permalink
atflaryon
Posted December 26, 2012 at 1:00 pm | Permalink
Scott Daniels
Posted December 26, 2012 at 6:19 pm | Permalink
evolion
Posted January 21, 2013 at 4:22 am | Permalink
I don’t quite understand all the info presented here but perhaps I could have
some feedback. Part of the project I have just started on is to measure sensor
input to my vehicle’s computer(PCM). Power to the sensor is +5Vn. If I were to
use the same +5Vn to power the arduino, would that automatically act as a
reference for a fairly accurate reading of the sensor output? or should it also be
input into the AREF to obtain an accuracy of +/- .01V?(is this accuracy even
possible?) I would assume that as long as I read the same value that would
appear in the PCM, it wouldn’t matter that power to the sensor is not exactly
5V.
Thanx
Scott Daniels
Posted January 24, 2013 at 2:47 pm | Permalink
As indicated by this article, the default analogRead uses the AVR’s Vcc
for a voltage reference. The technique given to measure Vcc is
somewhat crude (about 10% accuracy). If you need an absolute
accurate voltage reading (such as the 0.01 volts cited), then you will
need to use a precision voltage reference chip and feed it to AREF. Even
then, that kind of accuracy might be iffy at best. If you meant +/- 0.1
volts, then the precision ref will work.
evolion
Posted January 25, 2013 at 3:54 am | Permalink
Do you think that if I use the sensor input voltage for AREF, I will
still have only 10% accuracy?
Would you have suggestions for a particular reference chip to use
if I need to use one? I didn’t figure it would be a difficult
measurement seeing as how my $5 voltmeter reads to .01V, but
I’m a novice and the arduino experience is very new to me.
Harvey
Posted February 20, 2013 at 3:16 pm | Permalink
Jorge
Posted February 28, 2013 at 9:09 pm | Permalink
Hi,
This is all very helpful, but what if I want to measure the voltage across
another power line? I am working on a project in which I need to continuously
measure the voltage of the line powering the project. I am using regulators to
regulate, but I need a way to read and store that reading for data analysis
after the project. What is the best way I can do that? I’ve been looking around
but I can’t find anything.
Thanks,
Scott Daniels
Posted March 6, 2013 at 11:54 pm | Permalink
You’ll just need to use an analog pin to make the measurement. Use two
resistors to make a voltage divider that drops your maximum line
voltage just under 5 volts (or 1.1 volts if using the internal reference)
and measure your voltage at that point.
Marc
Posted March 12, 2013 at 4:14 pm | Permalink
I would like to change the reference on the Arduino DUO board. The
analogReference(INTERNAL1V1); code returns an error.
Do you think that reference could be changed with lower level code?
Scott Daniels
Posted April 24, 2013 at 12:39 pm | Permalink
I haven’t played with the DUO yet. Look in the spec sheet for the
appropriate analog reference bit to use.
Fx
Posted July 22, 2013 at 9:32 am | Permalink
Hi Marc, did you manage to change de reference on an Arduino due
board?
I’m having the same issue and don’t know how to get a reference
voltage.
Thanks,
britesc
Posted April 6, 2013 at 12:21 pm | Permalink
Hi,
Thank you for this article.
I have a large number of 2VDC 1200Ah Lead Acid Batteries that I use for off-
grid power.
I need to be able to monitor the voltage, amperage and temperature of each
battery. The “device” should be self powering, so I have settled on the
ATTINY43U as this operates from 0.8 to 5.5 VDC and is well within the operable
battery voltage range of 1.57 to 2.85 etc.
Your routine should I believe, give me the first part of the problem, namely the
battery voltage.
Is that correct?
Can the ATTINY43U also provide the amperage?
I also read that it can return the temperature of the chip for reference value.
I intend to use a copper lug with an LM35 inside sealed with hot glue and feed
that output back to the ATTINY43U but that requires 5VDC? So somehow I
need to increase the voltage from the battery to deliver that??
Could you or any of your stalwarts advise me as to whether this is feasible and
help me with a little bit of code / hardware advice to get me going, please?
Thanks and kind regards,
jB
Scott Daniels
Posted April 24, 2013 at 12:38 pm | Permalink
Yes, you can measure the voltage using this technique. You can also
measure the ambient temperature with a similar technique. The latter is
not real precise, but is probably sufficient with your application (you will
have to calibrate the chip however). Alternatively, you can use a
temperature chip as you mentioned, but will need a boost converter to
get 5 volts.
For current, that is not a property of each cell, but the entire battery of
cells. You will want to use another circuit for that. You will need to
measure it using an analog pin and a current sense resistor.
paul
Posted May 5, 2013 at 10:37 am | Permalink
Hi scott
I am using atmega2560 (arduino)
I had added your code for reading chip Vcc using the internal 1.1 vref and its
working great
The problem is that I need to read some value from other analog pin in my
program also
And iam doing it like this:
#define VPowerLeg 8
Serial1.print(“Voltage:”);
Serial1.println(analogRead(VPowerLeg));
When I add this to my code your function returns -1
If I use “analog read” function or readVcc() separately they work fine, but not
together
Please advice
paul
Posted May 8, 2013 at 8:23 am | Permalink
Coding Badly
Posted May 13, 2013 at 1:54 am | Permalink
flegmatoid
Posted May 14, 2013 at 2:05 pm | Permalink
Mark
Posted May 26, 2013 at 9:59 am | Permalink
I’ve tested on USB and external power supply. I’m gonna bring my board to a
battery with a voltage that might swing a bit.
If I’ve found the right constant with my board can I then use this to measure
the battery voltage (is also the powersupply for my duino) with a voltage
devider bringing it <1.1 Volts to A0 against internal reference?
regards,
Mark
Scott Daniels
Posted May 30, 2013 at 11:08 pm | Permalink
Mark,
You might want to reread the Improving Accuracy section. The internal
reference voltage of 1.1 volts can vary by as much as 10%. Therefore,
the constant value you discovered will be valid only for that chip. It may
also vary over temperature as well.
As far as measuring your battery voltage, you won’t even need any
hardware or the A0 pin. Just use the Vcc function. For battery
monitoring, the 10% error is probably not a big deal, even without
calibration.
Scot
Posted June 10, 2013 at 6:11 pm | Permalink
From your article, it sounds like the 1.1V reference, while perhaps not accurate
to 1.1V, is precise to whatever it’s set to. So maybe my unit reference is 1.0V
but it will always be 1.0V, (ignoring temperature variation). Is that correct or
might the reference voltage change over time?
Scott Daniels
Posted June 16, 2013 at 1:25 am | Permalink
For different pins, they would all use the same voltage reference that
you choose at that time. You can easily change your reference before
making a measurement, which can changed then for different pins. You
usually have 3 choices – internal 1.1v, external (whatever you choose),
and Vcc). So you can choose one reference before measuring one pin,
and then change it for another.
Tom
Posted August 15, 2013 at 7:16 pm | Permalink
Scott,
Thanks for a terrific solution to measuring the supply voltage on the arduino.
I am using arduino mega 2560
On May 8, 2013, Paul posted a code change he says is needed on the mega
2560
He appears to add
ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on
the ATmega2560
after the ADMUX = line for the mega2560
Question: can you confirm it is needed? If yes will you update the code listing
for your readVcc function?
On May 14, 2013, flegmatoid posted another code change related to using
analogread(pin) before calling readVcc, he added ADCSRB = 0 just above the
delay(2) statement.
Question: is this need also on the Mega2560
I wonder if they both are needed only for the Mega2560 because of its
additional analog input pins.
Saqib
Posted August 27, 2013 at 7:24 am | Permalink
nickdigger
Posted September 12, 2013 at 5:03 pm | Permalink
Just tested this on my 168. The adc value is 118, which according to the
formula 1.1*1023*1000 / adc = 9.536v, quite different from the 4.92 I
measured with a voltmeter. I also muxed the 1.1v to the Aref pin, and
measured it to be 1.05v.
Not impressed with the 9.536 result, I checked the datasheet, which says the
1.1v is based on an internal Vcc reference of 2.7v.
A revised formula, (1.05 * 1023 * 1000 / adc) * 2.7/5.0 gives a result of 4.915
— pretty darn close to my 4.92.
nickdigger
Posted September 14, 2013 at 3:46 am | Permalink
ahhh, whoops. I noticed a potential bug in my code, where i failed to put
parentheses around a #define, which could have affected my ADC
settings.
john errington
Posted October 7, 2013 at 1:30 am | Permalink
Hi Scott; I was looking for information on measuring voltages with the Arduino
and found your article. However I didnt find ANY that allowed me to measure
to the precision the arduino allows (0.25%). So I wrote my own pages to
explain how I managed this. The trick is to use a voltage reference IC (LM4040
– 0.5$) as shown here http://www.skillbank.co.uk/arduino/measure.htm
It also shows how you can measure negative voltages.
ems
Posted January 14, 2014 at 7:13 am | Permalink
Hi,
I wish I’d found this earlier! Spent a few hours setting up some maths and a
zener diode into one port to achieve the same thing. Should have read the
manual, but still, learnt something.
However (lucky me for finding this out,not) I found (at least on a sparkfun pro
micro clone) that if you have something like a global var that calls readVcc()
then it will appear to brick the device.
i.e. int Vcc=readVcc();
The reason this happens is because the compiler sets the global vars before
anything, including the timers etc that are used for delay(). So calling delay()
at such an early stage results in an infinite loop (possibly). Calling readVcc() in
setup() is fine.
This may be a problem on all Arduino’s and it’s many clones, however it’s more
noticeable on the Leonardo based Pro micro’s because if your code hangs at
such an early stage, your main PC cannot reset the device for programming,
saying it can’t find the device.
It appears bricked, but a double ‘click’ on reset—>gnd just after clicking the
upload button will allow programming.
ems
Posted January 14, 2014 at 7:18 am | Permalink
Cannot edit, so feel free to read above and substitute it’s/micro’s for
its/micros etc
AndrewK
Posted January 24, 2014 at 10:02 am | Permalink
Swap out the delay() call for a empty loop? That, or move the
initialization into the setup() function.
Gary Chapman
Posted March 11, 2016 at 9:42 am | Permalink
On a 5v chip I’d stick to using a simple LM4040 4.096v external ref (+/-
0.2%). Then the only remaining accuracy issue is the ADC’s 0.25%
typical variance.
love this article. Really explained the whole mess around accuracy and whys
well!
Ross
Posted June 7, 2014 at 3:49 pm | Permalink
Hi,
I am using this for a very battery sensitive project that needs to save as much
power as possible. What is the leakage current from having VCC set up to
measure in this way…do you think it would be a problem long term in regard to
battery life to measure it in such a way?
PeterDollar
Posted July 24, 2014 at 1:46 am | Permalink
This means the constant 1023 used in the readVcc function should be replaced
with 1024.
James Gallagher
Posted March 10, 2017 at 1:49 pm | Permalink
ArduinoLover
Posted September 24, 2014 at 1:14 pm | Permalink
Great! Quick question – If I called the function while plugged to the USB, is
that making a common ground and therefore short circuiting it to ground?
Thank you very much.
It’s a pity you don’t have a donate button! I’d certainly donate to this
excellent blog! I suppose for now i’ll settle for
book-marking and adding your RSS feed to my Google account.
I look forward to fresh updates and will share this website with
my Facebook group. Talk soon!
bola online
Posted October 4, 2014 at 4:39 am | Permalink
Wild Ds Installation
Posted October 14, 2014 at 7:00 am | Permalink
ok I get the concept on how to measure internal voltage but how do I measure
external voltages up to at least 24 vdc
orangekit9840.Soup.
Posted November 11, 2014 at 4:31 pm | Permalink
insanul
Posted November 13, 2014 at 1:15 am | Permalink
I have a servo load, optocoupler, LCD, and Arduino. how to monitor a battery
that has been given the burden?
insanul
Posted November 13, 2014 at 1:18 am | Permalink
I have a load that is servo, optocoupler, LCD, and Arduino. how to monitor a
battery that has been given the burden?
michael
Posted November 30, 2014 at 12:51 pm | Permalink
profuselectern632.
Posted December 1, 2014 at 11:57 pm | Permalink
If you would like to get much from this paragraph then you have to apply uch
methods too your won website.
salvatore
Posted December 23, 2014 at 10:35 am | Permalink
i am trying to use your code on my arduino micro but i have a little problem.
when i use the usb power, it measures correctly the voltage but when i use an
external power source with variable voltage connecting it on the GND and Vin, i
can not get the right value, also at 12v i can get max 5000mV.
thx
christian
Posted January 19, 2015 at 12:02 pm | Permalink
letting agents
Posted February 5, 2015 at 12:20 am | Permalink
jino p
Posted February 19, 2015 at 8:33 am | Permalink
double Vcc;
int row = 0;
int a0=24;
int a1=28; // MUX 1
int a2=32;
int b0=34;
int b1=38; // MUX 2
int b2=42;
uint8_t low = ADCL; // must read ADCL first – it then locks ADCH
uint8_t high = ADCH; // unlocks both
void setup()
{
pinMode(a0, OUTPUT);
pinMode(a1, OUTPUT);
pinMode(a2, OUTPUT);
pinMode(b0, OUTPUT);
pinMode(b1, OUTPUT);
pinMode(b2, OUTPUT);
pinMode(analogin1, INPUT);
pinMode(analogin2, INPUT);
Serial.begin(9600);
void loop()
{
Serial.println( readVcc(), DEC ); // Fn call 1
int i=0;
// Reading Temperature
float dummy;
for (i=0;i<11;i++)
{
dummy = analogRead(analogin1);
delay(10);
}
//i=0;
for(i=0;i>0)&1)==1)
{
digitalWrite(a0,HIGH);
digitalWrite(b0,HIGH);
}
else
{
digitalWrite(a0,LOW);
digitalWrite(b0,LOW);
}
// code for a1 and b1
if(((i>>1)&1)==1)
{
digitalWrite(a1,HIGH);
digitalWrite(b1,HIGH);
}
else
{
digitalWrite(a1,LOW);
digitalWrite(b1,LOW);
}
// code for a2 and b2
if(((i>>2)&1)==1)
{
digitalWrite(a2,HIGH);
digitalWrite(b2,HIGH);
}
else
{
digitalWrite(a2,LOW);
digitalWrite(b2,LOW);
}
Vcc = readVcc()/1000.0;
value_a[i]=analogRead(analogin1);
value_b[i]=analogRead(analogin2);
voltage_a[i]=(value_a[i] / 1023.0)* Vcc ;
voltage_b[i]=(value_b[i] / 1023.0)* Vcc ;
temp_a[i]=temp(i,voltage_a[i]);
temp_b[i]=temp(i+8,voltage_b[i]);
Serial.println( readVcc(), DEC );// Fn call 2
delay(500);
}
{
Serial.println( readVcc(), DEC );// Fn call 3
// Serial.print(“DATA,TIME,”); Serial.print(temp_a[0],DEC); Serial.print(“,”);
Serial.print(temp_a[1],DEC); Serial.print(“,”);
// Serial.print(temp_a[2],DEC); Serial.print(“,”); Serial.print(temp_a[3],DEC);
Serial.print(“,”);
//Serial.print(temp_a[4],DEC); Serial.print(“,”); Serial.print(temp_a[5],DEC);
Serial.print(“,”);
//Serial.print(temp_a[6],DEC); Serial.print(“,”); Serial.print(temp_a[7],DEC);
Serial.print(“,”);
//Serial.print(temp_b[0],DEC); Serial.print(“,”); Serial.print(temp_b[1],DEC);
Serial.print(“,”);
//Serial.print(temp_b[2],DEC); Serial.print(“,”); Serial.print(temp_b[3],DEC);
Serial.print(“,”);
//Serial.print(temp_b[4],DEC); Serial.print(“,”); Serial.print(temp_b[5],DEC);
Serial.print(“,”);
//Serial.print(temp_b[6],DEC); Serial.print(“,”); Serial.println(temp_b[7],DEC);
row++;
delay(500);
Serial.flush();
}}
CLEARDATA
LABEL,Time,Tc1,Tc2,Tc3,Tc4,Tc5,Tc6,Tc7,Tc8,Tc9,Tc10,Tc11,Tc12,Tc13,Tc14,Tc15,Tc16
5046
-1
-1
-1
-1…………………………..
Splinter
Posted February 24, 2015 at 2:47 pm | Permalink
pete
Posted June 2, 2015 at 5:02 pm | Permalink
Hi i was just wondering if you would be kind enough to help me out on some
arduino code im having an issue with. My code basically displays four
temperatures on a lcd screen. the code works perfectly on a Pro Micro
ATmega32U4 5V 16MHz. but i now want to use the code on a AMEGA328P AU.
(bread boarded with all pins broken out) Problem is now my temperatures are
reading incorrectly. I believe this is due to the fluctuations in voltage 5v vcc
being supplied to the chip and sensors.
to overcome this you simply connect the AREF pin to the 5v vcc this should
then correct the temperature readings. no matter that the vcc in is.i have done
this and does nothing so im wondering if my code has an error somewhere
making this not work.
i also have to connect 5v vcc connected to A5 to stop my temperature readings
going completely wrong -120c soon as i connect this pin to 5v i get correct
room temperature reading of 19c but if 5v vcc fluctuates so does the temp
reading.
would you be able to try and help me by having a look at my code and doing
any edits you may feel will fix this as im out of ideas now
i did try using a 5v voltage regulator on the vcc in but that does not give a
perfect constant 5v so this is not an option unfortunately
/*
unRaidLCD.ino
The Circuit:
Pin
1VssDisplay power ground & 10k Potentiometer Ground (pin 1)ground (either
black wire)
2VddDisplay power +5V & 10k Potentiometer pin 1) +5v (red wire)
This stops the message activating on screen (keeps D11 low and when 5v to
D11 make the pin high which activates message
*/
#include
#include
#define BBdelay 6000 // 2 second delay interval for backup battery screen
// initialize the lcd library with the numbers of the interface pins
char str[22];
//
====================================================
// Structure to define the sensors, text, text positions, value positions and
smoothing buffer
//
// alarm result of alarm test (0 no alarm, 1=below low limit, 2=above high
limit)
// lotxt text for alarm low (make this an even number of characters)
// hitxt text for alarm high (make this an even number of characters)
//
//
====================================================
struct {
int pin;
char *txt;
char type;
uint8_t txtx,txty;
char *fmt;
uint8_t valx,valy;
int ck,lo,hi;
uint8_t alarm;
char *lotxt,*hitxt;
uint8_t bufptr;
int buffer[BUFSIZ];
sensors[NUMADC] =
A0, " CPU ", 'c', 0,2, "%3dc", 4,2, 1, 0, 105, 0, "CPU Temp Lo","CPU Temp Hi",
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 105 = 65C OR 90 = 55C
A1, " SYS ", 'c', 10,2, "%3dc", 15,2, 1, 0, 78, 0, "SYS Temp Lo","SYS Temp Hi",
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //78 = 50C
A2, "PARITY ", 'c', 0,3, "%3dc", 6,3, 1, 0, 94, 0, "PARITY Temp Lo","PARITY
Temp Hi", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 94 = 60C
A3, " DRIVE ", 'c', 10,3, "%3dc", 16,3, 1, 0, 94, 0, "DRIVE Temp Lo","DRIVE
Temp Hi", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 94 = 60C
};
//
====================================================
//
====================================================
void setup()
lcd.setCursor((DISPLAY_WIDTH-7)/2,0);
lcd.print(" Admin"); // Print out a title while we wait for the analog smoothing
to initialise
lcd.setCursor(0,1);
timer = millis();
if (display_flip==1)
lcd.setCursor(0,0);
lcd.setCursor(0,1);
else
lcd.setCursor(0,0);
if(!shown)
{
for (uint8_t i=0; i<NUMADC; i++)
lcd.setCursor(sensors[i].txtx,sensors[i].txty);
lcd.print(sensors[i].txt);
shown = true;
if (display_flip==0)
lcd.setCursor(0,1);
StartReadings = true;
if(StartReadings)
lcd.setCursor(sensors[i].valx,sensors[i].valy);
sprintf(str,sensors[i].fmt,getVal(i));
lcd.print(str);
//
//
uint8_t k=1,l=0;
while (k==1)
int j=(-1);
lcd.clear();
l=1;
lcd.setCursor(6,0);
lcd.print(“WARNING”);
lcd.setCursor((DISPLAY_WIDTH-strlen(sensors[j].lotxt))/2,1);
lcd.print(sensors[j].lotxt);
lcd.setCursor((DISPLAY_WIDTH-strlen(sensors[j].hitxt))/2,1);
lcd.print(sensors[j].hitxt);
lcd.setCursor(3,2);
lcd.setCursor(8,3);
sprintf(str,sensors[j].fmt,getVal(j));
analogWrite(BUZZPIN,200);
delay(50); // bzzzzzzz
analogWrite(BUZZPIN,0);
BB_timer = millis();
scrToggle = !scrToggle;
if(scrToggle)
lcd.setCursor(0,0);
lcd.setCursor(0,1);
lcd.setCursor(0,2);
lcd.setCursor(0,3);
else lcd.clear();
shown = false;
//
====================================================
//
====================================================
delay(44); // Get the voltage reading from the temperature sensor and give it
time to settle x
reading = analogRead(sensors[Pin].pin);
if (sensors[Pin].type==’c’)
else {
float r=(reading*100.0)/1025.0;
reading=r;
// Note I do the alarm check on the current value rather than the smothhed
one as this would cause a time lag
{
if (readingsensors[Pin].hi) sensors[Pin].alarm=2; // Above High limit?
if ((++sensors[Pin].bufptr)>=BUFUSE) sensors[Pin].bufptr=0;
//
====================================================
//
====================================================
void getVref()
delay(17); // get the voltage reading from the temperature sensor and give it
time to settle
reading = analogRead(VREF);
Gauthier
Posted November 1, 2015 at 1:02 pm | Permalink
This trick is very usefull for mesuring the VCC voltage. In my project I have an
Arduino mini pro 3.3V powered by a 1s lipo on the raw input voltage pin. The
code tell me the 3.3v regulator output tension rather than the regulator input
from raw pin. So is it possible to read the raw input voltage pin voltage rather
than the vcc pin ?
Dave
Posted January 27, 2016 at 4:54 pm | Permalink
1024 is the correct number to use in the scale constant and here’s why from
the
“The ADC converts an analog input voltage to a 10-bit digital value through
successive approximation. The minimum value represents GND and the
maximum value represents the voltage on the AREF pin minus 1 LSB.”
So as you can see the maximum value is not the voltage on the AREF pin but
actually one unit lower. So if you’re performing an analogRead() and
referencing Vcc and you get a max value from the ADC then the value should
actually be treated as 1023/1024 * Vcc. It should be noted that really a max
value from the ADC is not accurate since any voltage higher than the reference
will report at the max value.
Furthermore, in the code in the article we measure the internal 1.1V and
reference the ADC with Vcc. The equation to convert the reported voltage is:
Dave
Posted January 27, 2016 at 4:58 pm | Permalink
Corrected link:
1024 is the correct number to use in the scale constant and here’s why from
the Atmel complete datasheet on this page
“The ADC converts an analog input voltage to a 10-bit digital value through
successive approximation. The minimum value represents GND and the
maximum value represents the voltage on the AREF pin minus 1 LSB.”
So as you can see the maximum value is not the voltage on the AREF pin but
actually one unit lower. So if you’re performing an analogRead() and
referencing Vcc and you get a max value from the ADC then the value should
actually be treated as 1023/1024 * Vcc. It should be noted that really a max
value from the ADC is not accurate since any voltage higher than the reference
will report at the max value.
Furthermore, in the code in the article we measure the internal 1.1V and
reference the ADC with Vcc. The equation to convert the reported voltage is:
Also people asked if they needed to change the reference. You do not since we
are referencing Vcc (which is default) but measuring the 1.1V reference. The
measurement will change when you perform an analogRead().
Gary Chapman
Posted March 11, 2016 at 9:48 am | Permalink
/1023 ? Oh my … that poor MCU. I can almost hear it’s tortured screams from
here : )
perigaacticon
Posted May 5, 2016 at 12:18 pm | Permalink
Hello,
I just tried this on a Mega2650, and I am getting the value of the 5V reference
instead of VCC. If I try with 12V on the barrel jack VCC = 5023, with USB
power only it reads 4892. Can you tell me if there are modifications I need to
make to the code you posted? Thanks!
perigaacticon
Posted May 5, 2016 at 12:24 pm | Permalink
Darko
Posted May 19, 2016 at 9:20 am | Permalink
Inoace
Posted August 16, 2016 at 11:15 am | Permalink
abel
Posted September 9, 2016 at 6:19 pm | Permalink
Great article, I learn a bit more, but couldn’t get profit of this. I want to
measure my battery level and I’m powering Arduino by L298N 5Vout into Vin
directly, maybe I got an error because I wasn’t really decided, since my simple
circuit of 2 resistors to divide my 12V battery into 4.5V of max and taking
aritmethic media of readings I got stable % when motors are off. Correct me if
you still think the best way is yours, since I guess it must be powered by 5V
regulator inside from a minimum of 9V input. Thanks. Keep working.
Olivier
Posted January 18, 2017 at 10:22 am | Permalink
It took me a while to understand the code and the logic behind the bandgap
value and how it relates to reading an external voltage, but now that I was
finally able to understand your code and implement it successfully, I feel in
deep gratitude with you. Thanks for taking the time to share your knowledge,
this guide can currently be found in pretty much all Arduino voltmeter related
topics on the internet
Jeff
Posted February 2, 2017 at 11:52 am | Permalink
Your instructions just solve my problem. Thank you so much. I had been
looking every place and was ready to give it up and try something different.
Situs Judi
Posted June 6, 2017 at 7:27 am | Permalink
This website was… how do I say it? Relevant!! Finally I have found something
that helped me.
Thank you!
Tim C
Posted November 5, 2017 at 2:17 pm | Permalink
For Mega 2560, you also need to set ADCSRB, which has the MUX5 bit in it,
otherwise you get zero’s returned
Mike K
Posted November 24, 2017 at 3:03 pm | Permalink
I know this is an old thread, but I made some adjustments that have given me
more accurate results along a wider range of Vcc. I did this by connecting Vcc
to AREF externally to use to compare. It is still necessary to calculate the
constant that is divided by ‘result’ (the formula is commented in the code). The
constant used in the code below is specific to my particular Arduino Nano; this
number will need to be changed in your case using the formula. I’ve also
placed the ADC in free-running mode and set the ADC frequency to 125kHz
(assuming a 16MHz clock). The adjusted code is posted below. Any critiques or
comments will be appreciated.
long readVcc() {
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); // Prescaler at 128
(125kHz)
ADMUX &= ~((1 << REFS1) | (1 << REFS0)); // Set reference to AREF
ADCSRB &= ~((1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0)); // ADC in
free-running mode
// Read 1.1V reference against AREF
ADMUX = (1 << MUX3) | (1 << MUX2) | (1 << MUX1); // set the
measurement to the internal 1.1V reference
ADCSRA |= (1 << ADEN); // enable ADC.
_delay_ms(2); // Wait for Vref to settle
ADCSRA |= (1 << ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first – it then locks ADCH
uint8_t high = ADCH; // unlocks both
33 Trackbacks
By » Arduino can be your voltmeter Fuzzy Hypothesis Online on July 12, 2012 at 11:27
am
By Belgaum news | About Belgaum | Belgaum information | Belgaum district | Belgaum
city | Belgaum Hotels | Belgaum People | Belgaum tourism | Belgaum entertainment |
Belgaum students | Inside facebook | Hack | make use of | technical news | | Arduino
voltage on August 15, 2012 at 6:07 pm
By Arduino voltage measurement tricks « My Horizon Wireless on August 16, 2012 at
5:39 am
By Secret Arduino Voltmeter — Arduino Passion on August 16, 2012 at 7:24 am
By Secret Arduino Voltmeter – Measure Battery Voltage | electronics-projects.info on
August 19, 2012 at 7:19 pm
By Measure the Vcc voltage applied to an Arduino « freetronicsblog on August 20, 2012
at 1:54 am
By Secret Arduino Voltmeter – Measure Battery Voltage | A Maker's Dream Factory on
August 29, 2012 at 8:31 pm
By Laurent Pantanacce » links to blog.pantanacce.com (weekly) on January 6, 2013 at
2:35 pm
By Accuracy of Arduino’s ADC | Baltazar's Hacks on November 19, 2013 at 12:17 am
By Hacking together a simple EMonCMS installation | Imaginary Industries on January
10, 2014 at 4:54 am
By mois-Blog - Bienenwaage: Todo on July 18, 2014 at 1:33 pm
By Arduino Mega 2560 ADC read Minivolts at ADC port A8 | CL-UAT on December 29,
2014 at 10:35 pm
By Improved RFM12B with accurate RSSI reading Library – on December 30, 2014 at
8:58 am
By Measure Arduino Battery Voltage | Begerk on February 8, 2015 at 11:18 am
By Прихований вольтметр в Arduino – вимірювання напруги батареї засобами
мікроконтролера » Блоґ Ореста on March 30, 2015 at 2:27 pm
By HOWTO: Very low power usage on Pro Mini V2 (Arduino clone) — whizzy.org on June
11, 2015 at 3:39 pm
By #Temp_Heart_Sensor | Facelesstech on July 31, 2015 at 3:28 pm
By Die Versorgungsspannung messen | wer bastelt mit? on December 8, 2015 at 4:45
pm
By Battery Voltage Drops When Driving | licsense - driving test on December 19, 2015 at
10:07 am
By Arduino power consumption and management | Raspberries and other fruits on
January 8, 2016 at 12:23 pm
By Wireless Steering Wheel Buttons - GT40s.com on January 29, 2016 at 9:57 am
By ARDUINO | Pearltrees on February 3, 2016 at 7:07 am
By Variometer selber gebaut on February 24, 2016 at 1:24 pm
By Como medir a tensão de alimentação do arduino. | AUTOMALABS on February 29,
2016 at 2:10 am
By How To Measure Voltage In Circuit | Yellow decoration on July 13, 2016 at 9:08 am
By How To Measure Voltage Drop Of Diode | Yellow decoration on July 14, 2016 at 11:44
pm
By How To Measure Resistance With A Voltmeter | Yellow decoration on July 18, 2016 at
2:17 am
By surveillance pile sur noeud mySensor | CM Ingenierie on February 11, 2017 at 7:52
am
By How To Double Battery Voltage | Information on February 18, 2017 at 9:40 pm
By Measuring Current Voltage And Power Book – inebooks Review on March 24, 2017 at
3:18 pm
By Voltuino Revisited | on April 13, 2017 at 4:08 pm
By Resources, articles and helpful links | okinesio on June 22, 2017 at 9:41 am
By Error In Voltmeter Readings on November 28, 2017 at 11:22 am