Tutorial · Principiante · 30 min
Lectura de tensiones analógicas: referencias ADC y divisores
analogRead devuelve una proporción, no una tensión. Elige una referencia que no se hunda, dimensiona un divisor y construye un monitor de batería fiable.
Introducción
analogRead() es la función más amable de un Arduino y una de las más silenciosamente engañosas. Devuelve un número entre 0 y 1023, todo el mundo trata ese número como una tensión, y la mayoría de las veces nada sale mal.
Sale mal en un robot, porque un robot tiene motores, y los motores mueven justo aquello contra lo que se mide ese número.
analogRead devuelve una proporción
El ADC no mide voltios. Compara su entrada con una referencia e informa la proporción:
reading = 1023 × V_in / V_ref
En un Arduino Uno V_ref por defecto es AVCC —el riel de 5 V de la placa. Así que analogRead() en realidad responde «¿qué fracción del riel de 5 V es esto?», y convertirlo a voltios multiplicando por 5/1023 solo es correcto mientras el riel esté exactamente a 5 V.
Ya sabes que no lo está, siempre que los motores están en marcha.
La referencia es el error
Cablea una batería a través de un divisor a A0 y mira el número mientras arrancan los motores.
Un corte por batería baja construido sobre el primer diseño hace lo contrario de su trabajo: cuanto más trabaja el robot, más sana parece la batería. Y el fallo es silencioso, porque cada lectura individual es una proporción perfectamente válida.
La solución es una referencia que no se mueva. El ATmega328P tiene una referencia bandgap de 1,1 V integrada:
analogReference(INTERNAL); // 1.1 V on an Uno; INTERNAL1V1 on a Mega
analogRead(A0); // discard — the reference needs a moment to settle
Desecha siempre la primera lectura tras cambiar de referencia. La referencia interna y el condensador de entrada necesitan tiempo, y la primera muestra se toma antes de que lo hayan tenido.
Dimensionar el divisor
La referencia ahora es de 1,1 V y tu pack es de 8,4 V, así que el divisor tiene que dejar el tope del rango justo por debajo de la referencia:
V_adc = V_pack × R2 / (R1 + R2)
Con R1 = 68 kΩ y R2 = 10 kΩ la proporción es 0,128, así que un pack lleno de 8,4 V presenta 1,077 V —justo por debajo de la referencia, usando casi toda la escala. Tres números que conviene comprobar en cualquier divisor que diseñes:
| Comprobación | Este divisor | Por qué |
|---|---|---|
| Tope del rango frente a referencia | 1,077 V frente a 1,1 V | Por encima de la referencia y recorta en plano |
| Corriente en reposo | 108 µA | Consume 2,6 mAh al día —despreciable frente a 2000 mAh |
| Impedancia de salida (R1∥R2) | 8,7 kΩ | Mantén por debajo de ~10 kΩ, ver abajo |
Compáralo con la versión ingenua —un divisor 20 kΩ/10 kΩ leído contra el riel de 5 V. Pone un pack lleno en 2,80 V, que son 573 cuentas de 1023 posibles, y usa 164 cuentas en todo el rango 6,0–8,4 V del pack frente a las 286 del mejor diseño. Casi el doble de resolución, por las mismas dos resistencias y una línea de código.
La resolución no es la precisión
Diez bits contra una referencia de 5 V son 4,88 mV por paso; contra la referencia de 1,1 V son 1,07 mV. Ninguno de los dos números es tu precisión.
Lo que realmente te limita:
- Tolerancia de la referencia. El bandgap es nominalmente 1,1 V y varía unos pocos puntos porcentuales entre chips. Eso es un error fijo de escala, así que mídelo una vez por placa: aplica una tensión conocida, lee las cuentas y despeja la referencia real. Guarda esa constante. Esto es un paso de calibración, no un refinamiento opcional.
- Ruido. La alimentación de un robot es ruidosa, y promediar es la respuesta barata. Promediar N muestras reduce el ruido aleatorio en √N —16 muestras son 4× más silenciosas, un bit extra de resolución utilizable. No hace nada contra un error de escala.
- Impedancia de fuente. El ADC carga un pequeño condensador de muestreo y retención a través de lo que tenga conectado. Una fuente de alta impedancia no puede llenarlo en el tiempo permitido, y el residuo del canal leído antes sigue ahí dentro.
Eso último produce un error distintivo que merece nombre.
Canales que leen como sus vecinos
Lee A0 y A1 por turnos con fuentes de alta impedancia y cada lectura es arrastrada hacia la anterior. Barre un potenciómetro en A0 y mira cómo A1 se mueve en simpatía. Nada está mal cableado.
Dos soluciones, y puedes usar ambas:
int readSettled(uint8_t pin) {
analogRead(pin); // charge the sample-and-hold on this channel
return analogRead(pin); // then take the one you keep
}
Leer dos veces y descartar la primera da al condensador una segunda ventana de muestreo para alcanzar la nueva tensión. La otra solución es bajar la impedancia de fuente —por eso el divisor de arriba usa 68 kΩ/10 kΩ en lugar de los 100 kΩ/100 kΩ que parecen más ordenados y dan una impedancia de salida de 50 kΩ.
Dónde aparece esto en un robot
- Monitorización de batería, como arriba —y es lo que hace un corte por baja tensión lo bastante fiable para proteger un pack de Li-ion.
- Sensores de línea analógicos. Un array de reflectancia IR da un valor continuo por sensor, que es lo que permite a un seguidor de línea calcular una posición suave en lugar de una bandera izquierda/derecha. Esos sensores se leen contra el mismo riel que los motores están hundiendo, que es una razón por la que la calibración de un seguidor de línea deriva a medida que se vacía la batería.
- Medición de corriente, una resistencia shunt o sensor Hall cuya salida es una tensión.
- Potenciómetros como mandos de ajuste, que es la forma más amable de ajustar una ganancia PID sin reprogramar.
- No para el sensor de 5 V de una placa de 3,3 V. Un ESP32 o una Raspberry Pi necesita el divisor por protección, no solo por rango.
Cuando algo sale mal
| Síntoma | Normalmente |
|---|---|
| La lectura de batería sube cuando arrancan los motores | Referenciada al riel que se hunde; usa INTERNAL |
| Lectura clavada en 1023 | Entrada por encima de la referencia —proporción del divisor demasiado alta |
| Un canal repite el eco del leído antes | Impedancia de fuente demasiado alta; lee dos veces y descarta |
| Las lecturas saltan decenas de cuentas | Ruido de alimentación; promedia, y revisa los rieles de alimentación |
| Tensión siempre desviada unos pocos puntos porcentuales | Referencia interna sin calibrar —mídela una vez |
Primera lectura tras analogReference() errónea |
Esperado; descártala |
| La calibración del sensor de línea deriva al vaciarse la batería | Lecturas referenciadas al riel en un riel que cae |
| Solo se usa el 15 % del rango | Divisor dimensionado para 5 V leyendo contra 1,1 V |
La regla que evita la mayor parte de esto: decide cuál es tu referencia antes de decidir nada más. Cada número que te da el ADC es relativo a ella, así que una referencia que se mueve hace que cada lectura cuente dos cosas a la vez.
Explora el grafo
Forma parte de estos montajes
Proyectos y rutas de aprendizaje que incluyen este tutorial.
Lecturas adicionales