Arduino Forum

Using Arduino => General Electronics => Topic started by: Boopidoo on Jan 02, 2013, 12:06 am

Title: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 12:06 am
My goal is to read voltage from either a 2S or 3S lipo-battery which means that to read it with my arduino I need to reduce the voltage. I had some 100K and 10K resistors at home so I built a voltage divider using these. I measured the resistors to be R1=98700 and R2=9790. As can be seen in the code I use a variable called voltage_divider that has these values which I use when reading the voltage. The voltage is read using the Vin pin, there I connect R1 & R2 then connect to ground. I read the voltage over R2 into the A0-pin.

The problem is that I get a value that's close to the correct value but too far away to be acceptable. For example, a voltage of 4.55V reads 4.35V and 11.68V reads 11.45V.

Can anyone spot an obvious error?

Code: [Select]

#include <LiquidCrystal.h>

//LCD display pinout - YM2004A & OV1604A
//VSS   LCD pin 1     -  Connect to ground
//VDD   LCD pin 2     -  Connect to +5V
//V0    LCD pin 3     -  Connect to potentiometer
//RS    LCD pin 4     -  Arduino pin D07 
//RW    LCD pin 5     -  Connect to ground
//EN    LCD pin 6     -  Arduino pin D08
//DB4   LCD pin 11    -  Arduino pin D09
//DB5   LCD pin 12    -  Arduino pin D10
//DB6   LCD pin 13    -  Arduino pin D11
//DB7   LCD pin 14    -  Arduino pin D12
//ELA   LCD pin 15    -  Arduino pin D13
//ELK   LCD pin 16    -  Connect to ground
//LiquidCrystal lcd(7, NULL, 8, 9, 10, 11, 12);
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int screen_backlight = 13;                 //pin D13 will control the backlight
float voltage_battery = 0;                 //pin A0
float voltage_divider = (98700+9790)/9790;    //((R1+R2)/R2)*voltage on A0-pin

void setup() {
  pinMode(screen_backlight, OUTPUT);       //LCD Setup
  digitalWrite(screen_backlight, HIGH);    // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
  lcd.begin(20,4);                         // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  lcd.clear();                             // start with a blank screen
  lcd.setCursor(0,0);                      //LCD text row 1
  lcd.print("Ui      V");
}

void read_voltage() {
  //Voltage input, U must be lower then 5V, HW-diveded then SW-multiplied
  voltage_battery = analogRead(A0)*voltage_divider*5/1023;
}

void screen_print() {
//Printing battery voltage level on LCD-screen
  lcd.setCursor(3,0);
  if(voltage_battery<10) {
    lcd.print(" ");
  }
  lcd.print(voltage_battery);
}

void loop() { 
  read_voltage();
  screen_print();
}
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 01:04 am
To clarify, this picture shows how I've done.

Title: Re: Voltage divider problem
Post by: fungus on Jan 02, 2013, 01:17 am
What are the exact voltages measured at the battery, the Arduino +5V pin and the analog input pin when it's connected up?
Title: Re: Voltage divider problem
Post by: MAS3 on Jan 02, 2013, 01:24 am
Your voltage divider adds up to about a factor 11, not as a factor 10.
I guess that's what you are tripping over.
Title: Re: Voltage divider problem
Post by: be80be on Jan 02, 2013, 01:36 am
I would change the resistor values to as in my drawing

Then a little math and see if it don't work better
Code: [Select]
ADC reading  1000 +2000 = 3000 /1000 = 3

check the chips ADC AREF pin say it's 4.89 volt
you can compensate for that in code 

so your math is 1000 +2000 = 3000 /1000 = 3 * 5 =(V1) 15

So a ADC reading of (V2) 5 volts = 15 volts


Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 01:46 am

What are the exact voltages measured at the battery, the Arduino +5V pin and the analog input pin when it's connected up?



The +5 pin is 4.55V and the battery is 11.68V.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 01:51 am
@be80be
Why the extra 1K resistor before the A0-pin?
Title: Re: Voltage divider problem
Post by: MarkT on Jan 02, 2013, 01:52 am

Your voltage divider adds up to about a factor 11, not as a factor 10.
I guess that's what you are tripping over.


That's obviously not the issue if you look at the code.
Code: [Select]

float voltage_divider = (98700+9790)/9790;    //((R1+R2)/R2)*voltage on A0-pin


One issue is that the calculation is in integer arithmetic, and secondly that error of about 2% is perfectly within spec anyway.

That code sets voltage_divider to 11.000.
Code: [Select]

float voltage_divider = (98700.0+9790.0)/9790.0;    //((R1+R2)/R2)*voltage on A0-pin


Will do the right thing.  Voltage regulators (such as the 5V regulator on the Arduino that you are using as
the voltage reference for ADC measurements) will normally have a +/- 2% or 5% rating - until you measure
the actual 5V rail voltage and substitute it for "5" in the calculations you can't do any better.
Title: Re: Voltage divider problem
Post by: be80be on Jan 02, 2013, 01:55 am

@be80be
Why the extra 1K resistor before the A0-pin?


I will save you from making a bo bo it limits the current
Title: Re: Voltage divider problem
Post by: be80be on Jan 02, 2013, 02:09 am
The voltage divider has to be set for the AREF to get a true  reading  You pick a voltage range 0 to 15

Then you pick the resistors to read full scale at your AREF voltage is how you get a true reading.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 02:15 am
Ok, so to improve the accuracy I could reduce the resistor values or at least the dividing factor so that I get something around 3 or 4 instead of 11. This should make the accuracy a little better right? I want to be able to connect up to 4S-battery (16.8V) safely.

The 5V supply from the arduino seems to be a pretty solid 5V when I connect an external battery. I get 5.00V on my multimeter and when I power it using USB I get 5.06V. Or do you mean another 5V-rail then the 5V-output pin?
Title: Re: Voltage divider problem
Post by: be80be on Jan 02, 2013, 07:18 am
I would go for 20 volts then R1 would be 3k  and R2 1K  I would use a 2K Trimpot feed 20 volts to it and set the center dead on my VREF.
Title: Re: Voltage divider problem
Post by: MAS3 on Jan 02, 2013, 07:47 am
Your measuring range with the original divider is too high.
I will gladly admit i didn't look at the code to see that you are using a formula that takes the number 11 as the divider.
But this way your maximum reading of 1023 would represent about 55 volts.

Therefore it would be better to try to get as close as possible to the actual range you are in.
So if you have 12 volts, and with the available resistors, i would use R1 as is, and instead of R2, 2 10K resistors in parallel forming a resistor of about 5K.
This would put you in a range of 15 volts, about 3 times better than where you are at now.

You then are measuring more accurate, because you have more bits to divide per voltage, so calculating with the measured result will also be more accurate.
Title: Re: Voltage divider problem
Post by: jackrae on Jan 02, 2013, 09:40 am
Hi guys

Don't confuse "resolution" (bits per volt) with "accuracy" (precision of measurement)

Increasing resolution will help with determination of measurement but it does not necessarily increase "accuracy", which depends on your Vref, ADC precision and input resistor tolerances.  You cannot get "accurate" results if you use 10% tolerance, high temp coefficient resistors.  And don't say you've already measured their values with your digital test meter.  What level of precision does that offer ?

On the other hand, measurement is a "relative" thing.  If you use your personal test meter as your "in-house standard" then all well and good since all subsequent measurements are referenced to it  -  not to precise national standards.  For example, I'm quite happy to use my cheap and nasty test meters as my reference standards but cannot ever consider them "accurate"  -  just good enough for my needs.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 01:45 pm
Now I've reduced the voltage divider and use R1=2990 and R2=984 and yes I do use my calibrated Fluke to measure everyting (as well as a cheapo but quite accurate meter). This will not need to hold any kind of indistry calibration standard but I need it to be as close to my meters as possible.

Now I get the following results:
Power over USB: 4.32V (arduino), 4.47 (on my meters),  3.35% diff
Power over 3S: 11.52V (arduino), 11.66V (on my meters), 1.2% diff

Of course I'd like it to be even better so I guess I should now start investigating this VREF that I guess is how the arduino close the arduino 5V supply is to 5V. Is that correct? Is there a prefered method of doing this?
Title: Re: Voltage divider problem
Post by: billhowl on Jan 02, 2013, 01:52 pm
Read this http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino (http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino)
Title: Re: Voltage divider problem
Post by: dhenry on Jan 02, 2013, 02:22 pm

Read this http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino (http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino)


[/quote]Wrong![/quote]

That's an overly simplistic, black-and-white view of a highly complex world.

For example, I can point to multiple cases where the "wrong" approach is correct and the author's "Very nice. very elegant. And, more importantly, very useful." approach is "wrong".

What the author forgot to mention is that what's right or wrong is highly application specific so it is wrong to insist one approach is "wrong" while the others "right".
Title: Re: Voltage divider problem
Post by: billhowl on Jan 02, 2013, 02:59 pm
Yes, the 1.1V have about 10% accuracy.
Quote
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!


http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ (http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/)
Title: Re: Voltage divider problem
Post by: tack on Jan 02, 2013, 03:06 pm
How much more 'accurate' are you expecting things?

A couple of percent looks pretty good really. There are a number of things that are going to affect the readings you get between your multimeter and the analog ports via voltage divider.

Your Arduino analog ports have 8 bit resolution. Your multimeter most likely has better than 8 bit resolution.

Your multimeter has limits. It will have accuracy fingures given in both percentage and digits (if digital).

Your reference voltage may not be exactly 5v, and will vary slightly with the load on that supply line.

Your resistors have a tolerance. Are you using 5% or 1% resistors. They will also vary as they will have a temperature coefficient.

You are measuring the resistances too, which again will be within the measuring tolerances of your meter AND at a specific temperature that can change.

Combine all of these and what you are seeing is actually pretty good as far as I can see.

You're measuring with two different instruments, in different ways, with various things that have errors and tolerances.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 07:12 pm
@tack
Well I'm almost pleased with the results but since there's more that can be one to improve the results I would like to try them as well.


Read this http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino (http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino)

That seems very interesting however I don't really undertand what that does so I guess I'll have to study it a little more.
Title: Re: Voltage divider problem
Post by: oric_dan on Jan 02, 2013, 08:28 pm
From dhenry's comments, I don't understand what his "specific" objections are.

In general, straightforward ADC readings using a microcontroller like Arduino will have
probably 2-5% error, at best. For 5V, that's as much as 0.25V.

First off, the v.reg voltages are not spot-on 5V, but will have up to 5% error, depending
upon the specific v.regs being used. Secondly, whenever you use a voltage divider, the
resistors also have their own tolerances, ranging from below 1% for high-precision parts
[and who uses these] to 5% for most discrete parts. Therefore, any ADC measurements
will be off from the get-go. You can use a precision voltage-reference, but still must
use precision resistors in the voltage dividers for best results.

It seems to me that the majenko page has some good info to help deal with the first
problem, of v.reg tolerance, so I don't see d-h's trouble.
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 02, 2013, 08:56 pm

From dhenry's comments, I don't understand what his "specific" objections are.

In general, straightforward ADC readings using a microcontroller like Arduino will have
probably 2-5% error, at best. For 5V, that's as much as 0.25V.

First off, the v.reg voltages are not spot-on 5V, but will have up to 5% error, depending
upon the specific v.regs being used. Secondly, whenever you use a voltage divider, the
resistors also have their own tolerances, ranging from below 1% for high-precision parts
[and who uses these] to 5% for most discrete parts. Therefore, any ADC measurements
will be off from the get-go. You can use a precision voltage-reference, but still must
use precision resistors in the voltage dividers for best results.

It seems to me that the majenko page has some good info to help deal with the first
problem, of v.reg tolerance, so I don't see d-h's trouble.



Well there are pretty simple methods to deal with both the 'problems' you addressed. First it's possible with proper coding to have an arduino measure it's own exact Vcc voltage to gain the proper value to convert counts to voltage readings. The second problem is easily deal with by using a 10 turn pot (say 5K ohms) for the voltage divider and set it for the division ratio you desire using a DMM to verify that it's accurately set.

Now if either or both those are really needed or even desired depends on the application and it's accuracy requirements or assumptions.

Lefty

Code: [Select]

// Function created to obtain chip's actual Vcc voltage value, using internal bandgap reference
// This demonstrates ability to read processors Vcc voltage and the ability to maintain A/D calibration with changing Vcc
// Now works for 168/328 and mega boards.
// Thanks to "Coding Badly" for direct register control for A/D mux
// 1/9/10 "retrolefty"

int battVolts;   // made global for wider avaliblity throughout a sketch if needed, example a low voltage alarm, etc

void setup(void)
    {
     Serial.begin(38400);
     Serial.print("volts X 100");
     Serial.println( "\r\n\r\n" );
     delay(100);
    }
   
void loop(void)
    {
     battVolts=getBandgap();  //Determins what actual Vcc is, (X 100), based on known bandgap voltage
     Serial.print("Battery Vcc volts =  ");
     Serial.println(battVolts);
     Serial.print("Analog pin 0 voltage = ");
     Serial.println(map(analogRead(0), 0, 1023, 0, battVolts));
     Serial.println();   
     delay(1000);
    }

int getBandgap(void) // Returns actual value of Vcc (x 100)
    {
       
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
     // For mega boards
     const long InternalReferenceVoltage = 1115L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
        // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
 
#else
     // For 168/328 boards
     const long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
        // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
       
#endif
     delay(50);  // Let mux settle a little to get a more stable A/D conversion
        // Start a conversion 
     ADCSRA |= _BV( ADSC );
        // Wait for it to complete
     while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
        // Scale the value
     int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // calculates for straight line value
     return results;

    }

Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 09:14 pm
Thanks, that code looks very interesting.

Also a question regarding resistor tolerances. These are manufacturing tolerances right? The resistors themselves does not "change" their resistance over time, right? If so then this problem should be overcome by just measuring them and using that exact value in my code. The projects I make is for myself and will not be mass produced hence it's ok for me to measure each resistor manually.

Also I have some 1% and some 5% resistors, the former is much closer to their specified value, of course, but is there any other benefits to use these over the ones with lower tolerances? As I said I do measure them prior to installation.
Title: Re: Voltage divider problem
Post by: oric_dan on Jan 02, 2013, 09:46 pm
Resistors will change their values with temperature changes.

Quote
measure it's own exact Vcc voltage

What you mean by "exact"? I've seen nothing "exact" in this analog world. Also, on
further looking, the bandgap reference in the ATmega 328P datasheet is only specified
to within 10% <-- gakk!

Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 09:50 pm
Using that code I got the following when powered over the USB:

USB
Battery Vcc volts =  5.03 (serial printer)
Analog pin 0 voltage = 1.09 (serial printer)
Analog pin 0 voltage = 1.11 (using my meter)

3S external power
Battery Vcc volts =  4.94 (serial printer)
Analog pin 0 voltage = 2.84 (serial printer)
Analog pin 0 voltage = 2.89 (using my meter)

That's pretty good, next I'll try to use these values and update my code to see what I'll get. If I get a consistent difference <2% I guess I can live with that.
Title: Re: Voltage divider problem
Post by: MAS3 on Jan 02, 2013, 10:00 pm
No, someone already pointed this out (couldn't find this to quote).
Tolerances depend on multiple factors.
I guess the most known is temperature.
Having the resistors in the circuit, might for instance have them pick up ambient temperature as well as temperature possible generated by your cicuit (one could argue that this is also ambient temperature).
The temperature generated by the circuit probably differs after an hour running compared to right after starting.
You should take that in consideration.
Ofcourse you could try to compensate that by using an other sensor, measuring the resistor's temperature, or heat up the resistors to a known fixed temperature.
But you also need to know that these methods themselves will also have their own tolerances.

Ofcourse for the sake of learning this is all worth trying, but it's questionable if this will ever get you to read with very high accuracy.
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 02, 2013, 10:08 pm

Resistors will change their values with temperature changes.

Quote
measure it's own exact Vcc voltage

What you mean by "exact"? I've seen nothing "exact" in this analog world. Also, on
further looking, the bandgap reference in the ATmega 328P datasheet is only specified
to within 10% <-- gakk!

Well 'exact' means measuring the actual Vcc relative to the bandgap voltage. And as you said even the bandgap voltage has a tolerance but it usually a steady value within that tolerance range for each specific chip, and that is one parameter in the sketch that does have to be 'tweeked' to account for one's specific chips bandgap value. Once that is done then the sketch (see the comments) will measure any variation of the Vcc that can be used to compensate for the standard analogRead commands rather then just assume that Vcc is always an exact 5.000 which it presently does and we all know it's not necessarily so. I've seen .5vdc differences of Vcc on a standard arduino board just switching from USB power to external power and that is what my sketch was designed to address, a way to measure the real world Vcc the chip has applied to it to come up with a compensation value to use with analogRead statements.
Lefty


Title: Re: Voltage divider problem
Post by: retrolefty on Jan 02, 2013, 10:15 pm
Quote
Ofcourse for the sake of learning this is all worth trying, but it's questionable if this will ever get you to read with very high accuracy.


And that is particularly true when you are working with the limited 10 bit ADC of the arduino. If one jumps into using one of the many 12,14,16, or even 24 bit external I2C or SPI ADC chips then applying principles and practices of good design and calibration will give dividends in trying for the best possible accuracy. The arduino ADC is very useful and simple to use but one shouldn't mistake if for instrumentation quality measurements.

Lefty
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 02, 2013, 10:16 pm
Ok, I'll better use the ones I have with lower tolerances then.

Measurement doesn't need to be super exact. I'll use the arduino to measure battery voltage in my UAV ground station. So it's mostly to make sure I don't run out of battery. Because of that I'll try to keep it as simple as possible but also not introduce any unneccessary errors. I'll also measure a bunch of other stuff such a current sensor, clock, timer, signal strength and buzzers and lights to indicate warnings etc. Information will be presented mostly on a 20x4 LCD.

As you probably figured out I'm an arduino newbie and this is my first project, I'm learning as I go along and really appreciate all input.
Title: Re: Voltage divider problem
Post by: oric_dan on Jan 02, 2013, 10:16 pm
All in all, seems like too much variability going on here for OP to read really accurate
values. Especially, considering powering via USB versus using Vin and the v.reg. Probably
best to go with a good external voltage reference chip and 1% Rs, and call it a day.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 03, 2013, 12:13 am
Yes, maybe. Do you have some ideas on such chips that I could use with the Arduino?
Title: Re: Voltage divider problem
Post by: dhenry on Jan 03, 2013, 12:55 am
Put a small capacitor on the analog input pin. Anything from 0.1n to 1000n will work.

The issue is that your input resistance is too high.

Title: Re: Voltage divider problem
Post by: retrolefty on Jan 03, 2013, 12:58 am

Yes, maybe. Do you have some ideas on such chips that I could use with the Arduino?


Here are two nice ones that adafruit sells:

12 bit ADC https://www.adafruit.com/products/1083

16 bit ADC https://www.adafruit.com/products/1085

I've got a ADS1115 module from an e-bay firm and was quite impressed with it's features and capabilities.

Lefty
Title: Re: Voltage divider problem
Post by: oric_dan on Jan 03, 2013, 03:53 am
What are the resistor tolerances on those adafruit devices?

Where they say 12 or 16-bit "precision", they actually mean resolution, and not accuracy.
You might be able to discriminate 1 part in 4096 or 65536, but the absolute value may
still be off by 5%, or 204  parts in 4096, or 3276 parts in 65536.
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 03, 2013, 05:32 am

What are the resistor tolerances on those adafruit devices?

Where they say 12 or 16-bit "precision", they actually mean resolution, and not accuracy.
You might be able to discriminate 1 part in 4096 or 65536, but the absolute value may
still be off by 5%, or 204  parts in 4096, or 3276 parts in 65536.



The total word size (bits) determine the steps of resolution possible, the accuracy depends on the reference voltage used and of course the quality of the internal design of the chip. Both those models have an internal voltage reference as well as programmable gain settings, 4 single ended input channels or 2 differential input channels. The datasheet shows all the possible error tolerances and are impressive if you study ADC chips in the past. It's not a cheap chip but certainly a very powerful feature filled chip. Study the datasheet at your leisure.
http://www.ti.com/lit/ds/symlink/ads1115.pdf
Title: Re: Voltage divider problem
Post by: oric_dan on Jan 03, 2013, 07:34 am
Ah so, I misinterpreted the ckt, and thought those smt resistors had to do
with gain-setting or voltage dividers. However, the d/s uses the word resolution,
and doesn't confuse with precision.

http://en.wikipedia.org/wiki/Accuracy_and_precision

I guess the accuracy would be wrapped up in the values of,
Integral nonlinearity DR = 8SPS, FS = ±2.048V, best fit(2) 1 LSB
FS = ±2.048V, differential inputs ±1 ±3 LSB
Offset error
FS = ±2.048V, single-ended inputs ±3 LSB
Offset drift FS = ±2.048V 0.005 LSB/°C
Offset power-supply rejection FS = ±2.048V 1 LSB/V
Gain error(3) FS = ±2.048V at 25°C 0.01 0.15 %
FS = ±0.256V 7 ppm/°C
Gain drift(3) FS = ±2.048V 5 40 ppm/°C
FS = ±6.144V(1) 5 ppm/°C
Gain power-supply rejection 80 ppm/V
PGA gain match(3) Match between any two PGA gains 0.02 0.1 %
Gain match Match between any two inputs 0.05 0.1 %
Offset match Match between any two inputs 3 LSB
At dc and FS = ±0.256V 105 dB
At dc and FS = ±2.048V 100 dB
Common-mode rejection At dc and FS = ±6.144V(1) 90 dB


Title: Re: Voltage divider problem
Post by: retrolefty on Jan 04, 2013, 12:06 am
At the refinery I worked at before retirement we dealt with a lot of calibration issues and training. We tried to teach two different concepts to new instrumentation techs that started work there about what a quality measurement was and was not.

(http://upload.wikimedia.org/wikipedia/commons/3/38/Accuracy_and_precision.svg)
If a sensor can be proved to have good 'repeatablity' within it's rated 'accuracy' over it's full measurement range then you have a good sensor, stop fussing with it. Absolute accuracy is all about standards and what you are using as a reference to compare all other readings with. We stressed about repairs and adjustments that ended up with good repeatablity, rather then the circular fool's path of 'proving' that a given measurement is 'accurate'. So we used the word repeatablity to mean precision and didn't pretend to claim anything about accuracy.



On a few legal compliance measurements that local government required for us to have official calibration standards traceable to an approved 3rd party lab standards. For those we had to send out a few of our "bench standards instruments" such as a couple of bench DMM, bench deadweight tester (used for pressure measurements), bench electronic pressure sensor, etc to an 'approved' calibration laboratory which would test our standards, publish accuracy specs for them and put a dated seal on them good for one year. With these 'bench standards' we could then use them to compare our other measurement equipment when dealing with compliance measurement issues.

The word accuracy is a very overloaded word that can mean many different things to many different people. In principal it would seem to be a simple word, how close is a specific measurement to it's 'true' value. The problem is defining 'true' and trying to implement it in a meaningful, useful, and practical matter. Metrology can be an incredibly complex field. It's also incredibly expensive.  :D

http://en.wikipedia.org/wiki/Metrology


 
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 04, 2013, 12:29 am
Well, now I've tried to try a few things in my code and have some interesting results. However I'm not done and will test this in various temperatures next.

In the following code I use three methods. All of them uses the same voltage divider so changes due to resistor tolerances and temperature change will be the same for all.

Method 1 is using the code from retrolefty.

Method 2 is using the code from Scott Daniels. This one suggests a method of calibrating which I've done: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

Method 3 is just using 5V without bothering to know about reference voltage etc.

Powering using USB:
4.52V (measured using my meter)
4.44V (method 1) diff 1.8%
4.51V (method 2) diff 0.2%
4.45V (method 3) diff 1.5%

Powering usning 3S:
11.62V (measured using my meter)
11.46V (method 1) diff 1.5%
11.62V (method 2) diff 0.0%
11.61V (method 3) diff 0.1%

Code: [Select]
// Boopidoo Ground Station

#include <LiquidCrystal.h>

//LCD display pinout - YM2004A & OV1604A
//VSS   LCD pin 1     -  Connect to ground
//VDD   LCD pin 2     -  Connect to +5V
//V0    LCD pin 3     -  Connect to potentiometer
//RS    LCD pin 4     -  Arduino pin D07  
//RW    LCD pin 5     -  Connect to ground
//EN    LCD pin 6     -  Arduino pin D08
//DB4   LCD pin 11    -  Arduino pin D09
//DB5   LCD pin 12    -  Arduino pin D10
//DB6   LCD pin 13    -  Arduino pin D11
//DB7   LCD pin 14    -  Arduino pin D12
//ELA   LCD pin 15    -  Arduino pin D13
//ELK   LCD pin 16    -  Connect to ground
//LiquidCrystal lcd(7, NULL, 8, 9, 10, 11, 12);
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int screen_backlight = 13;                       //pin D13 will control the backlight
float voltage_battery1 = 0.0;                    //voltage from pin A0
float voltage_reference1 = 0.0;                  //reference voltage on the arduino 5V-rail
float voltage_battery2 = 0.0;                    //voltage from pin A0
float voltage_reference2 = 0.0;                  //reference voltage on the arduino 5V-rail
float voltage_divider = (6780.0+2720.0)/2720.0;  //((R1+R2)/R2)*voltage for voltage divider before pin A0

void setup() {
 pinMode(screen_backlight, OUTPUT);       //LCD Setup
 digitalWrite(screen_backlight, HIGH);    // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
 lcd.begin(20,4);                         // columns, rows.  use 16,2 for a 16x2 LCD, etc.
 lcd.clear();                             // start with a blank screen
}

//method 1
int getBandgap(void) // Returns actual value of Vcc  (x100)
   {    
     #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
       // For mega boards
       const long InternalReferenceVoltage = 1115L;  // Adjust this value to your boards specific internal BG voltage x1000
       // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
       // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
       ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
     #else
       // For 168/328 boards
       const long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage x1000
       // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
       // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
       ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
     #endif
     delay(50);  // Let mux settle a little to get a more stable A/D conversion
     // Start a conversion  
     ADCSRA |= _BV( ADSC );
     // Wait for it to complete
     while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
       // Scale the value
       int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // calculates for straight line value
       return results;
   }

//method 2
long readVcc() {
 // Read 1.1V reference against AVcc
 // set the reference to Vcc and the measurement to the internal 1.1V reference
 #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
   ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
 #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
   ADMUX = _BV(MUX5) | _BV(MUX0);
 #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
   ADMUX = _BV(MUX3) | _BV(MUX2);
 #else
   ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
 #endif  
 delay(2); // Wait for Vref to settle
 ADCSRA |= _BV(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
 long result = (high<<8) | low;
 result = 1.1 * (5.00/5.13) * 1023 * 1000 / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
 //result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
 return result; // Vcc in millivolts
}

void read_voltage() {
 //method 1 using internal reference voltage
 voltage_reference1=(float)getBandgap();
 voltage_battery1=map(analogRead(0),0,1023.0,0.0,voltage_reference1) * voltage_divider;
 
 //method 2
 voltage_reference2 = readVcc();
 voltage_battery2 = map(analogRead(0),0,1023.0,0.0,voltage_reference2) * voltage_divider;

}

void screen_print() {
 //printing method 1
 lcd.setCursor(0,0);
 lcd.print(voltage_reference1 / 100);
 lcd.setCursor(0,1);
 lcd.print(voltage_battery1 / 100);
 
 //printing method 2
 lcd.setCursor(10,0);
 lcd.print(voltage_reference2 / 1000);
 lcd.setCursor(10,1);
 lcd.print(voltage_battery2 / 1000);
 
 //printing original method not bothering with voltage reference
 lcd.setCursor(0,3);
 lcd.print(analogRead(0)*voltage_divider/1023*5);
}

void loop() {  
 read_voltage();
 screen_print();
}


Also, another issue is that some of the values seem to fluctuate on my LCD screen. This is especially apparent for method 2. Any suggestions on how to reduce this and make the value more stable? I've added a 470n capacitor between A0 and ground.
Title: Re: Voltage divider problem
Post by: dhenry on Jan 04, 2013, 01:58 am
Use smoothing:

Code: [Select]

volt_avg = alpha * read_volt() + (1-alpha) * volt_avg;


If you pick alpha to be 1/2^n, you can greatly simplify the math above.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 04, 2013, 02:55 pm
How do you mean? Sorry if I'm a little slow. :)

I tried testing in just below 0°C and now I just bothered to take notes on method 2 and 3 since 1 was too far off.

Powering using USB:
4.47V (measured using my meter)
4.45V (method 2) diff 0.4%
4.39V (method 3) diff 1.8%

Powering usning 3S:
11.55V (measured using my meter)
11.56V (method 2) diff 0.1%
11.54V (method 3) diff 0.1%

Now if it gets even colder I will try again but for now I pretty happy with method 2, it seems to be very consistent with my meter which was what I strived for in the start.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 09, 2013, 08:31 pm

Put a small capacitor on the analog input pin. Anything from 0.1n to 1000n will work.

When should I use a capacitor like this? On all analog inputs? I have some inputs that goes straight from a 0-5V source and thus doesn't need a voltage divider but do I still need the capacitor?

Also should I route both ground and + from this source? I also monitor its voltage so I guess there's a risk of ground loops.
Title: Re: Voltage divider problem
Post by: Docedison on Jan 09, 2013, 09:32 pm
Quote
Quote from: dhenry on January 02, 2013, 03:55:02 PM
Put a small capacitor on the analog input pin. Anything from 0.1n to 1000n will work.
When should I use a capacitor like this? On all analog inputs? I have some inputs that goes straight from a 0-5V source and thus doesn't need a voltage divider but do I still need the capacitor?

What I fail utterly to see here is how a component that can be anywhere in a 10,000 to 1 range could possibly be meaningful compensation for anything.

Bob
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 09, 2013, 09:40 pm

Quote
Quote from: dhenry on January 02, 2013, 03:55:02 PM
Put a small capacitor on the analog input pin. Anything from 0.1n to 1000n will work.
When should I use a capacitor like this? On all analog inputs? I have some inputs that goes straight from a 0-5V source and thus doesn't need a voltage divider but do I still need the capacitor?

What I fail utterly to see here is how a component that can be anywhere in a 10,000 to 1 range could possibly be meaningful compensation for anything.

Bob


The concept of adding a cap is if the output impedance of whatever is driving the analog input pin is higher then 10K ohms then the internal sample and hold cap may not have time to charge up to the true value of the applied voltage. Possible solutions are:

Buffer the applied voltage with a device that meets the output impedance recommendation of the AVR ADC

Do consecutive analogRead() commands on the same input pin and ignore the first reading obtained

Add a small cap that will accumulate the charge of the applied voltage and will be able to transfer that charge voltage faster to the internal sample and hold cap when the pin is read.

Lefty
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 09, 2013, 10:25 pm
Is there a risk when adding a cap when it's not really neccessary?
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 09, 2013, 10:38 pm

Is there a risk when adding a cap when it's not really neccessary?


Nothing damaging, but if high speed sampling is being done on higher frequency type analog signals the cap may act as a low pass filter not giving as accurate a sample as it would without it.

Lefty
Title: Re: Voltage divider problem
Post by: dhenry on Jan 10, 2013, 12:17 am
Quote
Is there a risk when adding a cap when it's not really neccessary?


Yes.

Title: Re: Voltage divider problem
Post by: lemming on Jan 10, 2013, 01:39 am
Quote
Of course I'd like it to be even better so I guess I should now start investigating this VREF that I guess is how the arduino close the arduino 5V supply is to 5V. Is that correct? Is there a prefered method of doing this?


I would use a 4.7 volt zener/resistor combination to provide a 4.7v reference into Aref. (This could be fed off the power either pre or post regulator, but may be better pre regulator) Decouple Aref with a capacitor (<1uF) to ground. Measure exact voltage from the zener for more precision  for your calculations. Or you could use a precision voltage reference chip.

For the resistor divider into A0 I would use a 10k  trimmer (e.g. 25 turn type for finer adjustment) across the battery terminals; any more and your may get noise, any lower and you will be burning up too much power from your batteries. Decouple the input to A0 with .1uF or greater to ground. Tune to give 4.7 volts output for the maximum expected voltage from the LiPos.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 10, 2013, 08:38 am

Quote
Is there a risk when adding a cap when it's not really neccessary?


Yes.



This is my current breadboard. I drew it so it shows the connectors I plan to use. The caps I'm talking about are the ones that are placed for each analog input.

Title: Re: Voltage divider problem
Post by: dhenry on Jan 10, 2013, 01:21 pm
Quote
The caps I'm talking about are the ones that are placed for each analog input.


I was talking about the same caps too.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 10, 2013, 02:20 pm
Ok, so I should be able to remove these without having signal problems? If they don't do anything good then it will simplify my wiring and PCB-shield a lot.
Title: Re: Voltage divider problem
Post by: tack on Jan 10, 2013, 05:42 pm
Also, don't forget that the act of taking a measurement actually affects the circuit.

A DC Ammeter should have a low resistance, close to zero, but crucially NOT zero. Same, but opposite, for a DC Voltmeter; it should have high resistance, theoretically infinite, but it will just be very high.

This means that you never read the true value. Adding an ammeter will put a little more resistance in series, meaning a little less current flowing. Adding a voltmeter will add a very large resistance in parallel, meaning a little more current flowing, so more voltdrop in the series part of the circuit, than without it.

The effect will be dependant on the existing conditions of the circuit, in relation to the connection point, and value of resistance , of your test instrument. You can't take a measurement without affecting what you are measuring.

Biggest errors will be measuring current when you already have a low resistance circuit, or measuring voltage when you have a very high resistance circuit.

Using a resistor divider network and then measuring voltage at a midpoint will put the voltmeter in parallel with one of the resistors and mean the combined resistance value is now lower; 1/(1/R1+1/Rmeter). This will change your divider ratio and the voltage at that point to a lower volt drop than would be present without the meter connected. Therefore, the value with and without your meter connected WILL be different anyway, dependent on the values in the circuit and that of your meter.

Add on the errors mentioned previously and you will NEVER measure exactly the same with and without the meter connected, unless you actually had an infinite impedance voltmeters.

You could well be chasing ghosts here, by trying to get a value that is the same (or as close as you seem to want it), with all the factors that are affecting the measurement of that value via different methods.
Title: Re: Voltage divider problem
Post by: tack on Jan 10, 2013, 05:54 pm
As an example, imagine:-

Your voltmeter has a resistance of 10 Megohm

You have a 12V supply with 2 x 10 Megohm resistors across it (R1 and R2), making a 1:1 divider. Calculations tell you that there will be a 6v volt drop across each one, so you'll measure 6v at the mid point with reference to Gnd, or -6v with reference to +12v.

Now, you take your voltmeter and connect it across R2 and Gnd to measure the output voltage of your divider. This puts a 10Megohm resistance in parallel with R2, meaning you now have an effective series resistance in your circuit of 10 Megohm (R1) and 5 Megohm (R2 + Rmeter paralleled), totalling 15 Megohm. This is now a 2:1 divider.

So, you expect to measure 6v at the midpoint, but you actually measure 4v, an 'error' of -33% ;-)

This is without considering the resolution and accuracy of the instrument itself, which will mean that measured 4v could be up or down by a few percent too.

When testing and measuring it is important to understand the effect your instruments can have on what you are measuring. I regularly test for both extremely low and extremely high resistances in high voltage circuits. This is why I have specific instruments for each application. A micro-ohmeter for injecting 100A to measure micro-ohms and 40kV+ test sets for measuring Gigohms and Terraohms and leakage currents in micro-amps at, say, 25kV.
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 10, 2013, 06:47 pm
Well maybe I'm just lucky but I'm actually very happy with the measurements which are within 0.01V from what my volt-meter measures. This has now been tested between 4-12V and between -5 to +25 degrees C. If this is consistent I don't need the results to be any better in this project.

The measured voltage on my Arduino doesn't seem to change noticably when I add a volt-meter to the circuit and vice versa.

Now my problem is making the PCB which was harder then I imagined... a real puzzle. :)
Title: Re: Voltage divider problem
Post by: retrolefty on Jan 10, 2013, 07:32 pm

Well maybe I'm just lucky but I'm actually very happy with the measurements which are within 0.01V from what my volt-meter measures. This has now been tested between 4-12V and between -5 to +25 degrees C. If this is consistent I don't need the results to be any better in this project.

The measured voltage on my Arduino doesn't seem to change noticably when I add a volt-meter to the circuit and vice versa.

It's all about the output impedance of whatever you are wiring to the analog input if the 10/11 megohm input impedance of your DMM will effect the reading or not. As the analogRead() command is optimized (and recommended) for reading a voltage source with an output impedance of 10K ohms or less, a DMM reading at the same time will have no effect noticeable.

Lefty

Now my problem is making the PCB which was harder then I imagined... a real puzzle. :)
Title: Re: Voltage divider problem
Post by: Boopidoo on Jan 11, 2013, 10:58 am
What if I removed the caps on RX1 & RX2-inputs and placed resistors in series with the ground (to eliminate ground loops) or eliminated the ground for RX1&2 inputs altogether.

The ground on the RX1&2 is from two devices that is powered from the 12V-source which I am monitoring so that ground is already connected.
Title: Re: Voltage divider problem
Post by: dhenry on Jan 11, 2013, 01:22 pm
Quote
2 x 10 Megohm resistors across it (R1 and R2), making a 1:1 divider


That type of dividers are basically unusable for an avr's adc.
Title: Re: Voltage divider problem
Post by: tack on Jan 11, 2013, 03:03 pm

Quote
2 x 10 Megohm resistors across it (R1 and R2), making a 1:1 divider


That type of dividers are basically unusable for an avr's adc.


It was a hypothetical example to show the effect of a test instrument on the circuit being tested, in as simple terms as possible. The values were simply comparable to typical resistance of a voltmeter and values where any calculations were either simple enough to do in your head, or just intuitive to anyone with a little experience.
Title: Re: Voltage divider problem
Post by: dhenry on Jan 11, 2013, 03:09 pm
Even in those cases (of extreme resistance), you can still make it work if you are prepared for some compromises.