Nano: Analog read, values incorrect

Hi,
I am trying to read a voltage value from a higher (12-15V) supply. I know that the Nano's analogue input will only read vales up to 5V, so I am using a voltage divider.

Vin

2k
---> Nano (plugged into USB on a laptop)
1k

GND (commoned from the Arduino board to the battery)

The values I get back from the arduino seem to be slightly high. I don't know how accurate this should go in theory, but I'd really need to be at least within 0.2v accuracy, ideally better. I don't know if this is beyond the hardware capabilities, or if I've done something silly. The voltages measured by my meter were verified by a second meter.

These are the results with map(vPin,0,1023,0,50):

Location V Meter Arduino
Divider 4.18 44
Nano 5V pin 4.74 49
Nano 3.3V pin 3.34 35
Nano GND 0 0

And with map(vPin,0,1023,0,150):

Location V Meter Arduino
Vin 12.68 133

Am I doing something wrong here, or is this expected?

Please post your entire sketch here, and don't forget to enclose it in code tags. Also a schematic would be good just to be sure, even though it's a simple circuit.

It depends on what you have chosen for your reference.

As you will see on my own site, the "standard" references may be inaccurate.

My guess is you are using Vcc (DEFAULT) as your reference - but Vcc is not 5V but 4.74V - maybe this is why? Using an Arduino to measure USB voltage

You arent giving much headroom protection in your divider; if Vin > 15V then you are applying an excess voltage to the input pin, from a low impedance (2k // 1k = 600ohm ) source..

Finally, you should really use 44k : 22k to reduce the divider current and be a better match to the nano input. (for 44k use 2 22k in series)

Also to get an accurate reading its best to take a reading and reject it, then a set of readings (say 16) add 'em up and divide by 16 (left shift 4 places).

I'd suggest you map 0,1023, 0, 500 to get decent resolution.

Here is the code and schematic.

int vPin = A1;
int volts = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  
}

void loop() {
  volts = analogRead(vPin);
  volts = map(volts,0,1023,0,150);
  Serial.println(volts);
  delay(500);
}

OP circuit

I don't agree with everything in reply #2. It is a good suggestion that your Vcc from USB is not 5.00V, it almost never is. Your resistor value choices look fine to me, 20k/10k. With those you wouldn't damage the input if you go a little over 15V.

Also a minor tweak that makes almost no practical difference but bothers me every time I see it. 1023 is not the correct scaling factor to use in ADC to numerical conversion expressions. There are 1024 ADC steps not 1023. Thus each step is 1/1024 of the analog input range. Accordingly, it should be divided by 1024, not 1023. The difference is less than the ADC error, so makes no practical difference but is a conceptual error that is better to eradicate lest it migrate into other code where it might make a measurable difference.

I have given up using analogref (DEFAULT) It is just too heavily dependent on the supply voltage.
I prefer using analogref (INTERNAL) and a 0...1,1V range that is ways more reliable.
Anyhow with a trimpot to calibrate the input.

Thanks for all this! I have learned a lot in the last couple of hours.

johnerrington:
It depends on what you have chosen for your reference....

I tried the same thing on my Arduino Uno (100% legit) board and got 5.1v from the 5v pin. I went back and looked at my Nano (maybe not so legit) and found a diode hanging out. Compared it to internet images of the underside of the board. Measured the voltage. Story adds up. I removed it, got 5.1v from the 5V pin. Guess that'll show me for cheaping out.

It's still not quite accurate enough, so I'll go for an external source. I've got a couple of LM4040s on their way (might as well take a spare if they're so cheap).

Honestly, it never occurred to me that the analogue read would be relative to the supply voltage, but now that I think about it, it makes a lot more sense.

I will be changing the configuration of the voltage divider just in case, too. 15V is the maximum I'd ever expect to see on the system, but it's a very messy source (vehicle alternator/battery), so who knows. I'll also try the averaging, although the readings I get are fairly consistent (just consistently wrong!).

aarg:
Also a minor tweak that makes almost no practical difference but bothers me every time I see it. 1023 is not the correct scaling factor to use in ADC to numerical conversion expressions.

I'm trying to get my head around this. If the ADC starts at 0, wouldn't that be the same as 0 volts on that pin?

jospanner:
And with map(vPin,0,1023,0,150):

Location V Meter Arduino
Vin 12.68 133

Your mapping is assuming that the reference voltage is exactly 5V - but is out by a factor of 10.
However you have established that the voltage on the 5V pin (and hence the reference voltage) is actually 4.74

Location



V Meter



Arduino



Divider



4.18



44



Nano 5V pin



4.74



49



Nano 3.3V pin



3.34



35



Nano GND



0



0




So you can 'correct' your value of 133 by dividing by 10, then multiplying by (4.74/5).

(133/10) x (4.74/5) = 12.61
Which is pretty close to the 12.68 that you measured with your meter

(I think that the difference is only a rounding error as there is only about 0.5% difference between the two values).

jospanner:
I'm trying to get my head around this. If the ADC starts at 0, wouldn't that be the same as 0 volts on that pin?

Absolutely, yes. Both ranges begin at 0. The upper limit of the target range is 5.000V, the upper limit of the ADC range is 1024. The greatest possible value is 1023, but that isn't the relevant number. It expresses 1023/1024 of the analog input range, not the full range. Suppose the input range is 5V, and there are 1024 steps. A reading of 1/2 of 5V should yield 2.500V, right? 1/2 is 512/1024, not 512/1023.

jospanner:
I removed it, got 5.1v from the 5V pin.

That diode is there to protect the computer/laptop. Do not remove.
The Uno has a more elaborate 'ideal diode' circuit there in the form of a mosfet.
The smaller Arduinos don't have room for that, so they use a simple Schottky diode.

The default setting of the A/D is fine for some sensors, and even must be used for that,
but voltage measurements should always be done with (one of) the internal/stable reference(s).

Calculate your divider for 1volt. Something like 33k:2k2
Then add this line to setup()

analogReference(INTERNAL); // switch to the more stable internal reference

Leo..

Oh dear aarg - not the 1023 /1024 debate AGAIN. Its been ably resolved by Nick Gammon - BOTH ARE WRONG.

Full (and irrelevant) discussion on my site with an excel spreadsheet to try it all out - The Arduino ADC and how it measures an input voltage

Why irrelevant? because the error introduced in using 1023, 1024 etc is
a FIXED error - so can be calibrated out
and much less than the fixed error in the divider chain (did you use 0.1% tolerance resistors?)
and much MUCH less than the error in using an arduino reference
and ignores the possibility that the input voltage may be changing; or temperature dependence; or converter non-linearity.

For accurate results an external reference is definitely the way to go - well done Jo for getting the 4040's.
Also (despite my rant above) I'd use 1024 as the most convenient option.

Wawa:
That diode is there to protect the computer/laptop. Do not remove.

I didn't see one on the official board (from what I could see, anyway), so I thought it would be OK. I'll put it back for now, seeing as it's not really a problem if I'm using an external source anyway. I will play with the internal source though, it's good to know for the future!

johnerrington:
and much less than the fixed error in the divider chain (did you use 0.1% tolerance resistors?)

I am indeed using 0.1% resistors, I thought about going lower but I think that might be overkill for this application.

I've redrawn the Nano schematic, making it easier to follow. Unfortunately the symbols lend them selves to a right-to-left flow, vs left-to-right.

On the lower right is the USB connector, above that is the diode that prevents external 5V from the regulator from backfeeding 5V into the PC. In my experience the PC doesn't like that, mine declares a Power Surge and shuts down the USB port on me, requiring a PC reset to get the port functional again.

After that is the FT232 chip which is the USB/Serial interface, and it's 3 connections to the '328P, Rx, Tx, and DTR cap which combines with the 10K pullup resistor to create a Reset pulse. It is also the 50mA, 3.3V source. And it controls the Rx/Tx LEDs.

In the middle is the '328P chip and the ICSP header for bootloading it, or Upload Using Programmer if one wanted to run a sketch with no bootloader for faster startups.

And then the pins that we interact with.

You can (and should) calibrate the final device. At that step, it's possible to completely gloss over the difference between using a scale factor of 1023 vs. 1024 by not using it at all. Yes, you read me correctly, you don't really need to know or use it. First ground the input, take a raw ADC reading, verify it is 0. Now apply an accurate 15.00V to the input, suppose it gives you 1007. 1007-0 == 1007. In your code (or in EEPROM if you want to put the cal constant there) the voltage calculation can now be 15.0ADC/cal = 15.0ADC/1007.

This calibration encompasses all the errors including resistor and ADC inaccuracies, all at the same time. As a matter of fact, it would allow for resistors of much lower tolerance if necessary, for example 1% or even 5%.

In your code as it stands, it would look like:

int calConstant = 1007;  //use this initialization or load from EEPROM
...
  volts = map(volts,0,calConstant,0,150);

jospanner:
I am indeed using 0.1% resistors...

Resistor tolerance is totally irrelevant here. You must calibrate anyway, because of Aref.
Just use the common 1% metalfilm (for stability).
Leo..

Wawa:
That diode is there to protect the computer/laptop. Do not remove.

Maybe, maybe not!

Possibly more to protect from loading the on-board regulator.

Wawa:
The UNO has a more elaborate 'ideal diode' circuit there in the form of a mosfet.

But it does not actually provide the same protection.

This is predicated that the on-board regulator is a useful power supply, which is not the case once you add other devices to the basic board.

It's a bit of a botch!

What is odd about both designs is that the USB interface chip is powered by the main 5 V line and not the USB 5 V as you would expect. This means it is drawing current even when you are not using the USB interface.

Hi Leo - I love this discussion and I'm sure the OP is learning a LOT.

My comments about resistor precision was to show that the question of scaling factor was generally much less significant than other factors involved.

In fact since the OP stated she was seeking 0.2V accuracy (1 part in 25, or 4%) 0.1% tolerance resistors would have been overkill.

Of course ideally, as you say, the result SHOULD be calibrated; but if you dont HAVE a stable voltage standard of better than 0.1% accuracy an alternative is to use a good voltage reference and high quality resistors.

Then, does your voltage divider load the source significantly?

Also (as I hinted) there is a question of how frequently to measure the voltage - and what are you trying to learn about the value you are measuring?

Surely the function of diode D1 is to prevent excess voltage feeding back to the USB in the event of a fault? But it DOES reduce the voltage at Vcc and, as Jo has observed, changes the result if you use "DEFAULT" as your reference.

Jo, thanks for staying with this discussion. Can you tell us what is the source of the voltage you are measuring?

Yeah I'm learning things just from reading this! :slight_smile: Using the regulator, I shouldn't need to worry about whether or not the diode is there, but it's worth knowing that this board design gets a significant voltage drop from the USB power source, for any future work.

The shunt regulator arrived today, by the way.

I have an LM4040 set up, and based on my reading of the data sheet, I think I can use a 1k resistor before the regulator/ARef connection, and this should pass through about 900uA.

If I'm reading the sheet correctly, though, we can go as low as 68uA which we should get with 13.2k of resistance, so the temptation is to give it a 10k and see if that works.

The application in question is a low voltage cutoff for a 12v lead-acid battery power system in a van (as well as for general switching of high-ish current relays). For this purpose, I don't really need more than .1v of precision.

Note that the maximum recommended input impedance for analog inputs is 10K, your voltage divider has 20K. This could be resolved by connecting a 0.1µF capacitor from A1 to GND. This will help somewhat with reading accuracy and stability. Another thing to try is taking 2 readings in succession and using the second reading only.

dlloyd:
Note that the maximum recommended input impedance for analog inputs is 10K, your voltage divider has 20K.

I think not. The actual impedance is 10k||20k, resistors in parallel. That's 6.67k ohms.