← Índice del curso

Microcontroladores · Tema 45

Cierre y puente a sensores y actuadores

Cuarenta y cuatro temas después, un microcontrolador dejó de ser una caja negra: sabés qué hay dentro, cómo se configura, cómo se le habla y cómo se lo hace dormir. Falta la habilidad que distingue a quien programa un chip de quien lo domina: encontrar por qué no anda. Este tema repasa el recorrido, propone un método para depurar sin adivinar y señala por dónde seguir.

01 · Punto de partida

Lo que ya sabés

Al empezar, un microcontrolador era un componente que «ejecuta un programa». Ahora podés describir qué pasa entre el reset y la primera línea de main(); leer el datasheet para configurar un periférico por sus registros; sacar una señal de 1 kHz de un temporizador y calcular su error; muestrear una señal analógica y saber qué significa cada bit; hablar por UART, I2C y SPI y mirar el resultado con un analizador lógico; comandar un motor sin quemar un pin; y diseñar un dispositivo que dura años con dos pilas o que mantiene una temperatura con un lazo cerrado.

Es mucho material, y tiene un riesgo: aprenderlo como una lista de recetas. Las recetas funcionan hasta el día en que algo no sale como en el libro, y ese día lo único que sirve es un método para encontrar la causa. En electrónica y en firmware, los errores no se dejan ver: no hay una línea que marque «aquí falló», y lo mismo puede ser un cable, un fusible, un registro, una interrupción o un desbordamiento. Un programador de aplicaciones tiene depuradores, trazas y excepciones; en un microcontrolador, el depurador es en buena parte uno mismo.

El tema no trae un proyecto nuevo, sino que cierra el curso con tres cosas: el mapa de lo aprendido, el método para depurar y un puente hacia lo que viene. Las herramientas del laboratorio incluyen un asistente de depuración por síntomas, las calculadoras que más se repiten (error de baudios y temporizadores) y una guía de estudio según el objetivo.

02 · Repaso

El mapa del curso

Los diez bloques y la idea que sostiene cada uno.
BloqueTemasIdea central
1. Del chip al sistema1 a 5Un microcontrolador es una computadora completa en un chip: CPU, memorias y periféricos conectados por buses; se programa en una cadena de compilar, cargar y depurar.
2. CPU, memoria y registros6 a 11Todo se reduce a ciclos de búsqueda, decodificación y ejecución; los periféricos son registros con direcciones, y se configuran con operaciones de bits.
3. Reloj y arranque12 a 14El reloj marca el ritmo de todo; el reset, los fusibles y el watchdog definen cómo nace y cómo se protege el sistema; todo tiempo se puede medir en ciclos.
4. Entradas y salidas digitales15 a 18Un pin es un circuito con límites eléctricos reales: corriente, pull-ups, rebotes.
5. Interrupciones19 a 22El hardware avisa; la rutina es breve; los datos compartidos exigen cuidado (volatile, secciones críticas).
6. Temporizadores y PWM23 a 26Contar ciclos da tiempo, frecuencia, captura y potencia controlada por el ancho de un pulso.
7. Conversión analógica y digital27 a 30Muestrear es cuantizar: la referencia, el ruido y la impedancia deciden la calidad de cada bit.
8. Comunicación serie31 a 35UART, I2C y SPI son tres acuerdos de tiempos y niveles; un analizador lógico muestra si se cumplen.
9. Sensores y actuadores36 a 39Medir bien es una cadena (acondicionar, calibrar, filtrar); un pin no es una fuente de potencia.
10. Energía, estructura y proyectos40 a 45Dormir casi siempre, estructurar con bucle e interrupciones, tareas cooperativas y lazos de control; integrar todo en un dispositivo.

Si se resume todo el curso en una frase, sería esta: un microcontrolador es una máquina de estados que lee registros, escribe registros y mira el reloj, y todo lo demás —sensores, motores, protocolos, pantallas— son maneras de convertir el mundo físico en valores de esos registros y de vuelta. Esa frase es la base del método de depuración, porque tiene una consecuencia práctica: en cualquier falla, hay un valor de registro, una señal en un pin o un instante de tiempo que no es el que esperabas, y encontrarlo es cuestión de medir.

03 · Dónde buscar

Un modelo mental por capas

Las capas de un sistema con microcontrolador y qué se rompe en cada una Seis capas apiladas. De abajo hacia arriba: alimentación y lógica, CPU memorias y reloj, registros GPIO y pines, periféricos como el ADC y la UART, interrupciones y temporizadores, y estructura de la aplicación. A la derecha, el síntoma típico de cada capa: no hace nada, no arranca bien, el pin no cambia, datos basura o lecturas malas, una interrupción que no corre, y fallas que aparecen después de horas. Una flecha indica que se busca de abajo hacia arriba. Estructura de la aplicaciónbucle, tareas, módulos (temas 41 a 44) Interrupciones y temporizadoresvectores, banderas, tiempos (temas 19 a 26) PeriféricosADC, UART, I2C, SPI, PWM (temas 25 a 35) Registros, GPIO y pinesconfiguración, electrónica del pin (temas 9 a 18) CPU, memorias y relojarranque, fusibles, reset (temas 3 a 14) Alimentación y lógicatensiones, masa, niveles (temas 1, 2, 40) Síntomas típicos se cuelga tras horas; se pierde un evento una ISR no corre o corre de más datos basura, lecturas inestables el pin no cambia, otro valor del esperado no arranca; frecuencia equivocada no hace nada; reinicios al azar se busca de abajo hacia arriba

El modelo ordena la búsqueda: una capa puede fallar de por sí, y cuando falla arrastra a todas las de arriba. Si el chip no tiene tensión estable, ninguna línea de código importa; si el reloj no es el que se supone, la UART mandará basura aunque la configuración del periférico sea perfecta; si un pin tiene una función alternativa activa, el registro de salida no sirve de nada. Por eso se depura de abajo hacia arriba: primero se confirma lo que todo lo demás da por sentado. El error más frecuente de los principiantes es lo contrario: revisar durante horas el código de la capa de arriba mientras la de abajo (un fusible, un cable) está mal.

Y hay una regla de oro que acompaña al modelo: cuanto más abajo está el problema, más raro parece el síntoma. Un reinicio espontáneo, caracteres aleatorios, un comportamiento que cambia al tocar el cable: lo extraño suele venir de la alimentación, el reloj o la masa, no de un error ingenioso en el programa.

04 · El método

Depurar con método

Depurar no es mirar el código hasta que aparezca el error: es aplicar el método científico a un aparato. Los pasos, en orden:

  1. Reproducir. Un fallo que ocurre «a veces» no se puede estudiar. Hay que encontrar las condiciones que lo disparan, o aumentarlas (acelerar el tiempo, forzar las entradas). Si no se logra reproducir, se instrumenta para atrapar la próxima vez (sección 8).
  2. Describir el síntoma con exactitud. «No anda» no es una descripción. «El LED no cambia y el pin mide 0 V» es una descripción. «Se reciben 6 de cada 10 caracteres y el ancho de bit es el doble» también. La precisión del síntoma ya descarta capas enteras.
  3. Formular una hipótesis que se pueda refutar y buscar la medición más barata que la confirme o la descarte. La pregunta no es «¿qué estará mal?», sino «¿qué medición separa el sistema en dos mitades?».
  4. Bisectar. Se divide el sistema por la mitad y se mide en el punto medio: si ahí la señal está bien, el defecto está después; si está mal, antes. Cada medición descarta la mitad de lo que queda, de modo que con 10 puntos de prueba se encuentran fallas entre 1000 posibilidades. El bloque de Python lo cuenta.
  5. Cambiar una sola cosa por vez, y volver a medir. Si se cambian tres cosas y el problema desaparece, no se sabe cuál lo arregló, ni si volverá.
  6. Anotar. Qué se probó, qué se midió y qué se concluyó. A las dos horas de depuración nadie recuerda qué descartó; un cuaderno evita repetir pruebas y es la base para la explicación final.
  7. Entender la causa antes de cerrar. Un cambio que «lo arregla» sin explicación es una promesa de que volverá. La prueba de que se entendió es poder predecir qué ocurre si se deshace el arreglo.

Detrás del método hay una actitud: desconfiar de lo que se da por sentado, empezando por uno mismo. Los errores más largos son los que se esconden en una suposición que nunca se verificó: que el reloj es de 16 MHz, que el cable estaba bien, que el sensor está en la dirección que dice el tutorial, que el compilador entiende lo que pensamos que escribimos. Medir la suposición cuesta minutos; no medirla, días.

05 · Ver lo invisible

Herramientas: qué ve cada una

Instrumentos y técnicas para depurar firmware, de la más barata a la más completa.
HerramientaQué muestraLímites
MultímetroTensiones y continuidad estables: alimentación, niveles, fusibles, cablesNo ve nada que cambie en milisegundos; en µA altera el circuito
LED o pin de trazaSi el programa llegó a un punto y cuánto tardó (un pin en alto durante la región)Un solo bit de información; hay que medirlo con otro instrumento
Salida serie (printf, trazas)Valores de variables, estado, causa del reset, contadoresCuesta tiempo (a 9600 baudios, 1 ms por carácter) y puede cambiar el comportamiento; no sirve si el fallo es la propia UART
OsciloscopioFormas de onda, tiempos, ruido, caídas de tensión, rebotes, glitchesPocos canales; hay que saber dónde mirar; la sonda carga el circuito
Analizador lógicoMuchas señales digitales a la vez, con decodificación de UART, I2C, SPI (tema 35)Solo niveles digitales; no ve la calidad analógica de la señal
Depurador (debugWIRE, JTAG, SWD)Detener el programa, ver y cambiar registros y memoria, avanzar por instruccionesDetiene el tiempo real; en algunos chips cambia el reloj o el consumo; no sirve para fallas de temporización
SimuladorEjecutar el firmware sin hardware, ver registros y tiemposNo modela el mundo real: ruido, rebotes, caídas de tensión
Analizador de energíaCorriente en el tiempo, de nanoamperios a amperios (tema 40)Costo; hay que conectarlo en serie con la alimentación

Una advertencia sobre el principio de incertidumbre del depurador: observar cambia lo observado. Una traza por serie añade milisegundos y puede ocultar una condición de carrera; un depurador detiene el reloj de los periféricos; una sonda de osciloscopio agrega 10 pF y puede estabilizar un oscilador que fallaba. Cuando un fallo desaparece al medirlo, eso ya es una pista: casi siempre es temporización, una condición de carrera o una señal marginal.

La combinación más rentable para un aficionado es el trío multímetro, pin de traza y un analizador lógico barato (unos pocos dólares, con decodificadores de protocolos incluidos). Con eso se resuelven nueve de cada diez problemas de este curso.

06 · Un primer movimiento seguro

La lista por capas

Cuando el problema no se deja describir, hay una lista de comprobaciones que casi siempre sirve, ordenada de abajo hacia arriba. Es la lista que un buen técnico recorre sin pensar:

Primera revisión según el síntoma. La herramienta 1 del laboratorio la amplía con pasos y valores esperados.
SíntomaQué revisar primeroTema
No hace nadaTensión en los pines del chip, pin RESET en alto, reloj, fusibles, que el programa realmente esté cargado4, 13
Un pin no cambiaDDRx, función alternativa del pin, el mapa de pines de la placa, la carga conectada9, 15, 16
Datos basura por UARTReloj real contra F_CPU, error de baudios, formato de la trama, cruce de TX y RX, niveles12, 32
Lecturas del ADC inestablesReferencia, impedancia de la fuente, primera lectura tras un cambio de canal, masa común, ruido28, 36
Reinicios al azarCausa en MCUSR, caída de VCC bajo carga, watchdog, desbordamiento de pila13, 38, 41
Una interrupción no corresei(), máscara de la fuente, nombre del vector, bandera, señal de entrada19, 20
Una frecuencia sale equivocadaReloj real, prescaler, modo del temporizador, «OCR + 1»23, 24
El dispositivo I2C no respondePull-ups, dirección (barrido), niveles, cableado, velocidad33, 35
Falla después de horasMemoria libre, desbordes de contadores, variables compartidas sin proteger, eventos perdidos21, 41
Funciona con una optimización y falla con otraVariables sin volatile, comportamiento indefinido, dependencia del orden de evaluación10, 21

Dos reflejos útiles antes de abrir cualquier instrumento: probar el ejemplo mínimo (el programa de parpadeo, la lectura aislada de un canal, un eco por serie) para ver si la capa de abajo anda, y cambiar la pieza por otra igual cuando se sospecha de un componente (otro cable, otro sensor, otra placa). Un montaje dudoso se confirma o se descarta en minutos con una pieza conocida.

07 · Práctica con casos

Cuatro casos resueltos

Caso 1: la UART devuelve basura

Un programa configurado para 9600 baudios con F_CPU de 16 MHz envía «Hola» y el terminal muestra símbolos al azar. Síntoma preciso: con el analizador lógico, el ancho de un bit mide 1,66 ms. Cálculo: a 9600 baudios el bit debería medir 104 µs; 1,66 ms es 16 veces más. Hipótesis: el reloj real es 16 veces más lento de lo que supone el código. Medición: un programa que conmuta un pin da 1 MHz, no 16. Causa: el chip arranca con el oscilador interno de 8 MHz dividido por 8 y la placa no tiene el cristal de 16 MHz conectado (o los fusibles no lo seleccionan). Con UBRR = 103 para 16 MHz y el reloj real de 1 MHz, la velocidad efectiva es 1 000 000 / (16 · 104) = 601 baudios. Arreglo: corregir F_CPU y el valor de UBRR (con 1 MHz y U2X, UBRR = 12), o programar los fusibles para el cristal. La lección: el ancho de bit medido dio el factor 16 antes de tocar una línea de código.

Caso 2: el potenciómetro «tiembla» y lee de menos

Un potenciómetro de 100 kΩ conectado a un canal del ADC da lecturas que varían ±15 cuentas, y al alternar entre dos canales la primera lectura de cada uno sale mal. Hipótesis: la impedancia de la fuente es demasiado alta para el capacitor de muestreo del ADC, que mide unos 14 pF y necesita unos pocos microsegundos para cargarse: la fuente debe ser de 10 kΩ o menos (tema 28). Un cursor en el medio de un potenciómetro de 100 kΩ llega a 25 kΩ. Medición: con un capacitor de 100 nF entre el cursor y masa, la dispersión baja a ±2 cuentas, y descartando la primera conversión tras cambiar de canal desaparece el error de lectura cruzada. Arreglo: un potenciómetro de 10 kΩ, o el capacitor, o un seguidor con un operacional. Es el mismo problema de fondo que el de los sensores del tema 36.

Caso 3: el sistema se reinicia al arrancar el motor

Un robot con un motor de CC pequeño se reinicia cada vez que el motor arranca. Primer paso: leer MCUSR y mostrarla por serie: el bit BORF está en 1, un reset por brown-out. Medición: el osciloscopio en VCC muestra una caída de 5 V a 2,3 V durante 3 ms al arrancar el motor, justo la corriente de arranque de varios amperios (tema 38) a través de una fuente de baja capacidad y cables finos. Arreglo: fuente separada para el motor con la masa unida en un solo punto, un capacitor electrolítico de 470 a 1000 µF cerca del driver y un arranque con rampa de PWM (tema 39). Nada de eso se habría encontrado leyendo el código: era la capa de alimentación.

Caso 4: funciona con -O0 y se cuelga con -Os

Un programa espera con while (!listo) { } a que una interrupción ponga listo = 1. Compilado sin optimización funciona; con -Os, el bucle no termina nunca. Hipótesis: el compilador cargó listo en un registro una sola vez, porque desde su punto de vista nada dentro del bucle la modifica. Confirmación: en el ensamblador generado (avr-objdump -d), el bucle es un salto incondicional a sí mismo. Arreglo: declarar volatile uint8_t listo; (tema 21). La lección es general: cuando un cambio de optimización cambia el comportamiento, casi siempre el programa tiene una suposición que no le dijo al compilador.

08 · Preparar el terreno

Instrumentar el código

La mejor depuración es la que se prepara antes de que ocurra el fallo. Un firmware que se va a instalar lejos tiene que poder decir qué le pasó. Cinco recursos baratos que caben en cualquier programa:

  • Pines de traza: un pin que sube al entrar a una región y baja al salir. El ancho del pulso mide el tiempo de la región, y el analizador lo registra sin alterarlo.
  • Causa del último reset, guardada y mostrada al arrancar (MCUSR).
  • Contadores de eventos anómalos: bytes perdidos, desbordes del búfer, lecturas inválidas, reintentos. Un contador que crece es un síntoma medible.
  • Aserciones: comprobaciones de lo imposible que, si fallan, dejan la línea del error y llevan el sistema a un estado seguro.
  • Medición de la pila: pintarla con un patrón al arrancar y ver cuánto se pisó.
#define TRACE_HI()  (PORTB |=  (1 << PB5))
#define TRACE_LO()  (PORTB &= ~(1 << PB5))

ISR(TIMER0_COMPA_vect) { TRACE_HI(); ms++; TRACE_LO(); }     // el ancho del pulso es lo que tarda la ISR

/* aserción: si lo imposible ocurre, deja el rastro y se detiene en estado seguro */
#define ASSERT(c)  do { if (!(c)) falla_fatal(__LINE__); } while (0)

static void falla_fatal(uint16_t linea) {
    cli();
    actuadores_apagar();                                  // primero, lo peligroso
    eeprom_update_word((uint16_t *)EE_ULTIMA_FALLA, linea);   // para leerla después
    for (;;) { }                                          // el watchdog reinicia en 1 s
}

/* pila: se pinta al arrancar y se mide cuando se quiere */
extern uint8_t _end;                                      // símbolo del enlazador: fin de .bss
void pila_pintar(void) {
    uint8_t *p = &_end;
    while (p < (uint8_t *)SP - 32) *p++ = 0xAA;           // deja un margen bajo el tope actual
}
uint16_t pila_maxima(void) {                              // bytes usados, como mínimo
    uint8_t *p = &_end;
    while (*p == 0xAA) p++;                               // el primer byte alterado marca el límite
    return RAMEND - (uint16_t)p + 1;
}

/* al arrancar: informar la causa del reset y el último error */
void informe_arranque(uint8_t causa) {
    txs("reset="); tx_num(causa);
    txs(" falla="); tx_num(eeprom_read_word((const uint16_t *)EE_ULTIMA_FALLA));
    txs(" pila="); tx_num(pila_maxima()); tx('\n');
}

El costo de esta instrumentación es de unos cientos de bytes y se puede apagar para el producto final con un #ifdef DEBUG. Se recomienda dejar activas las más baratas (la causa del reset, el contador de fallas y las aserciones críticas) incluso en producción, porque el día que un equipo falle en el campo será lo único que se pueda leer.

09 · Más allá del banco de pruebas

Del prototipo al producto

Los proyectos de los temas 43 y 44 funcionan en una mesa. Un producto funciona en un entorno hostil, durante años, con usuarios que no leyeron el manual. Lo que cambia, de forma resumida:

Qué agrega un producto a un prototipo.
AspectoEn el prototipoEn el producto
AlimentaciónUna fuente de laboratorio o una pilaProtección contra polaridad invertida y sobretensión, reguladores con margen, arranque ordenado
Entradas del exteriorCables cortos en la mesaProtección contra descargas electrostáticas (diodos TVS), filtros RC, aislamiento donde haga falta
Ruido electromagnéticoNo se notaPlano de masa, capacitores de desacople en cada pin de alimentación, cables trenzados o blindados, y pruebas de compatibilidad electromagnética
Rango de temperaturaAmbienteComponentes especificados para todo el rango; el cristal, la pila y el sensor cambian con la temperatura
FallasSe reinicia a manoWatchdog, estados seguros, registro de fallas y recuperación sin intervención
ActualizaciónSe vuelve a cargar con el programadorUn cargador de arranque (bootloader) con verificación; versión del firmware visible
Fabricación y pruebaUna unidad armada a manoPuntos de prueba, un modo de autodiagnóstico, calibración de fábrica guardada en la EEPROM
DocumentaciónUn esquema en una libretaEsquemas y código con control de versiones, lista de materiales, procedimiento de prueba

Un tema que sorprende es la vida útil de la memoria Flash y EEPROM: las escrituras se agotan (tema 43). Y otro, la seguridad: un dispositivo conectado a una red o a un teléfono es un blanco, y las contraseñas de fábrica, los canales sin cifrar y la falta de actualizaciones son la causa de la mayoría de los incidentes. Ninguno de los dos se ve en un banco de pruebas; ambos se piensan en el diseño.

10 · Hacia dónde seguir

Próximos pasos

Este curso usó el ATmega328P porque es simple, está bien documentado y deja ver cada mecanismo sin capas de por medio. Lo que aprendiste no se limita a ese chip: la estructura es la misma en todos los microcontroladores, con otros nombres, más periféricos y más capas de ayuda.

Qué cambia y qué se conserva al pasar a otra familia.
Tema del cursoATmega328PARM Cortex-M (STM32, RP2040, nRF52)ESP32
RelojOscilador interno o cristal; prescaler simplePLL y árbol de reloj con varios dominios; se configura al arrancarPLL; dos núcleos y relojes de radio
InterrupcionesVectores fijos; prioridad por posiciónControlador anidado (NVIC) con prioridades programablesMatriz de interrupciones, o tareas de un RTOS
GPIODDRx, PORTx, PINxRegistros de modo, salida, entrada, función alternativa por pinMatriz de entrada y salida: casi cualquier periférico a casi cualquier pin
Temporizadores3, de 8 y 16 bitsVarios de 16 y 32 bits, con captura y comparación múltipleTemporizadores de 64 bits, generador de PWM de LED
Datos sin CPUNo hayDMA: transferencias entre memoria y periféricos sin ocupar la CPUDMA en la mayoría de los periféricos
ProgramaBucle y interrupcionesLo mismo, o un RTOS; bibliotecas del fabricante (HAL, CMSIS)Un RTOS (FreeRTOS) como estándar, con Wi-Fi y Bluetooth
DepuracióndebugWIRE o printsSWD con puntos de interrupción y trazasJTAG y registros por USB

Los registros cambian de nombre; el procedimiento es el mismo: leer el manual de referencia, encontrar el periférico, habilitar su reloj, configurarlo, y verificar con un instrumento. Quien aprendió a leer un datasheet de 600 páginas para una cosa sabe leer cualquiera.

El curso 8, «Sensores y Actuadores», toma esta base y la profundiza: cómo funciona cada tipo de sensor (temperatura, presión, luz, movimiento, distancia), cómo se acondiciona su señal con amplificadores y filtros, y cómo se comandan motores, servos y otros actuadores con realimentación. Los cursos siguientes avanzan hacia la comunicación, los sistemas embebidos, el Internet de las cosas y la robótica. La última herramienta del laboratorio sugiere un camino según el objetivo.

Una recomendación para cualquier camino: construir cosas pequeñas y completas. Un proyecto que obliga a pasar por todas las capas —hardware, registros, estructura, energía, verificación— enseña más que diez ejercicios aislados. Y cuando falle, aplicar el método de este tema.

11 · Analogía con programación

Contar, calcular y comparar con datos

Si sos programador, la bisección te resulta familiar: es una búsqueda binaria, solo que sobre un sistema físico, y es la razón de que el método funcione. Este programa la cuenta (por etapas del sistema), arma la tabla del error de baudios para los relojes y velocidades más comunes, calcula el tamaño de una cuenta del ADC para varias referencias y resoluciones, y repite el caso 1 del tema (UART con el reloj equivocado).

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math

# 1) encontrar la etapa defectuosa: en orden o por biseccion
#    falla = primera etapa cuya salida ya es incorrecta (las anteriores estan bien)
def en_orden(n, falla):
    return falla + 1                              # se mide etapa por etapa hasta ver la primera salida mala

def biseccion(n, falla):
    lo, hi, pruebas = 0, n - 1, 0
    while lo < hi:
        medio = (lo + hi) // 2
        pruebas += 1                              # una medicion en la salida de la etapa 'medio'
        if medio >= falla:
            hi = medio                            # ya esta mal: el defecto esta en 'medio' o antes
        else:
            lo = medio + 1
    return lo, pruebas

print("etapas   en orden (media / peor)   biseccion (media / peor)")
for n in (8, 64, 1024):
    cuentas = []
    for falla in range(n):
        hallada, pruebas = biseccion(n, falla)
        assert hallada == falla
        cuentas.append(pruebas)
    print(f"{n:6d} {(n + 1) / 2:12.1f} / {n:<8d} {sum(cuentas) / n:14.1f} / {max(cuentas)}")

# 2) error de baudios de la UART: se prueba velocidad normal (divisor 16) y doble (divisor 8)
def uart(f, baud):
    mejor = None
    for k, u2x in ((16, 0), (8, 1)):
        n = max(1, round(f / (k * baud)))             # UBRR + 1
        real = f / (k * n)
        error = (real - baud) / baud * 100
        if mejor is None or abs(error) < abs(mejor[3]):
            mejor = (u2x, n - 1, real, error)
    return mejor

print()
print("reloj (MHz)   baudios   U2X   UBRR   velocidad real    error")
for f in (1e6, 8e6, 11.0592e6, 16e6):
    for baud in (9600, 57600, 115200):
        u2x, ubrr, real, error = uart(f, baud)
        print(f"{f / 1e6:11.4f} {baud:9d} {u2x:5d} {ubrr:6d} {real:15.0f} {error:8.2f} %")

# 3) tamano de una cuenta del ADC (en milivoltios)
print()
print("referencia   8 bits   10 bits   12 bits")
for v in (5.0, 3.3, 1.1):
    print(f"{v:7.1f} V " + " ".join(f"{v / 2 ** b * 1000:8.3f}" for b in (8, 10, 12)))

# 4) caso 1: el codigo calcula UBRR para 16 MHz, pero el chip corre a 1 MHz
ubrr = uart(16e6, 9600)[1]
real = 1e6 / (16 * (ubrr + 1))
print()
print(f"UBRR = {ubrr} (pensado para 16 MHz); con el reloj real de 1 MHz la velocidad es {real:.0f} baudios")
print(f"el bit mide {1e6 / real / 1000:.2f} ms en lugar de {1e6 / 9600:.0f} us: un factor de {9615 / real:.0f}")

Resultado: con 8 etapas, buscar en orden cuesta 4,5 mediciones de media (8 en el peor caso) y la bisección 3; con 64, 32,5 contra 6; con 1024, 512,5 contra 10. En la UART, 16 MHz da 9600 baudios con error de 0,16 %, 57 600 con −0,79 % y 115 200 con 2,12 %; 8 MHz da 115 200 con −3,55 % (demasiado; se corrige con 7,3728 u 11,0592 MHz); 1 MHz no llega a 57 600 ni a 115 200 (8,51 %); y 11,0592 MHz es exacto en las tres velocidades (UBRR de 71, 11 y 5). Una cuenta del ADC de 10 bits vale 4,883 mV con 5 V, 3,223 mV con 3,3 V y 1,074 mV con la referencia interna de 1,1 V. En el caso 1, el código calculó UBRR = 103 para 16 MHz; con el reloj real de 1 MHz la velocidad es 601 baudios y el bit mide 1,66 ms en lugar de 104 µs: un factor de 16, que es el dato que delata el reloj equivocado.

Los valores de los instrumentos y de los errores son los de las hojas de datos del ATmega328P; en un proyecto real se verifican contra la versión del chip que se usa.

12 · Exploración interactiva

Depurar, calcular y elegir

La primera herramienta es un asistente de depuración: elegí el síntoma y muestra, en orden, qué revisar, con qué instrumento y qué valor esperar. La segunda reúne dos calculadoras que se repiten en todos los proyectos: el error de baudios de la UART y la configuración de un temporizador. La tercera propone un camino de estudio según tu objetivo.

Banco de cierre

1. Asistente de depuración por síntomas

Capa más probable—
Qué suele pasar—

    2. Calculadoras de bolsillo: UART y temporizador

    Registro UBRR—
    Velocidad real—
    Error—

    Configuración—
    Resultado—

    3. Ruta de estudio según tu objetivo

    Qué estudiar—
    Plataforma sugerida—
    Proyecto para practicar—
    Temas del curso para repasar—

    Recorrido guiado

    1. En el asistente, elegí «La UART da basura»: el segundo paso es confirmar el reloj real contra F_CPU y el tercero, calcular el error de baudios, que se hace en la herramienta siguiente.
    2. En la calculadora de la UART, 16 MHz y 115 200 dan UBRR = 16 con velocidad doble y un error de 2,12 % (marginal). Con 8 MHz, el error es de −3,55 %: demasiado. Con 11,0592 MHz, el error es de 0 %. Con 1 MHz y 9600 baudios, UBRR = 12 con U2X da 0,16 %.
    3. En el temporizador, 16 MHz, 1000 Hz y 8 bits dan prescaler 64 y OCR = 249, exacto. Con 1 Hz, el temporizador de 8 bits no alcanza, y con el de 16 bits sale prescaler 256 y OCR = 62 499, exacto.
    4. Probá 12 MHz y 1000 Hz con 8 bits: prescaler 64 queda con OCR = 187 y un error de 0,27 % (230 s por día en un reloj).
    5. En la ruta de estudio, «Pasar a ARM» recomienda repetir el controlador de temperatura del tema 44 en la nueva plataforma, para ver qué cambia y qué se conserva.
    Desafío: un diagnóstico completo

    Una estación como la del tema 43 mide bien durante dos días y después deja de guardar datos; el botón sigue despertándola y la consola responde. ¿Cómo se encuentra el problema? 1) Describir el síntoma con precisión: ¿deja de guardar del todo o guarda datos incorrectos? Se vuelca el registro con D: los últimos registros son válidos hasta cierto punto y luego quedan vacíos. 2) Hipótesis: un fallo de la tensión (la batería baja de 2,0 V y el programa se niega a escribir) o de la cabeza del anillo. 3) La medición más barata: el comando S informa la tensión de la batería. Si da 1,9 V, el programa se negó a escribir con razón: la batería estaba agotada; la estación hizo lo que debía. Si da 3,0 V, la hipótesis queda descartada y se pasa a la siguiente: el contador de registros. 4) Revisar el contador de fallas y la última falla guardada. Con el método, cada paso descarta una causa con una medición.

    13 · Cierre del curso

    Lo aprendido en el curso

    1. Un microcontrolador es una máquina de estados con registros y un reloj. Todo lo demás (periféricos, buses, sensores) se reduce a leer y escribir registros en el momento correcto.
    2. El datasheet es la fuente de la verdad. Se lee por periférico, con un objetivo, y se verifica con una medición.
    3. El mundo físico tiene límites: un pin da miliamperios, un ADC tiene ruido, un contacto rebota, un cable tiene resistencia, una pila se agota. El software que ignora esos límites falla.
    4. El tiempo es un recurso: se cuenta en ciclos, se reparte con interrupciones y temporizadores y se protege con rutinas breves.
    5. No bloquear: las esperas se convierten en estados y los eventos se atienden cuando llegan; así un solo hilo atiende muchas cosas.
    6. La energía y la memoria se presupuestan antes de escribir código, y lo que no se midió no se sabe.
    7. Un sistema se protege en capas: validación de datos, límites de software, watchdog y, para lo peligroso, un corte físico independiente del programa.
    8. Depurar es medir: reproducir, describir el síntoma con exactitud, bisectar desde la capa de abajo, cambiar una cosa por vez y entender la causa antes de cerrar.

    Si hubo una sola idea que atravesó todo el curso, es esta: el firmware no es una abstracción, es una conversación con el hardware, y la conversación sale bien cuando se conoce el idioma, se respetan los tiempos y se verifica cada respuesta. Eso se transfiere a cualquier chip, a cualquier sensor y a cualquier proyecto que quieras construir.

    14 · Comprensión

    Confusiones frecuentes

    «Si el código es correcto, el problema no puede ser mío»

    Un programa correcto sobre un reloj equivocado, un cable flojo o una tensión que cae falla igual. La mitad de los problemas de firmware viven fuera del código. Por eso se depura de abajo hacia arriba y se mide antes de editar.

    «Imprimir por serie es suficiente para depurar»

    Sirve para muchas cosas, pero cuesta tiempo (a 9600 baudios, un carácter son 1,04 ms), puede ocultar condiciones de carrera y es inútil si el fallo es la propia UART o el reloj. Un pin de traza y un analizador lógico no alteran el sistema.

    «Cambiar cosas hasta que funcione»

    Si se cambian varias cosas a la vez y el problema desaparece, no se sabe cuál fue la causa y probablemente vuelva. Cambiar una sola cosa por vez y medir es más lento al principio y mucho más rápido en total.

    «Una frecuencia con 2 % de error está bien»

    Depende de para qué. En una UART, cada extremo tolera cerca de ±2 % y los errores de los dos extremos se suman. En un reloj de pared, 2 % son casi media hora por día. El mismo número es perfecto para una cosa y desastroso para otra: hay que preguntarse qué se hace con el valor.

    «Al terminar este curso ya sé microcontroladores»

    Se sabe lo esencial para entender cualquier otro y construir proyectos propios. Lo que sigue (sensores específicos, radio, tiempo real, otras familias) se apoya en esto y se aprende construyendo.

    15 · Práctica guiada

    Predecí antes de comprobar

    1. Velocidad de la UART

    Un diseño usa un reloj de 8 MHz y 115 200 baudios. ¿Qué UBRR y qué error da? ¿Qué se puede hacer para mejorarlo?

    Ver solución

    Con velocidad doble: 8 MHz / (8 · 115 200) = 8,68 → 9, UBRR = 8; velocidad real = 8 MHz / (8 · 9) = 111 111 baudios, un error de −3,55 %. Sin velocidad doble el resultado es peor: 8 MHz / (16 · 115 200) = 4,34 → UBRR = 3, 125 000 baudios, +8,5 %. Se mejora cambiando el reloj a 7,3728 u 11,0592 MHz (exactos) o bajando la velocidad a 57 600 baudios (+2,12 % con UBRR = 16 y U2X), o 38 400 baudios.

    2. Un temporizador

    Con un reloj de 16 MHz se quiere una interrupción de 250 Hz con un temporizador de 8 bits en modo CTC. ¿Qué prescaler y qué OCR usás?

    Ver solución

    Con el prescaler 256: 16 MHz / (256 · 250) = 250 cuentas, o sea OCR = 249, exacto y dentro de las 256 cuentas del temporizador. Con el prescaler 1024 serían 62,5 cuentas: se redondea a 63 y el error es de −0,8 %. Con el 64, 1000 cuentas, que no entran en 8 bits.

    3. Cuántas mediciones

    Un sistema tiene 32 puntos donde se puede medir una señal, uno tras otro, y una falla en alguno. ¿Cuántas mediciones hacen falta por bisección, y cuántas de media si se mide en orden?

    Ver solución

    Por bisección, log2 32 = 5 mediciones. En orden, la media es (32 + 1) / 2 = 16,5 y el peor caso, 32. La ventaja crece con el tamaño: con 1024 puntos son 10 contra 512.

    4. El ancho de bit

    Un programa debe transmitir a 9600 baudios y el analizador lógico mide un ancho de bit de 832 µs. ¿Qué indica? ¿Qué se revisa primero?

    Ver solución

    Un bit a 9600 baudios debe medir 104 µs; 832 / 104 = 8. El reloj es 8 veces más lento que el que supone el código: el síntoma clásico del fusible CKDIV8 (el oscilador interno de 8 MHz dividido por 8, o sea 1 MHz en lugar de 8). Se revisan los fusibles y la definición de F_CPU; después se recalcula UBRR.

    5. La cuenta del ADC

    Un ADC de 12 bits con referencia de 3,3 V mide un LM35 de 10 mV/°C. ¿Cuántos °C vale una cuenta? ¿Y con un ADC de 10 bits y 5 V?

    Ver solución

    Con 12 bits y 3,3 V: 3,3 V / 4096 = 0,806 mV por cuenta, o 0,0806 °C. Con 10 bits y 5 V: 5 V / 1024 = 4,88 mV, o 0,488 °C: seis veces más grueso. Con la referencia interna de 1,1 V y 10 bits: 0,107 °C. Elegir la referencia acorde al rango de la señal es la forma más barata de ganar resolución.

    16 · Síntesis

    Ideas para recordar

    • Un sistema con microcontrolador se entiende por capas, desde la alimentación y el reloj hasta la estructura del programa; cuando una capa falla arrastra a las de arriba.
    • Se depura de abajo hacia arriba, con método: reproducir, describir el síntoma con exactitud, formular una hipótesis refutable, bisectar el sistema, cambiar una cosa por vez y anotar.
    • Cada herramienta ve una parte: el multímetro, las tensiones estables; el osciloscopio, las formas de onda; el analizador lógico, los protocolos; el pin de traza, los tiempos; el depurador, los registros.
    • Observar cambia lo observado: un fallo que desaparece al medirlo apunta a temporización, a una condición de carrera o a una señal marginal.
    • Los síntomas raros suelen venir de abajo: reinicios y datos basura se originan en la alimentación, el reloj, la masa o la configuración, no en un error ingenioso del programa.
    • Un firmware que se instala lejos tiene que poder decir qué le pasó: causa del reset, contadores de eventos anómalos, aserciones y medición de la pila.
    • Pasar de prototipo a producto agrega protecciones, tolerancia a fallas, actualización, prueba de fábrica y documentación.
    • La estructura que se aprendió con el ATmega328P (reloj, registros, interrupciones, temporizadores, buses, ADC, energía) se repite en ARM, ESP32 y RP2040; solo cambian los nombres y las capas de ayuda.

    ¿Y ahora qué?

    Elegí un proyecto pequeño y completo que te interese —un termómetro con registro, un control de un motor, un sensor que publica sus datos— y construilo de principio a fin: diseño, esquema, firmware, verificación con instrumentos. Cuando algo falle, aplicá el método de este tema. Cuando funcione, medí su consumo y escribí lo que aprendiste.

    Con eso termina el curso de Microcontroladores para Programadores. La ruta continúa con el curso 8, Sensores y Actuadores, que parte de esta base para profundizar en cómo se mide y se actúa sobre el mundo físico.