Estoy midiendo voltajes de hasta 20 V con mi MCU ATmega2650 (ADC de 10 bits).
Estoy usando una referencia de voltaje de precisión de 5V (LT1021 - 0.05%).
Los divisores de voltaje están configurados con resistencias Panasonic del 1%.
Vcc > 10kOhm- > Measure- > 3.3kkOhm- > GND.
Relación de división: 3.3 / 13.3 = 0.248
Lo que he notado son los siguientes errores cada vez mayores al medir voltajes más grandes:
Vmeas ADC Err(%)
3.05 152 -0.013382929
4.09 205 -0.0075968
5.02 253 -0.002075695
6.08 308 0.003057305
7.07 359 0.0054141
8.07 410 0.00595279
9.07 461 0.00637229
10.02 510 0.007764232
11.05 563 0.008777353
12.05 615 0.01046932
13.05 665 0.008925735
14.05 717 0.010366242
15.06 769 0.010955198
16.05 820 0.011495804
17.07 872 0.011368671
18.06 923 0.011826103
19.04 973 0.011739502
19.51 998 0.01271154
19.94 1020 0.012715509
¿Puede alguien explicar qué está causando esa no linealidad?
¿Alguna sugerencia sobre matemáticas para estimar esto (características de ADC en lugar de ajuste múltiple)? Cualquier referencia a modelos matemáticos ayudaría.
EDITAR - errores en todo el rango de voltaje:
La metodología de cálculo:
#define PSU_ANALOG_CHANNELS 3
#define PSU_ANALOG_MEASURES 5
#define PSU_ANALOG_MEASURE_DELAY 1
//apply vRef to each pin to measure post-divided ADC reading
const int psu_adc_corr[PSU_ANALOG_CHANNELS] = {250,251,251};
int psu_volts_raw[PSU_ANALOG_CHANNELS];//stores ADC readings
float psu_volts[PSU_ANALOG_CHANNELS] = {0}; //stores final values
float mvAdc[PSU_ANALOG_CHANNELS]; //stores mV per each ADC-channel (to avoid division)
void calcMvADC(){
for (int i=0; i<PSU_ANALOG_CHANNELS; i++) {
mvAdc[i] = 5.0 / psu_adc_corr[i];
}
}
//returns averaged reading for each ADC channel
int readAnalog(int ch) {
int val = 0;
for (int i=0; i<PSU_ANALOG_MEASURES; i++) {
val += analogRead(ch);
delay(PSU_ANALOG_MEASURE_DELAY);
}
return val/PSU_ANALOG_MEASURES;
}
void readADC() {
for (int i=0; i<PSU_ANALOG_CHANNELS; i++) {
psu_volts_raw[i]=readAnalog(i);
}
}
/*
>6 <=7 : -1.1%
>7 <=9: -1.14%
>9 <=13: -1.25%
>13 -1.7%:
*/
float corrVoltage(float V) {
if (V<6) return V;
if (V>6 && V<=7) return V*0.989;
if (V>7 && V<=9) return V*0.9886;
if (V>9 && V<=13) return V*0.9875;
if (V>13) return V*0.983;
return V;
}
void calcVoltages() {
for (int i=0; i<PSU_ANALOG_CHANNELS; i++) {
psu_volts[i] = psu_volts_raw[i] * mvAdc[i];
psu_volts[i] = corrVoltage(psu_volts[i]);
}
}
void setup (){
analogReference(EXTERNAL);
calcMvADC();
Serial.begin(115200);
}
void loop (){
readADC();
calcVoltages();
for (int i=0; i<PSU_ANALOG_CHANNELS; i++) {
Serial.println(psu_volts[i]);
}
delay(500);
}