Voltage divider problem

oric_dan(333):
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.

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.

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

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.


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. :smiley:

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%

// 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.

Use smoothing:

 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.

How do you mean? Sorry if I'm a little slow. :slight_smile:

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.

dhenry:
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.

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

Docedison:

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

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

Boopidoo:
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

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

Yes.

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.

dhenry:

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.

The caps I'm talking about are the ones that are placed for each analog input.

I was talking about the same caps too.

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.

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.

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% :wink:

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.

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. :slight_smile:

Boopidoo:
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. :slight_smile: