This is driving me nuts.
I am trying to measure battery voltage. I have a voltage divider with 47K to source, and 20K to ground.
I have a 2.2uF cap to ground to filter any ripple.
What I am seeing is very high non-linearity.
If I set the max voltage to 16.75 (which is what is calculated from the divider) I get voltages that are too low. I get readings of 706 from the pin, which then multiplies out to 11.54V, for source voltages of 13.04.
If I change the max voltage to somewhere around 18.90 in order to get a correct reading at 13V, I get readings that are too low at 12V. The discrepancies can be as high as 0.5V, and the discrepancies don't seem to be constant.
If I disconnect everything, I get a reading of 0, which is correct.
I've tried reading the pin once, many times and averaging, and none of it makes any difference.
Here's the code, boiled down to just the essentials.
What am I doing wrong?
#include <inttypes.h>
unsigned int readVcc() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1125300L / result; // Back-calculate AVcc in mV
return result;
}
unsigned int
analogRead100 (byte reg)
{
unsigned long analog = 0;
static int skip=1; // I've tried various values, up to 8
static long samples=1; // I've tried various values, up to 128
static int msec=2;
// throw away the first few readings
for (byte ai = 0; ai < skip; ai++)
analogRead (reg);
if(msec > 0) delay(msec);
for (byte ai = 0; ai < samples; ai++)
{
analog += analogRead (reg);
}
return analog / samples;
}
unsigned int getVoltage (unsigned int raw)
{
// 1675 is the max voltage from the divider
// 20K to ground
// 47K to source
return (1675l * raw) / 1024l;
}
void
setup(void) {
Serial.begin (9600);
}
void
loop(void) {
unsigned int V, Vraw;
delay(1000);
Vraw = analogRead100 (A0);
V = getVoltage(Vraw);
Serial.print("Voltage ");
Serial.print(Vraw);
Serial.print(" ");
Serial.println(V);
Serial.print("Vcc ");
Serial.println(readVcc());
}