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.
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.
A/Ds can have an offset error. This really has to be calibrated out. Some A/Ds have this built in.
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.
Take a peek at the input impedance of the device vs the values of the resistors in your divider. You might be pullng down your input.
You say that you've got a "straightforward voltage divider" going into your ADC. I'm suggesting that it might be a bit less straightforward than you think.
In an ideal world, you assume that the resistance of an analog input (or any amplifier) is infinite. In fact, the input should be considered to be a finite resistance. On a very good ADC, like the type you would expect to see on a National Instruments card, the input impedance is in the MegaOhm range. On typical microcontrollers, though, its much lower, usually around 10 kiloohms.
Let's assume, your straightforward voltage divider is 5v going through a 10K resistor in series with a 20K resistor, and your voltage at the ADC would be 5V*20Kohms/30Kohms, or 5V*0.66=3.35V. In reality, because the input impedance of your device is 10K, that 20K resistor is really 20K in parallel with the device's 10K, or 6.7K!!! Now what the ADC actually sees is 5V*(6.7k/16.7K), or 5V*0.40, or 2V.
Easiest way to tell what's going on: with the circuit on, use a multimeter to measure the voltage at the ADC, instead of assuming the simple voltage divider is acting the way you think it is.
In fact, an STM32 datasheet on page 124 says the input impedance of the ADC is 50K, suggesting that your voltage divider is in the neighborhood of a 50K in series with a 100K from the numbers you've given, if this is in fact the issue.
Try to keep your voltage divider resistors on the order of 1k to 2k to avoid this problem, or buffer your analog input with an op amp configured as a voltage follower.
Correction: looks like the actual input impedance, at least of the device in the datasheet I randomly chose, is 6K, or maybe even a funky function of sampling frequency (like a switched cap function) -- use the numbers at your own risk, but I think you're having a low input impedance problem.
Best Answer
V = (R/4096)Vref(82K + 5.6K)/5.6K
Which gives me about 10.6V, which I suspect is too far off from 12.0V to be explained by even 5% resistor tolerances and a few percent Vref tolerance.