← Índice del curso

Circuitos Secuenciales y Memoria · Tema 36

Cierre y puente a microcontroladores

Un microcontrolador no es una caja negra: es un procesador rodeado de bloques que ya conocés. Su puerto de entrada y salida es un registro con un buffer, su timer es un contador con un comparador, su SPI es un registro de desplazamiento, su UART es un registro de desplazamiento con una máquina de estados, su interrupción es un latch con sincronizador y su Flash es una memoria. Este tema cierra el curso con tres habilidades: elegir bloques a partir de requisitos, depurar con cronogramas y reconocer los periféricos de un microcontrolador como los bloques del curso.

01 · Lo que recorriste

Lo que recorriste

El curso fue una escalera con cuatro tramos, cada uno apoyado en el anterior:

Mapa del curso en cuatro ideas.
TramoTemasIdea que quedó
Recordar con realimentación1 a 12Dos compuertas cruzadas forman un latch; con un reloj y una disciplina de tiempos (preparación y retención) se convierten en flip-flops, el átomo de la memoria sincrónica
Registros y contadores13 a 21Con flip-flops se arman registros que guardan, registros que desplazan, contadores que cuentan y anillos que circulan
Máquinas de estados22 a 25Estado + entradas → estado siguiente y salidas: una tabla y un registro describen cualquier comportamiento secuencial
Memoria y tiempo26 a 33Las memorias son tablas direccionables (SRAM, DRAM, ROM, EEPROM, Flash); el tiempo se genera con osciladores, divisores y comparaciones
Proyectos34 y 35Un semáforo con máquina de estados y un secuenciador con memoria: la misma cosa, una vez en lógica y otra en datos

02 · Elegir bloques

Elegir bloques a partir de requisitos

Ante un problema nuevo, el primer error es empezar a conectar integrados. El método de los dos proyectos fue siempre el mismo: requisitos numerados, bloques con interfaces claras, verificación en código y recién entonces el armado. La decisión clave es qué bloque corresponde a cada necesidad:

De la necesidad al bloque.
Necesito…BloqueDónde lo viste
Recordar un bit o una palabraLatch, flip-flop, registroTemas 5 a 13
Pasar de paralelo a serie, o al revésRegistro de desplazamiento (74HC595, 74HC165)Temas 14 a 16
Contar eventos o medir tiempoContador y comparadorTemas 17 a 20 y 32
Un comportamiento que depende de lo que pasó antesMáquina de estados: registro + tabla de próximo estadoTemas 22 a 25 y 34
Almacenar muchas palabras o una tabla fijaRAM, ROM, EEPROM o FlashTemas 26 a 31
Una secuencia larga de salidasContador + ROMTema 35
Una frecuencia exactaCristal + divisorTemas 32 y 33
Aceptar una señal asíncronaAntirrebote + latch + sincronizador de dos flip-flopsTemas 11, 20 y 34
Ajustar una potencia o un brilloPWM: contador + comparadorTema 33

Cuatro preguntas ayudan a decidir: ¿hay memoria? (si la salida depende del pasado, hace falta estado), ¿hay tiempo? (si hay duraciones, hace falta una base de tiempo y un contador), ¿hay una entrada que no es del sistema? (si es asíncrona, hace falta sincronizarla), y ¿cambiará? (si el comportamiento va a cambiar, conviene que sea un dato y no un cableado).

03 · Depurar

Depurar con cronogramas

Un sistema secuencial falla en el tiempo: lo que está mal no es un valor, es un valor en un instante. La herramienta de depuración es el cronograma, la gráfica de varias señales contra el tiempo, obtenida con un analizador lógico o un osciloscopio de varios canales. Un método que sirve siempre:

  1. Definí el disparo. Elegí una señal de referencia (un flanco del reloj o una señal de inicio) y capturá siempre con el mismo disparo, para que las capturas sean comparables.
  2. Dibujá antes lo que esperás. Hacé el cronograma esperado a mano o en código; después compará. Es la misma disciplina del «predecí antes de simular».
  3. Mirá primero lo básico: alimentación, reloj (frecuencia y forma), reset (se libera después de que el reloj arranca).
  4. Buscá el primer desvío. No importa dónde termina mal, sino dónde se aparta primero de lo esperado; la causa está en o antes de ese punto.
  5. Cambiá una sola cosa por vez y repetí la captura.
Síntomas y causas típicas, con el tema donde las viste.
Síntoma en el cronogramaCausa probableTema
Pulsos angostos o dobles en una salida de ROM o de compuertasGlitch por entradas que no cambian a la vez; falta un registro de salida35
Un contador salta valores o cuenta de másRebotes en la entrada de reloj; falta Schmitt y antirrebote7 y 20
Un flip-flop queda a veces en un nivel intermedioMetaestabilidad: una entrada cambió cerca del flanco; falta sincronizador11
Un registro captura el dato viejoViolación de preparación o retención (dato tardío o reloj con desfasaje)8 y 13
La máquina arranca en un estado raroReset ausente o liberado antes que el reloj; estados no usados sin salida10, 24 y 34
Dos salidas en un bus pelean y se calientanDos tri-estados habilitados a la vez; falta decodificar con exclusión26 y 31
Datos leídos de una EEPROM o Flash incorrectosEscritura sin esperar el fin o lectura antes de tiempo (tiempos de acceso)29 y 30
El sistema falla solo con ruido o al cambiar de cargaFalta de condensadores de desacople de 100 nF o masa compartida2 y 35

El mismo método sirve en un microcontrolador: el analizador lógico no distingue si la señal sale de un 74HC o de un pin configurado como salida, y los problemas son los mismos (rebotes, glitches, metaestabilidad, reset, desacople).

04 · Periféricos

Los periféricos son bloques que ya conocés

Cuando abras la hoja de datos de un microcontrolador, la lista de periféricos va a parecer larga. Casi todos son uno de los bloques del curso con un registro de configuración al lado, que el procesador escribe y lee como si fuera una memoria:

Periférico de microcontrolador y el bloque del curso que contiene.
PeriféricoQué es por dentroTema
Puerto GPIOUn registro de salida (74HC574), un buffer de tres estados que lo conecta al pin y un buffer de lectura; un registro de dirección elige entre entrada y salida13 y 26
TimerContador con prescaler (divisor) y registro de comparación; el desborde o la igualdad son los eventos17, 19 y 33
PWMEl mismo contador comparado con un umbral: la salida es alta mientras la cuenta es menor33
SPIRegistro de desplazamiento con un contador de 8 pulsos y una bandera de fin (74HC595 más 74HC165)14 a 16
UARTRegistro de desplazamiento más una máquina de estados (inicio, 8 datos, parada) y un divisor de baudios14, 22 y 33
I²CMáquina de estados que maneja dos líneas de colector abierto con un registro de desplazamiento14 y 22
InterrupciónUn latch que memoriza el evento, un sincronizador y una máscara; la bandera se borra cuando se atiende, igual que el borrado de la solicitud del semáforo11 y 34
WatchdogUn contador (o monoestable) que reinicia al sistema si no se rearma a tiempo32
Reloj de la CPUOscilador de cristal o RC, divisores y multiplicadores (PLL)32 y 33
RAM internaSRAM: filas y columnas de celdas con decodificador de direcciones26 y 27
Flash de programaMemoria no volátil con borrado por bloques y ciclos limitados30
EEPROM de datosMemoria no volátil con escritura por byte y tiempos de espera29

Lo que cambia es que todos comparten un bus interno con la CPU: leer o escribir un registro de configuración es acceder a una dirección de un mapa de memoria, igual que en el tema 31. Un pin que parpadea se activa escribiendo un bit en la dirección de su puerto. El mapa de memoria que armaste con el 74HC138 es, en miniatura, el del microcontrolador.

05 · Hardware o software

Hardware o software: cómo decidir

Cada bloque del curso puede hacerse con integrados dedicados o con un programa en un microcontrolador. No hay una respuesta universal:

Comparación para decidir.
CriterioHardware dedicadoMicrocontrolador
VelocidadTodo en paralelo, a la velocidad del integrado (MHz a decenas de MHz)Una cosa por vez; cada ciclo de CPU cuenta; los periféricos corren en paralelo
CambiosSoldar o recablearReprogramar
DeterminismoTiempos exactos, sin sistema operativo ni interrupciones inesperadasDepende del código y las prioridades de interrupción
Complejidad lógicaCrece con la cantidad de integrados y cablesCrece con las líneas de código
Costo y tamañoPocos bloques: barato. Muchos: grandeUn chip con todo, por pocos dólares
ConsumoMuy bajo en reposo si solo cambia lo necesarioHay modos de bajo consumo, pero el reloj de la CPU cuenta
AprendizajeSe ve cada señalSe ve el programa, no las señales

Una regla práctica: lo que debe ser muy rápido, exactamente simultáneo o independiente del software va a hardware (en un microcontrolador, a un periférico: un timer, un SPI); lo que cambia a menudo o es complejo y lento (un menú, un protocolo de alto nivel) va a software. Entre los dos extremos están los dispositivos programables (FPGA y CPLD), que permiten describir circuitos como los de este curso y que el hardware ejecuta en paralelo.

06 · Lo que cambia

Lo que cambia en un microcontrolador

  • El reloj de la CPU no es el del sistema. El procesador ejecuta instrucciones, no «pasos de lógica»; el tiempo de cada una depende del reloj y del código. Para tiempos exactos se usan timers, no bucles de espera.
  • Las entradas asíncronas siguen existiendo. Cada pin sincroniza su entrada con dos flip-flops antes de que la CPU lo lea; una interrupción es un latch con prioridad. Los rebotes de un botón siguen necesitando un filtro, por hardware o por software.
  • El estado vive en variables. Una máquina de estados en software es una variable de estado y una estructura switch o una tabla indexada, es decir, la misma tabla de próximo estado. La verificación exhaustiva del tema 34 se traslada igual a las pruebas del programa.
  • La memoria es parte del sistema. El programa vive en Flash; los datos, en RAM; los parámetros que deben sobrevivir al apagado, en EEPROM o en Flash emulando EEPROM. Todo con los límites de ciclos y de tiempos que viste en los temas 29 y 30.
  • La corriente por pin sigue siendo un límite. Un pin típico maneja una corriente del orden de 10 a 25 mA, no más; las cargas mayores van con transistores o buffers, como los LED del tema 35.
  • El reset y el arranque son tan importantes como antes. Un microcontrolador sin un buen reset de encendido y sin desacople puede arrancar en estados impredecibles; el watchdog es el último recurso.

07 · El puente en código

Cuatro bloques del curso, dentro de un microcontrolador

Los bloques de código muestran el mismo registro de desplazamiento hecho con hardware y con un bucle, un timer calculado como lo hace un microcontrolador, una UART con su tolerancia a un error de velocidad y un antirrebote por software.

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

Paso 1: el registro de desplazamiento, en hardware y en un bucle

class Reg595:
    """Modelo del 74HC595: registro de desplazamiento de 8 bits + registro de almacenamiento (latch)."""

    def __init__(self):
        self.sr, self.q = 0, 0

    def shcp(self, ds):                       # flanco de SHCP: desplaza e ingresa DS por el bit 0
        self.sr = ((self.sr << 1) | ds) & 0xFF

    def stcp(self):                           # flanco de STCP: copia el registro de desplazamiento a las salidas
        self.q = self.sr


def enviar_hardware(chip, byte):
    for i in range(7, -1, -1):                # MSB primero
        chip.shcp((byte >> i) & 1)
    chip.stcp()


def enviar_software(estado, byte):
    """Lo que hace un microcontrolador con tres pines GPIO: la misma secuencia, en un bucle."""
    sr = estado["sr"]
    for i in range(7, -1, -1):
        bit = (byte >> i) & 1                 # poner DS
        sr = ((sr << 1) | bit) & 0xFF         # pulso en SHCP
    estado["sr"] = sr
    estado["q"] = sr                          # pulso en STCP


hw, sw = Reg595(), {"sr": 0, "q": 0}
iguales = True
for byte in (0x00, 0xA5, 0xFF, 0x3C, 0x81):
    enviar_hardware(hw, byte)
    enviar_software(sw, byte)
    iguales &= (hw.q == sw["q"] and hw.sr == sw["sr"])
    print(f"byte {byte:02X}: salidas del chip {hw.q:02X}, salidas del bucle de software {sw['q']:02X}")
print("el bucle de software reproduce al registro de hardware:", iguales)


def spi_intercambio(salida, entrada):
    """Un intercambio SPI de 8 bits: en cada pulso de reloj sale un bit propio y entra uno del otro lado."""
    recibido = 0
    for i in range(7, -1, -1):
        miso = (entrada >> i) & 1
        recibido = (recibido << 1) | miso
    return recibido


print(f"SPI: se enviaron 8 bits y se recibieron {spi_intercambio(0xA5, 0x3C):02X} (lo que tenía el otro lado)")
print("un periférico SPI de microcontrolador es este mismo registro de desplazamiento con un contador de 8 pulsos y una bandera 'terminé'")

El bucle que mueve tres pines (DS, SHCP, STCP) deja las mismas salidas que el 74HC595 para los cinco bytes de prueba. Esa es la razón por la que un SPI «por software» (bit-banging) funciona y por la que un SPI «por hardware» es lo mismo con un contador de ocho pulsos y una bandera: la diferencia es quién genera los pulsos, no qué hacen.

Paso 2: un timer, calculado como en la hoja de datos

import math

F_CPU = 16_000_000                       # reloj del microcontrolador (valor típico)
PRESCALERS = (1, 8, 64, 256, 1024)
BITS = 16                                # contador de 16 bits


def mejor(f_deseada):
    """Elige prescaler y valor de comparación (como los registros PSC y ARR de un timer)."""
    candidatos = []
    for p in PRESCALERS:
        arr = round(F_CPU / (p * f_deseada)) - 1
        if 1 <= arr < 2 ** BITS:
            real = F_CPU / (p * (arr + 1))
            candidatos.append((abs(real - f_deseada) / f_deseada, p, arr, real))
    return min(candidatos)


print("frecuencia pedida -> prescaler, valor de comparación (ARR), frecuencia real, error")
for f in (1, 10, 440, 1000, 20_000):
    e, p, arr, real = mejor(f)
    print(f"  {f:6d} Hz -> prescaler {p:4d}, ARR = {arr:6d}, real {real:11.4f} Hz, error {e * 100:.4f} %")

f = 1000
e, p, arr, real = mejor(f)
print(f"PWM de {f} Hz: el contador cuenta 0..{arr}; el pin está en alto mientras cuenta < comparador")
for duty in (0, 25, 50, 75, 100):
    cmp_ = round((arr + 1) * duty / 100)
    alto = sum(1 for n in range(arr + 1) if n < cmp_)
    print(f"  ciclo de trabajo {duty:3d} % -> comparador {cmp_:5d}; ciclos en alto {alto}/{arr + 1} = {100 * alto / (arr + 1):.2f} %")

print("resolución del PWM según la frecuencia (con prescaler 1):")
for f in (100, 1000, 20_000, 100_000):
    niveles = F_CPU // f
    print(f"  {f:7d} Hz: {niveles:6d} niveles = {math.log2(niveles):.1f} bits")
print("a mayor frecuencia, menos niveles: es el compromiso del contador del tema 33")

Con un reloj de 16 MHz, un contador de 16 bits y prescalers de 1 a 1024, se obtienen 1 Hz (prescaler 256, ARR = 62 499), 10 Hz (prescaler 64, ARR = 24 999) y 1 kHz (prescaler 1, ARR = 15 999) sin error. En 440 Hz el error es de 0,001 %. En un PWM de 1 kHz el ciclo de trabajo se fija con el comparador (4000, 8000 y 12 000 para 25, 50 y 75 %), y la resolución cae de 17,3 bits a 100 Hz a 7,3 bits a 100 kHz: el compromiso entre frecuencia y resolución del tema 33. Los 16 MHz y los prescalers son valores típicos usados como ejemplo, no los de un modelo particular.

Paso 3: una UART y su tolerancia al error de velocidad

def trama(byte):
    """Trama UART 8N1: start (0), 8 bits de datos LSB primero, stop (1)."""
    return [0] + [(byte >> i) & 1 for i in range(8)] + [1]


def recibir(byte, error, f=0.5):
    """El receptor detecta el flanco de bajada y muestrea en (k + f) de SU período de bit.
    error: diferencia relativa entre el período del receptor y el del transmisor."""
    bits = trama(byte)
    muestras = []
    for k in range(10):
        t = (k + f) * (1 + error)               # instante de muestreo, en períodos del transmisor
        idx = int(t // 1)                        # bit que está presente en la línea en ese instante
        muestras.append(bits[idx] if idx < 10 else 1)
    dato = sum(b << i for i, b in enumerate(muestras[1:9]))
    ok = muestras[0] == 0 and muestras[9] == 1 and dato == byte
    return dato, ok


print("recepción de 0x55 y 0x41 con distintos errores de velocidad (muestreo a mitad del bit):")
for e in (0.0, 0.02, 0.04, 0.05, 0.06, -0.04, -0.06):
    r55, ok55 = recibir(0x55, e)
    r41, ok41 = recibir(0x41, e)
    print(f"  error {e * 100:+5.1f} %: 0x55 -> {r55:02X} {'bien' if ok55 else 'MAL '}   0x41 -> {r41:02X} {'bien' if ok41 else 'MAL '}")


def tolerancia(f):
    """Mayor error simétrico que todavía recibe bien TODOS los bytes."""
    e = 0.0
    while e < 0.2:
        e2 = e + 0.0005
        if not all(recibir(b, s * e2, f)[1] for b in range(256) for s in (1, -1)):
            return e
        e = e2
    return e


print()
print("tolerancia del error de velocidad según el punto de muestreo (con los 256 bytes posibles):")
for f in (0.25, 0.5, 0.75):
    print(f"  muestreo al {int(f * 100):2d} % del bit: tolera ±{tolerancia(f) * 100:.1f} %")
print("el teórico para muestrear a mitad del bit es ±5,26 %: 9,5 períodos del receptor deben quedar dentro de 9 a 10 del transmisor")

for nombre, ppm in (("cristal de 20 ppm", 20), ("oscilador RC interno (±2 %)", 20000)):
    e = ppm * 1e-6
    ok = all(recibir(b, 2 * e)[1] for b in range(256))
    print(f"  {nombre}: dos equipos con el peor error opuesto difieren {2 * e * 100:.3f} % -> {'funciona' if ok else 'falla'}")

Con el muestreo a mitad del bit, 0x55 y 0x41 se reciben bien hasta ±5 % de diferencia de velocidad y mal a ±6 % (el receptor lee D5 y C1: la muestra de D7 cae en el bit de parada y lee un 1). Probando los 256 bytes, la tolerancia es de ±5,3 % al 50 % del bit, pero solo ±2,7 % al 25 % y ±2,9 % al 75 %: el punto de muestreo en el centro es el que más margen deja. Dos cristales de 20 ppm difieren 0,004 %, y dos osciladores RC de ±2 % podrían diferir 4 %: dentro del límite de 5,3 % en teoría, pero sin margen real para jitter y para la detección del flanco inicial, por eso las comunicaciones serie serias usan cristal.

Paso 4: un antirrebote por software

import random


def senal_con_rebotes(rnd, inicio, duracion=600):
    """Una pulsación mecánica muestreada a 1 kHz: unos ms de rebotes al cerrar, contacto firme y rebotes al abrir."""
    linea = [0] * duracion
    t = inicio
    for _ in range(rnd.randint(3, 8)):          # al cerrar: alternancias breves
        linea[t] = 1
        t += rnd.randint(2, 3)
    fin = inicio + 300
    for k in range(t, fin):
        linea[k] = 1
    t = fin
    for _ in range(rnd.randint(3, 8)):          # al abrir: pulsos sueltos
        linea[t] = 1
        t += rnd.randint(2, 3)
    return linea


def flancos(senal):
    return sum(1 for a, b in zip(senal, senal[1:]) if a != b)


class Integrador:
    """Antirrebote por software: el contador sube con 1, baja con 0 y satura; la salida cambia solo en los extremos."""

    def __init__(self, maximo=10):
        self.n, self.maximo, self.salida = 0, maximo, 0

    def muestra(self, x):
        self.n = min(self.maximo, self.n + 1) if x else max(0, self.n - 1)
        if self.n == self.maximo:
            self.salida = 1
        elif self.n == 0:
            self.salida = 0
        return self.salida


rnd = random.Random(36)
total_crudo, total_filtrado, eventos_ok = 0, 0, 0
for _ in range(200):
    cruda = senal_con_rebotes(rnd, inicio=100)
    filtro = Integrador(10)
    limpia = [filtro.muestra(x) for x in cruda]
    total_crudo += flancos(cruda)
    total_filtrado += flancos(limpia)
    eventos_ok += (flancos(limpia) == 2)
print(f"200 pulsaciones con rebotes: flancos en la línea cruda {total_crudo} (promedio {total_crudo / 200:.1f}); tras el filtro {total_filtrado} (promedio {total_filtrado / 200:.1f})")
print(f"pulsaciones que dejan exactamente un cierre y una apertura: {eventos_ok}/200")

ej = senal_con_rebotes(random.Random(5), inicio=100)
f = Integrador(10)
limpia = "".join(str(f.muestra(x)) for x in ej)
print("primeras muestras de una pulsación:", "".join(str(x) for x in ej[98:130]))
print("tras el filtro:                    ", limpia[98:130], "(retardo del orden de 10 ms)")
print("el integrador es el equivalente de software del filtro RC y la compuerta Schmitt del tema 20: la constante de tiempo es el contador")

En 200 pulsaciones simuladas, la línea cruda tiene en promedio 21,8 flancos por pulsación (rebotes de cierre y apertura) y, después de un integrador de 10 muestras, exactamente 2,0: un cierre y una apertura, en las 200 de 200 pulsaciones. El retardo es del orden de 10 ms, porque la constante de tiempo ahora es un contador. Es el mismo trabajo que el filtro RC y la compuerta Schmitt del tema 20, hecho con una variable.

Los cuatro pasos muestran el patrón del puente: lo que hacía un circuito pasa a ser un registro de configuración o un bucle, pero la lógica, las tablas y los problemas de tiempo son los mismos.

08 · Exploración interactiva

El laboratorio: cronograma de una UART

Una UART es el mejor ejemplo de un periférico que es registro de desplazamiento, máquina de estados y divisor de reloj. El laboratorio muestra la trama 8N1 de un carácter (inicio en 0, ocho datos con el bit menos significativo primero, parada en 1) y los instantes en que el receptor la muestrea cuando su velocidad no coincide con la del transmisor. Verde: el receptor lee lo que se envió. Rojo: lee el bit vecino.

Receptor UART con error de velocidad

Cronograma de una trama UART Una forma de onda de diez bits: inicio, ocho datos y parada, con líneas verticales en los instantes en que el receptor toma muestras. Las muestras correctas se dibujan en verde y las que caen en un bit vecino en rojo. Debajo, el valor leído en cada bit y el valor transmitido.
Enviado55
Recibido55
Bits leídos mal0 de 10
Trama (inicio y parada)correcto
Margen mínimo al borde del bit50.0 % del bit

Sin error de velocidad, el receptor muestrea siempre en el centro de cada bit. Movelo y mirá cuándo se cae un bit.

Muestras del receptor, bit por bit (instante en períodos del transmisor).
BitInstante de muestreoBit presente en la líneaEnviadoLeído
Cargando…

Recorrido guiado

  1. Con el error en 0 y el muestreo al 50 %, cada línea cae en el centro de su bit: el margen es de 50 % hacia cada borde.
  2. Subí el error de a poco. El margen se achica y las líneas se corren hacia la derecha. Los últimos bits son los que primero se acercan al borde, porque acumulan el desvío de varios períodos.
  3. Pasá de +5,9 %: la muestra de D7 cae en el bit de parada y se lee un 1 en lugar del dato. Del otro lado, a −5,3 % la muestra de la parada cae sobre D7. Por eso el límite que vale para todos los caracteres es el menor de los dos, ±5,3 %.
  4. Con «Hallar el error máximo tolerado» obtenés el límite para el carácter y el punto de muestreo actuales. Probalo con 0xFF, con 0x00 y con 0x55 y compará: cada carácter tiene su propio límite, pero el del sistema es el del peor carácter.
  5. Movés el punto de muestreo al 25 % o al 75 %: el límite baja a la mitad, porque la muestra empieza más cerca de un borde.
  6. Pensá en el hardware de la UART: un divisor genera 16 ticks por bit; un contador de 3 a 4 bits alinea el muestreo al centro; un registro de desplazamiento junta los 8 bits; una máquina de estados cuenta los diez bits. Todo es del curso.
Desafío: tres muestras por bit

Muchos receptores toman tres muestras alrededor del centro y deciden por mayoría. ¿Cómo cambiaría la tolerancia al error de velocidad y al ruido? Con la mayoría, un pulso de ruido de una sola muestra no cambia el bit, pero el tramo de tres muestras ocupa parte del bit y, con error de velocidad grande, la muestra extrema se acerca al borde: se gana inmunidad al ruido y se pierde algo de tolerancia al error de velocidad.

09 · Qué estudiar después

Qué estudiar después

El curso termina acá, pero el camino sigue por varias ramas. Elegí la que más te sirva:

Siguientes pasos posibles.
Si querés…EstudiáQué vas a reconocer
Programar placas pequeñasUn microcontrolador de 8 o 32 bits: GPIO, timers, interrupciones, UART, SPI, I²CTodos los periféricos de la sección 4
Describir circuitos en lugar de armarlosUn lenguaje de descripción de hardware y una FPGALas máquinas de estados y los contadores del curso, escritos como código y ejecutados en paralelo
Entender cómo se construye una computadoraArquitectura de computadoras y organización de un procesadorRegistros, buses, memoria, contadores de programa y una máquina de estados enorme
Conectar con el mundo físicoElectrónica analógica, sensores, ADC y DACEl comparador, el filtro RC y la tensión de umbral, ahora en el lado continuo
Diseñar sistemas confiablesSincronización entre dominios de reloj, verificación, tolerancia a fallosLos sincronizadores, los estados seguros y las verificaciones exhaustivas del curso

10 · Comprensión

Confusiones frecuentes

«Un microcontrolador reemplaza todo lo del curso»

Lo contiene, pero no lo elimina: sus periféricos son esos bloques, y los problemas de tiempo, rebotes y metaestabilidad persisten. Entender los bloques es lo que permite configurarlos bien.

«Un bucle de espera es un buen temporizador»

Su duración depende del compilador y del reloj, y bloquea al procesador. Un timer cuenta con el reloj del sistema, sin consumir instrucciones.

«Si el programa es correcto, las señales también»

El programa puede ser correcto y el pin tener rebotes, ruido o un desacople insuficiente. Se verifica en el cronograma, no solo en el código.

«Más velocidad de comunicación siempre es mejor»

Más velocidad deja menos margen de tiempo y exige un reloj más exacto. Se elige la menor que cumpla el requisito.

«Los osciladores internos RC alcanzan para una UART»

Con ±2 % en cada extremo se puede llegar al 4 % de diferencia, cerca del límite de 5,3 %. Sin margen para jitter ni para detectar el flanco inicial. Con cristal, la diferencia es de ppm.

«Una interrupción es instantánea»

Hay latencia: la señal se sincroniza, la CPU termina la instrucción en curso, guarda su contexto y salta. Una bandera que no se borra vuelve a disparar.

«El hardware es más difícil que el software»

Es distinto: más lento de modificar, pero cada señal se puede medir. Un buen diseñador de sistemas conoce las dos mitades y decide cuál usar para cada bloque.

«Al terminar el curso ya no hace falta repasar la base»

Los temas 7, 11 y 20 (rebotes, metaestabilidad y entradas limpias) vuelven a aparecer en cada sistema real. Vale la pena revisarlos con la mirada de los proyectos.

11 · Práctica guiada

Predecí antes de simular

1. Identificar el bloque

La hoja de datos de un microcontrolador dice: «contador de 16 bits con prescaler y registro de captura/comparación». ¿Qué bloques del curso son?

Ver solución

Un contador (temas 17 a 19) con un divisor de frecuencia delante (prescaler) y un comparador con un registro (temas 13 y 33). Es el diseño del PWM del tema 33.

2. Calcular un timer

Con un reloj de 8 MHz y prescaler 8, ¿qué valor de comparación da una interrupción cada 100 ms?

Ver solución

Frecuencia del contador = 8 000 000 / 8 = 1 MHz. Para 100 ms hacen falta 100 000 cuentas: ARR = 100 000 − 1 = 99 999, que no entra en 16 bits (máximo 65 535). Con prescaler 64: 125 kHz y 12 500 cuentas, ARR = 12 499.

3. Tolerancia de una UART

Dos equipos usan osciladores de ±1 %. ¿Pueden comunicarse en 8N1 con muestreo a mitad del bit?

Ver solución

La diferencia máxima es 2 %, menor que el límite de ±5,3 %: sí, con 3 puntos de margen. Con ±3 % cada uno, la diferencia de 6 % ya supera el límite.

4. Hardware o software

Un sistema debe generar un pulso de 10 µs de ancho exacto cada vez que llega un flanco de una entrada, sin importar lo que haga el procesador. ¿Dónde lo hacés?

Ver solución razonada

En hardware: un monoestable digital (contador + comparador, tema 32) o el periférico de captura y comparación de un timer, que dispara la salida sin intervención del procesador. En software, la latencia de la interrupción haría variar el ancho.

5. Antirrebote

Con muestreo cada 1 ms y rebotes de hasta 10 ms, ¿qué saturación del integrador alcanza? ¿Qué pasa si se usa un valor de 3?

Ver solución

Un valor de 15 a 20 muestras cubre cómodamente 10 ms de rebotes. Con 3, un tren de rebotes con más de tres unos seguidos puede saturar el contador y producir salidas falsas antes de que el contacto se estabilice.

6. Diagnóstico

Un microcontrolador lee un botón en un pin y cuenta cada pulsación, pero cuenta de 3 a 5 de cada vez. ¿Qué falta y cómo se confirma?

Ver solución razonada

Falta un antirrebote, por hardware (RC y Schmitt) o por software (integrador, o ignorar el pin durante unos 20 ms tras el primer flanco). Se confirma capturando el pin con un analizador lógico: se verá una ráfaga de flancos al cerrar y al abrir.

12 · Síntesis final

Ideas para llevarte

  • Todo sistema secuencial se arma con pocos bloques: memoria de un bit (latch y flip-flop), registros, contadores, comparadores, tablas (ROM) y una disciplina de reloj.
  • Una máquina de estados es un registro más una tabla de próximo estado y salidas; una secuencia de salidas es un contador más una tabla. Con datos en lugar de cableado, el comportamiento cambia sin tocar el circuito.
  • El tiempo se mide contando un reloj estable; la exactitud la da el cristal y el divisor, no la lógica.
  • Las entradas externas se filtran (antirrebote), se memorizan (latch) y se sincronizan (dos flip-flops); las salidas de lógica combinacional se registran antes de usarlas.
  • Un buen diseño nace de requisitos numerados, se divide en bloques con interfaces claras, se verifica en código y se arma por etapas.
  • Depurar es comparar un cronograma esperado con uno medido, buscando el primer desvío y cambiando una cosa por vez.
  • Los periféricos de un microcontrolador (GPIO, timer, PWM, SPI, UART, interrupciones, watchdog, memorias) son los bloques del curso, accesibles desde un mapa de memoria.
  • Elegir entre hardware y software es una decisión de velocidad, determinismo, flexibilidad y costo, que se toma bloque por bloque.

Fin del curso

Si podés explicar con tus palabras cómo se pasa de un latch a un flip-flop, cómo un contador y una ROM generan una animación, por qué una entrada asíncrona necesita un sincronizador y qué hace por dentro un timer de microcontrolador, el curso cumplió su objetivo. El resto es práctica: armar, medir, equivocarse y volver al cronograma.