LPC2148 ADC problem with voltage divider for battery

adcarmvoltage divider

edit: solution found with our new board revision; outside of careless mistakes, buffering the signal with an op amp seems to have resolved the issue (as suggested by Joshua below).

I am working with a custom PCB using the ARM LPC2148. I'm trying to measure the battery voltage, which can be up to 4.2V or so, by using a voltage divider. However, using different resistors causes huge changes in the accuracy of ADC readings. Why is this?

Details:

I set the power supply to 3.0 V and hooked it up to an ADC pin, and got a reading of 2.987V, which is accurate enough for our use and shows that everything is working.

Using the voltage divider we built into the PCB with 47K and 100K resistors, the readings from the ADC vary in a non-linear manner — I mean, not by a simple scalar factor — (data below).

I built a voltage divider using 5% 10K 1K and 100K resistors (divides by 11 101), and took a reading on the ADC. Software showed 0.029V, or 0.319V after being scaled according to the voltage divider. This is obviously wrong, but the reason we're using large resistor values is that it limits the current draw; the power supply is showing less than 1mA being used.

I built another voltage divider using much smaller 5% resistors, of values 4.7 and 8.2 (divides by 2.745), and took a reading on the ADC. Software showed a value of 1.071V, or 2.940V after being scaled according to the voltage divider. This is obviously much better than the other voltage divider, and we could probably use this. However, the current draw is 228mA, which is unacceptable. It seems that the path forward is to redesign the board to use smaller resistor values and to hook the divider up to a transistor to limit current draw.

ADC Vref is 2.5V.

My question: why the huge change in accuracy from the different resistors?

Data:

power supply: voltage coming from the power supply to the board
input voltage: voltage reading taken at the voltage divider
voltage after divider: the voltage reading taken at the output of the voltage divider
raw from ADC: value from the ADC; average of a few readings
scaled by divider: value obtained by taking the ADC reading and scaling by the voltage divider (the first row is 0.28/0.32, etc)
voltage divider: resistor values for the current data set
+---------------+---------------+-----------------------+--------------+-------------------+-----------------+
| using the voltage divider on the board (47K / 47K + 100K)                                                  |
|                                                                                                            |
| power supply  | input voltage | voltage after divider | raw from ADC | scaled by divider | voltage divider |
|         3.8   |         3.80  |                 1.22  |        0.28  |             0.87  |      47,150  Ω  |
|         3.7   |         3.70  |                 1.18  |        0.29  |             0.89  |     100,000  Ω  |
|         3.6   |         3.60  |                 1.15  |        0.30  |             0.92  |         0.320   |
|         3.5   |         3.50  |                 1.12  |        0.31  |             0.95  |                 |
|         3.4   |         3.40  |                 1.09  |        0.32  |             1.00  |                 |
|         3.3   |         3.30  |                 1.06  |        0.33  |             1.04  |                 |
|         3.2   |         3.20  |                 1.02  |        0.35  |             1.08  |                 |
|         3.1   |         3.10  |                 0.99  |        0.37  |             1.15  |                 |
|         3.0   |         3.00  |                 0.96  |        0.39  |             1.21  |                 |
+---------------+---------------+-----------------------+--------------+-------------------+-----------------+
| using an external voltage divider (4.7 / 4.7 + 8.2)                                                        |
|                                                                                                            |
| power supply  | input voltage | voltage after divider | raw from ADC | scaled by divider | voltage divider |
|         3.8   |         3.79  |                 1.39  |        1.37  |             3.76  |          4.7 Ω  |
|         3.7   |         3.69  |                 1.35  |        1.33  |             3.66  |          8.2 Ω  |
|         3.6   |         3.59  |                 1.31  |        1.30  |             3.56  |         0.364   |
|         3.5   |         3.50  |                 1.28  |        1.26  |             3.47  |                 |
|         3.4   |         3.40  |                 1.24  |        1.23  |             3.37  |                 |
|         3.3   |         3.30  |                 1.21  |        1.19  |             3.27  |                 |
|         3.2   |         3.20  |                 1.17  |        1.16  |             3.17  |                 |
|         3.1   |         3.10  |                 1.13  |        1.12  |             3.07  |                 |
|         3.0   |         3.00  |                 1.10  |        1.09  |             2.98  |                 |
+---------------+---------------+-----------------------+--------------+-------------------+-----------------+
| using an external voltage divider (10K / 10K + 100K)                                                       |
|                                                                                                            |
| power supply  | input voltage | voltage after divider | raw from ADC | scaled by divider | voltage divider |
|         3.8   |         3.80  |                 0.35  |        0.35  |             3.81  |       9,820  Ω  |
|         3.7   |         3.70  |                 0.34  |        0.34  |             3.71  |      98,400  Ω  |
|         3.6   |         3.60  |                 0.33  |        0.33  |             3.63  |         0.091   |
|         3.5   |         3.50  |                 0.33  |        0.32  |             3.53  |                 |
|         3.4   |         3.40  |                 0.32  |        0.31  |             3.43  |                 |
|         3.3   |         3.30  |                 0.31  |        0.30  |             3.33  |                 |
|         3.2   |         3.20  |                 0.30  |        0.29  |             3.23  |                 |
|         3.1   |         3.10  |                 0.29  |        0.28  |             3.13  |                 |
|         3.0   |         3.00  |                 0.28  |        0.28  |             3.04  |                 |
+---------------+---------------+-----------------------+--------------+-------------------+-----------------+

Best Answer

By your values, I have to assume that you are measuring off of the 10kOhm resistor on the bottom. I would hazard a guess that your 10kOhm resistor is a little high and the 100kOhm resistor is a little low. This would mean if your 10kOhm resistor is taking more of the voltage in the voltage division than expected.

There are a few problems at work here.

  1. The first is the resistor value error. Ohm's Law: V=I*R. So if there is 5% error in R, then for a constant I, there will be a %5 error in the expected value of V. The %error from resistor tolerances are the maximum +/- error. So in reality, there could be a resistor with +5% error and other with -5% error. So there is a much larger possible range in output voltages for a constant current.

    • This can be eliminated by either hard-coding the real resistances in software or adding a reference voltage that is more accurate than the resistor or A/D quantization error. This reference voltage would be used to get the real resistance values as the A/D sees them.
  2. A/Ds can have an offset error. This really has to be calibrated out. Some A/Ds have this built in.

  3. A/Ds also have quantization error. So if a voltage falls between two consecutive quantization levels, it will have to be rounded to one of those two, introducing error. There are ways of increasing the number of bits for an A/D by oversampling and averaging blocks of samples into one sample.

There are other errors that could be at work, but those three are the main ones I have run into. If the A/D is fairly linear, then measuring two accurate voltages with the A/D circuitry would let you build an affine linear equation to correct the data. This builds off of the problems in 1 and 2.

A/Ds can appear linear, but end up being very nonlinear at a particular range. I have heard of some implementations using a look-up table to correct the nonlinear behavior. But that is getting a little beyond your current problems.

Edit: One more item. It is a good idea to buffer your analog signals to the A/D. It does a few things, like add another device to protect the microcontroller, and limit any possible transient sampling behavior from the A/D go into the analog signal.