01 · Punto de partida
Del concepto al periférico
Ya sabés calcular el escalón de un conversor, su error y la frecuencia de muestreo que necesita una señal. Falta ver cómo se manda a un ADC real hacer su trabajo. Como todo periférico del ATmega328P, se configura escribiendo registros (tema 9), se dispara con un bit, avisa con una bandera y entrega el resultado en otros registros. La novedad está en las decisiones analógicas que acompañan a esa configuración: contra qué referencia medir, con qué velocidad de reloj y qué hacer para que el ruido no arruine los 10 bits.
La plataforma es la de siempre: ATmega328P a 16 MHz. Las ideas valen para otros microcontroladores (SAR de 12 bits en un STM32, ADC de 12 bits en el ESP32), con distintos registros pero los mismos compromisos.
02 · Cómo convierte
Arquitectura: aproximaciones sucesivas
El ADC del ATmega328P es de tipo aproximaciones sucesivas (SAR, successive approximation register). La idea es la misma de una búsqueda binaria. Un DAC interno genera una tensión de prueba; el comparador dice si la entrada está por encima o por debajo; el registro SAR conserva o descarta el bit probado y pasa al siguiente. Empieza por el bit más pesado (la mitad del rango) y termina por el menos pesado: un bit por ciclo de reloj del ADC, 10 comparaciones para 10 bits.
Es un diseño económico: un comparador y un DAC en lugar de 1023 comparadores en paralelo (conversor «flash»). El precio es la velocidad, porque la conversión es secuencial, y una exigencia de estabilidad: la entrada debe quedar quieta mientras dura la búsqueda. De eso se encarga el circuito de muestreo y retención, que carga un capacitor de unos 14 pF a través de una resistencia interna y lo desconecta. La herramienta 2 del laboratorio muestra paso a paso esta búsqueda.
Hay un solo conversor. El multiplexor elige qué pin se le conecta, de manera que dos señales no se pueden convertir a la vez: se miden una tras otra.
03 · Qué se mide
El multiplexor y los canales
Los cuatro bits MUX3:0 del registro ADMUX eligen la entrada:
| MUX3:0 | Entrada | Pin en el Arduino Uno |
|---|---|---|
| 0000 a 0101 | ADC0 a ADC5 | A0 a A5 (PC0 a PC5) |
| 0110 y 0111 | ADC6 y ADC7 | no existen en el Uno (DIP); sí en Nano y Mini (TQFP) |
| 1000 | Sensor de temperatura interno | sin pin; solo con referencia de 1,1 V |
| 1110 | Referencia de 1,1 V | sin pin; sirve para medir Vcc |
| 1111 | GND (0 V) | sin pin; sirve para comprobar el offset |
Dos detalles importantes. Primero, cada pin analógico es también un pin digital (PC0 a PC5): el registro DIDR0 permite apagar el buffer digital de un pin que se usa como entrada analógica, lo que ahorra consumo y reduce el ruido (sección 9). Segundo, el ATmega328P mide solo tensiones respecto de masa («un solo extremo»); los modelos con ADC diferencial y ganancia programable (ATmega32U4, ATtiny85) tienen más combinaciones de MUX.
Al cambiar de canal conviene recordar que el capacitor de muestreo conserva algo de carga del canal anterior. Si dos canales tienen tensiones muy distintas y la impedancia de la fuente es alta, la primera lectura tras el cambio sale contaminada. La práctica habitual es descartar la primera lectura después de cambiar de canal o de referencia.
04 · Contra qué se mide
La referencia de tensión
Los bits REFS1:0 de ADMUX eligen la tensión que equivale a «escala completa»:
| REFS1:0 | Referencia | LSB (10 bits) | Cuándo usarla |
|---|---|---|---|
| 00 | Pin AREF externo | Vref / 1024 | Hay una referencia de precisión externa (por ejemplo, un integrado de 2,5 V) |
| 01 | AVcc (alimentación analógica) | 4,883 mV con 5 V | Lo habitual. Funciona bien con sensores ratiométricos (potenciómetros) |
| 11 | Interna de 1,1 V | 1,074 mV | Señales pequeñas (LM35, termopares) y medición de Vcc |
| 10 | Reservada | ||
El pin AREF no se debe usar con ligereza. Con AVcc o la referencia interna, el pin queda conectado a la referencia, y el datasheet recomienda un capacitor de 100 nF entre AREF y masa para estabilizarla. Si elegís una referencia interna y a la vez conectás una tensión externa a AREF, se cortocircuitan las dos fuentes. En la placa Arduino, el pin AREF suele estar libre; cuando se usa una referencia externa, el programa debe seleccionar esa opción antes de la primera lectura.
Cambiar la referencia en pleno funcionamiento tiene un costo: la referencia interna necesita unos instantes para estabilizarse (el capacitor de AREF se carga), y las primeras lecturas tras el cambio pueden ser erróneas. Se descartan una o dos y, si hace falta, se espera unos milisegundos.
05 · Velocidad
Reloj y tiempo de conversión
El ADC tiene su propio reloj, derivado del del sistema con un divisor (los bits ADPS2:0 de ADCSRA). Para obtener la exactitud completa de 10 bits, el datasheet pide un reloj de ADC de 50 a 200 kHz. Con un cristal de 16 MHz, el único divisor que cae en ese rango es 128:
| ADPS2:0 | Divisor | Reloj ADC | Conversión | Muestras/s |
|---|---|---|---|---|
| 001 | 2 | 8 MHz | 1,6 µs | 615 385 |
| 010 | 4 | 4 MHz | 3,25 µs | 307 692 |
| 011 | 8 | 2 MHz | 6,5 µs | 153 846 |
| 100 | 16 | 1 MHz | 13 µs | 76 923 |
| 101 | 32 | 500 kHz | 26 µs | 38 462 |
| 110 | 64 | 250 kHz | 52 µs | 19 231 |
| 111 | 128 | 125 kHz | 104 µs | 9615 |
Una conversión normal dura 13 ciclos del reloj del ADC; la primera tras activar el ADC dura 25, porque inicializa los circuitos analógicos. A 125 kHz son 104 µs (unas 9600 muestras por segundo): la analogRead() de Arduino ronda los 110 µs porque usa este divisor. Un reloj mayor es válido si bastan 8 bits de exactitud; el reloj más rápido simplemente deja menos tiempo al capacitor de muestreo para cargarse y baja la exactitud. Por eso la tabla marca solo la fila de 125 kHz como recomendada y las demás como una elección explícita.
Si el microcontrolador corre a otra frecuencia, el divisor se ajusta para quedar en el rango: a 8 MHz, 64; a 1 MHz, 8.
06 · Control
Los registros del ADC
ADMUX: referencia, ajuste y canal
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bits 3:0 |
|---|---|---|---|---|
| REFS1 | REFS0 | ADLAR | — | MUX3:0 |
ADLAR = 1 alinea el resultado a la izquierda: los 8 bits más altos quedan en ADCH, y se puede leer solo ese byte cuando bastan 8 bits de resolución.
ADCSRA: control y estado
| Bit | Nombre | Función |
|---|---|---|
| 7 | ADEN | Habilita el ADC (consume energía mientras está en 1) |
| 6 | ADSC | Escribir 1 inicia una conversión; se pone en 0 solo al terminar |
| 5 | ADATE | Habilita el disparo automático desde la fuente elegida en ADCSRB |
| 4 | ADIF | Bandera de «conversión completa» (se borra al entrar a la ISR o escribiendo 1) |
| 3 | ADIE | Habilita la interrupción de fin de conversión |
| 2:0 | ADPS2:0 | Divisor del reloj del ADC (tabla de la sección 5) |
ADCSRB, DIDR0 y el resultado
| Registro | Qué contiene |
|---|---|
| ADCSRB, bits ADTS2:0 | Fuente del disparo automático (con ADATE = 1): 000 modo libre, 001 comparador analógico, 010 INT0, 011 comparación A del Timer0, 100 desbordamiento del Timer0, 101 comparación B del Timer1, 110 desbordamiento del Timer1, 111 captura del Timer1 |
| DIDR0 (bits ADC5D a ADC0D) | Cada bit en 1 desconecta el buffer de entrada digital del pin correspondiente |
ADCL y ADCH (16 bits en C: ADC) | Resultado. Se lee primero ADCL y después ADCH; en C, la macro ADC lo hace en el orden correcto |
| PRR, bit PRADC | En 1 apaga el ADC por completo (ahorro de energía, tema 40) |
El orden de lectura de ADCL y ADCH importa: leer ADCL bloquea el acceso de la conversión a ADCH hasta que se lee, para que no se mezclen los dos bytes de dos conversiones distintas (la misma idea del registro temporal de 16 bits de los temporizadores, tema 23).
07 · Primer programa
Leer por sondeo
La forma más sencilla: iniciar, esperar a que ADSC vuelva a 0 y leer.
#define F_CPU 16000000UL
#include <avr/io.h>
static void adc_init(void) {
ADMUX = (1 << REFS0); // referencia AVcc, canal ADC0
ADCSRA = (1 << ADEN)
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // habilitar; divisor 128 (125 kHz)
DIDR0 = (1 << ADC0D); // sin buffer digital en PC0
}
static uint16_t adc_read(uint8_t canal) {
ADMUX = (ADMUX & 0xF0) | (canal & 0x0F); // elige el canal, conserva REFS y ADLAR
ADCSRA |= (1 << ADSC); // inicia la conversión
while (ADCSRA & (1 << ADSC)) { } // espera: ~104 µs
return ADC; // 0 a 1023
}
int main(void) {
adc_init();
for (;;) {
uint16_t crudo = adc_read(0);
uint32_t milivolts = (uint32_t)crudo * 5000UL / 1024UL; // con AVcc = 5 V
(void)milivolts;
}
}
Tres cuidados en este código. La cuenta usa uint32_t: crudo * 5000 con 1023 vale 5 115 000 y desbordaría un entero de 16 bits (tema 10). El divisor es 1024, no 1023: cada código es un escalón de ancho 1 LSB. Y adc_read() conserva los bits altos de ADMUX (referencia y ajuste) al cambiar de canal.
La espera activa de 104 µs es aceptable para programas simples, pero es tiempo en que la CPU no hace otra cosa. Se resuelve de dos maneras: disparar la conversión y volver más tarde a ver si terminó (consultando ADSC en cada vuelta del lazo principal), o usar la interrupción de la sección siguiente.
Receta para varios canales
- Cambiá el canal en
ADMUX. - Descartá la primera lectura (carga residual del capacitor de muestreo) si las impedancias de fuente son altas.
- Leé la segunda; opcionalmente promediá varias.
- Pasá al canal siguiente. Un barrido de 6 canales a 125 kHz con descarte de la primera lectura tarda unos 1,25 ms.
08 · Sin esperar
Disparo automático e interrupción
Con ADIE = 1 (y las interrupciones globales habilitadas), cuando termina la conversión se activa el vector ADC_vect. La CPU puede seguir con otra tarea durante los 104 µs. Con ADATE = 1 el ADC ni siquiera necesita que la CPU lo inicie: arranca solo desde la fuente que elija ADTS. Si la fuente es el desbordamiento o la comparación de un temporizador, el muestreo ocurre a intervalos exactos, sin el jitter que introduce el software:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint16_t ultima_lectura;
volatile uint8_t lectura_nueva;
EMPTY_INTERRUPT(TIMER1_COMPB_vect); // solo borra la bandera que dispara el ADC
ISR(ADC_vect) {
ultima_lectura = ADC; // al entrar se borra ADIF
lectura_nueva = 1;
}
static void muestreo_1khz(void) {
// Timer1 en CTC: comparación B cada 1 ms (16 MHz / 64 -> 250 cuentas)
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
OCR1A = 249;
OCR1B = 249;
TIMSK1 = (1 << OCIE1B); // la ISR vacía limpia OCF1B
ADMUX = (1 << REFS0);
ADCSRB = (1 << ADTS2) | (1 << ADTS0); // ADTS = 101: comparación B del Timer1
ADCSRA = (1 << ADEN) | (1 << ADATE) | (1 << ADIE)
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
sei();
}
El ADC se dispara con el flanco de subida de la bandera elegida (aquí OCF1B), así que esa bandera tiene que volver a 0 antes del próximo ciclo. Por eso se habilita la interrupción de comparación B con un manejador vacío (EMPTY_INTERRUPT): su única función es borrar la bandera. Medí con un osciloscopio o un pin de prueba que el período sea realmente de 1 ms antes de confiar en la regularidad.
El modo libre (ADTS = 000) hace una conversión tras otra sin intervención, a una tasa de unas 9600 por segundo con divisor 128: útil para promediar o para audio de baja calidad, pero con una tasa fija que no se controla finamente. La interrupción del ADC a esa velocidad consume tiempo: 9600 llamadas por segundo, cada una de unos 3 µs (tema 19), es aproximadamente 3 % de la CPU.
09 · Los últimos bits
Reducir el ruido
Con 10 bits y 5 V cada escalón mide 4,9 mV: un ruido de unos pocos milivolts en la alimentación o en la entrada ya cambia los dos últimos bits. Las medidas habituales, de menor a mayor esfuerzo:
- Filtrar y desacoplar. Un capacitor de 100 nF junto al pin de entrada (con una resistencia en serie, forma el filtro RC antialias del tema 27) y otro de 100 nF entre AVcc y masa, además del de AREF.
- Alimentar AVcc con un filtro. El datasheet recomienda alimentar AVcc a través de una inductancia de 10 µH desde Vcc, para separar el ruido digital del analógico. Muchas placas ya lo incluyen.
- Apagar el buffer digital del pin (
DIDR0): evita que el nivel analógico intermedio haga conducir la etapa de entrada digital, que consume y genera ruido. - Dormir durante la conversión. El modo ADC Noise Reduction (
SM = 001) detiene la CPU y los periféricos ruidosos mientras convierte; al terminar, la interrupción del ADC despierta al chip (tema 40). - Promediar varias lecturas (tema 27: +1 bit por cada 4 lecturas, si hay algo de ruido).
- Cuidar el cableado. Cables cortos, entradas lejos de líneas PWM y de conmutación, masa común con camino corto, y el pin sin conectar nunca debe leerse: «flota» y entrega valores arbitrarios.
- No conmutar pines digitales cercanos durante la conversión: cada flanco inyecta un pico en la alimentación.
Para validar el montaje, medí el canal de GND (MUX = 1111): debería dar 0 o 1. Valores mayores indican offset o ruido en la propia alimentación.
10 · Analogía con programación
Simular el conversor
Este programa implementa el algoritmo de aproximaciones sucesivas y comprueba que da el mismo resultado que dividir directamente. Después calcula la velocidad de conversión para cada divisor y simula la medición de Vcc con la referencia de 1,1 V, incluido el error que produciría una referencia real distinta de la nominal.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
import random
def adc_directo(vin, vref, bits=10):
# lo que hace el conversor idealmente: piso de vin/LSB, saturado
niveles = 2 ** bits
return min(niveles - 1, int(vin / vref * niveles))
def adc_sar(vin, vref, bits=10):
# aproximaciones sucesivas: un bit por comparacion, del mas pesado al menos
niveles = 2 ** bits
lsb = vref / niveles
codigo = 0
for b in range(bits - 1, -1, -1):
prueba = codigo | (1 << b)
if vin >= prueba * lsb:
codigo = prueba
return codigo
# 1) el SAR coincide con la conversion directa
random.seed(7)
distintos = 0
for _ in range(10000):
v = random.uniform(0, 5)
if adc_sar(v, 5) != adc_directo(v, 5):
distintos += 1
print("SAR contra division directa: diferencias en 10000 tensiones =", distintos)
print("ejemplo 3,3 V con Vref 5 V ->", adc_sar(3.3, 5))
# 2) reloj del ADC y velocidad segun el divisor (cristal de 16 MHz)
print()
print("divisor reloj ADC conversion muestras/s en rango 50-200 kHz")
for div in (2, 4, 8, 16, 32, 64, 128):
f = 16e6 / div
t = 13 / f
print(f"{div:7d} {f/1000:8.1f} kHz {t*1e6:8.1f} us {1/t:9.0f} {'si' if 50e3 <= f <= 200e3 else 'no'}")
# 3) medir Vcc con la referencia interna de 1,1 V
print()
print("Vcc real codigo Vcc estimada error")
for vcc in (5.0, 4.5, 4.0, 3.3, 3.0):
codigo = round(1.1 / vcc * 1024)
est = 1.1 * 1024 / codigo
print(f"{vcc:6.2f} V {codigo:6d} {est:8.3f} V {est - vcc:+.3f} V")
# si la referencia real fuera 1,0 V en lugar de 1,1 V
real = 1.0
codigo = round(real / 5.0 * 1024)
print("con una referencia real de 1,0 V y Vcc = 5 V se estimaria", round(1.1 * 1024 / codigo, 2), "V")
Resultado: el algoritmo SAR coincide con la división directa en las 10 000 tensiones de prueba. Con divisor 128 son 104 µs por conversión, y solo esa fila cae en el rango de 50 a 200 kHz. La estimación de Vcc tiene un error de unos 6 mV (el redondeo del código) si la referencia es exactamente 1,1 V, pero si en realidad fuera de 1,0 V, se mediría 5,49 V en lugar de 5 V: de ahí la necesidad de calibrar.
El SAR de verdad opera con tensiones analógicas y con la imperfección de cada comparación; el modelo reproduce solo la lógica.
11 · Exploración interactiva
Registros, SAR y lecturas
La primera herramienta arma los valores de ADMUX y ADCSRA y el código C a partir de tus elecciones, y calcula el reloj y el tiempo de conversión. La segunda muestra el algoritmo de aproximaciones sucesivas paso a paso. La tercera interpreta un código leído como tensión, tensión de un divisor, temperatura de un LM35 o tensión de alimentación.
Banco del ADC
1. Constructor de registros
2. Aproximaciones sucesivas
| Paso | Bit probado | Código de prueba | Tensión del DAC | Decisión | Resultado parcial |
|---|
3. Interpretar una lectura
Recorrido guiado
- Con AVcc, ADC0 y divisor 128 aparecen
ADMUX = 0x40yADCSRA = 0x87: la configuración deadc_init(). Cambiá el reloj a 8 MHz: el reloj del ADC queda en 62,5 kHz, todavía dentro del rango. - Subí el divisor a 16 con 16 MHz: 1 MHz de reloj, 13 µs por conversión y aviso de que supera los 200 kHz.
- Elegí «Sensor de temperatura» con AVcc: la nota recuerda que solo se mide con la referencia interna. Cambiá a 1,1 V y el valor de ADMUX pasa a
0xC8. - En la herramienta 2, 3,3 V con 5 V y 10 bits da 675. Pasá a 4 bits: son solo cuatro pasos y el resultado 10 (1010), con un error de hasta un escalón de 312 mV.
- En la herramienta 3, código 512 con 5 V son 2,5 V. Con 1,1 V de referencia y LM35, el código 256 son 0,275 V, es decir, 27,5 °C.
- Elegí «Medir Vcc» con el código 225: 5,006 V. Con 375, 3,004 V.
Desafío: un sensor de 0 a 3,3 V con referencia de 5 V
Si el sensor solo llega a 3,3 V y usás AVcc = 5 V, el código máximo es 3,3 / 5 × 1024 = 675: se desperdicia un tercio del rango y el escalón sigue en 4,88 mV. Con la referencia interna de 1,1 V habría que reducir la señal con un divisor 3:1 (3,3 V pasan a 1,1 V), a costa de ruido y de la tolerancia de las resistencias. La mejor opción es una referencia externa de 3,3 V en AREF (REFS = 00): da 3,22 mV por escalón y aprovecha los 1024 códigos.
12 · Comprensión
Confusiones frecuentes
«Puedo leer dos pines analógicos al mismo tiempo»
No: hay un solo conversor y un multiplexor. Los canales se leen uno detrás de otro, y entre lecturas conviene descartar la primera tras el cambio.
«El resultado va de 0 a 1023, así que divido por 1023»
Se divide por 1024: hay 1024 escalones de ancho Vref/1024. Dividir por 1023 produce un error pequeño pero sistemático, que además da el valor máximo exacto a una tensión que el conversor nunca alcanza.
«Con 16 MHz puedo poner cualquier divisor en el ADC»
Puedo, pero solo el 128 (125 kHz) cumple los 50 a 200 kHz para exactitud completa. Con divisores menores el ADC corre más rápido y entrega menos exactitud.
«Si elijo la referencia interna, AREF no importa»
AREF queda conectado a la referencia interna: poner una tensión externa ahí la cortocircuita. Además, el capacitor de AREF debe tener un valor moderado (100 nF).
«Un pin analógico sin conectar lee 0»
Flota y entrega valores arbitrarios, influidos por pines vecinos y por la mano. Se usa una resistencia a masa o se lee solo cuando hay un sensor conectado.
«El sensor de temperatura interno mide la temperatura ambiente»
Mide la del chip, que se calienta con la propia actividad. Su exactitud sin calibración es de unos ±10 °C.
13 · Práctica guiada
Predecí antes de comprobar
1. ADMUX
¿Qué valor hay que escribir en ADMUX para medir ADC3 con referencia AVcc y resultado alineado a la izquierda?
Ver solución
REFS0 = 0x40, ADLAR = 0x20, canal 3: 0x40 | 0x20 | 0x03 = 0x63.
2. Tiempo de un barrido
Se leen 8 canales a 16 MHz con divisor 128, una conversión por canal. ¿Cuánto tarda un barrido?
Ver solución
8 × 104 µs = 832 µs. Si además se descarta la primera lectura de cada canal, el doble: 1,66 ms.
3. Divisor para otro reloj
El microcontrolador funciona a 8 MHz. ¿Qué divisor deja el reloj del ADC entre 50 y 200 kHz?
Ver solución
8 MHz / 64 = 125 kHz (también sirve 128, que da 62,5 kHz). El divisor 64 mantiene los 125 kHz y los 104 µs.
4. Conversión de un LM35
Con la referencia interna de 1,1 V, el código leído es 300. ¿Qué temperatura indica un LM35 (10 mV/°C)?
Ver solución
V = 300 × 1,1 / 1024 = 0,3223 V → 32,2 °C. El escalón es de 0,107 °C.
5. Vcc de una batería
Al medir la referencia de 1,1 V con AVcc como referencia, el código es 340. ¿Cuál es Vcc?
Ver solución
Vcc = 1,1 × 1024 / 340 = 3,313 V.
14 · Síntesis
Ideas para recordar
- El ADC del ATmega328P es un SAR de 10 bits: un bit por ciclo de su reloj, 13 ciclos por conversión (25 la primera).
- Es un solo conversor con un multiplexor (
MUX3:0): ADC0 a ADC5, sensor de temperatura, 1,1 V y GND. - La referencia (
REFS1:0) fija la escala: AVcc para uso general y sensores ratiométricos, 1,1 V para señales pequeñas, AREF para una referencia externa. Se divide por 1024, no por 1023. - El reloj del ADC debe estar entre 50 y 200 kHz para exactitud completa: divisor 128 a 16 MHz, 104 µs por conversión.
- Se inicia con
ADSC, se espera su fin por sondeo o porADC_vect, y se puede disparar desde un temporizador conADATEyADTS. - Contra el ruido: capacitores en AVcc, AREF y entrada,
DIDR0, modo de reposo del ADC, promediado y buen cableado.
¿Listo para el tema 29?
Antes de avanzar, escribí de memoria adc_init() y adc_read(), calculá el tiempo de conversión para un reloj dado y explicá cómo medirías la tensión de la batería sin componentes externos.
En el próximo tema vamos en sentido contrario: del número a la tensión. Veremos el DAC y las salidas analógicas: la red R-2R, el PWM filtrado y los DAC integrados.