analogicas-mas-precisas

Entradas analógicas más precisas midiendo Vcc en Arduino

En esta entrada vamos a ver una pequeña curiosidad que nos va a permitir obtener mediciones de nuestras entradas analógicas más precisas.

Es algo poco conocido que algunos modelos de Arduino pueden medir su propio voltaje al que están alimentados. Esto es válido para los modelos de Arduino basados en procesadores AVR 168 y 328.

Para ello se emplea la referencia de 1.1V, que viene incorporada en la mayoría de modelos de Arduino. Podemos emplear el ADC de Arduino para medir esta referencia y, por interpolación, medir la tensión a la que realmente está alimentado Arduino.

long readVcc() {
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  
  long result = ADCL;
  result |= ADCH << 8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(readVcc(), DEC);
  delay(1000);
}

Donde el valor 1126400L corresponde a 1.1 x 1024 x 1000. Para tener una precisión adecuada debemos medir la referencia 1.1V de nuestro Arduino con un polímetro para calibrar este valor. Este valor es independiente de Vcc, por lo que sólo hay que calibrar una vez.

¿Para qué sirve esto? Principalmente para rectificar las mediciones de ADC y, así, conseguir unas entradas analógicas más precisas que las que obtendremos sin esta rectificación.

El ADC toma como referencia el Vcc de Arduino. Por tanto, cualquier variación en la tensión de alimentación se traduce en un error proporcional en la medición analógica.

Midiendo la tensión de alimentación real, podemos corregir las posibles desviaciones debidas a variaciones en Vcc.

long readVcc()
{
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2);
  ADCSRA |= _BV(ADSC);
  while (bit_is_set(ADCSRA, ADSC));
  
  long result = ADCL;
  result |= ADCH << 8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  float vcc = readVcc() / 1000.0;
  float voltage = (analogRead(A0) / 1024.0) * Vcc;

  Serial.println(voltage);
  delay(1000);
}

Un pequeño truquito que nos puede ser de utilidad cuando necesitemos realizar lecturas analógicas más precisas en Arduino, cuando la necesidad de precisión justifique el incremento de código.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full