← Índice del curso

Circuitos Secuenciales y Memoria · Tema 35

Proyecto: secuenciador con memoria

El tema 34 puso la secuencia en la lógica de una máquina de estados. Acá se hace lo contrario: la lógica es mínima (un contador y una memoria) y la secuencia es un dato. Un contador recorre direcciones, una ROM guarda en cada dirección el patrón de ocho luces que corresponde, y cambiar la animación es cambiar el contenido de la memoria, no el circuito. Es el ejemplo más claro de la idea que une todo el curso: una tabla almacenada más un contador equivalen a una máquina de estados.

01 · Requisitos

Requisitos

Un tablero de ocho LED que muestra animaciones. Como en el tema anterior, se empieza por lo que el sistema debe hacer:

Requisitos del secuenciador.
N.ºRequisitoValor
R1Ocho LED mostrando un patrón distinto en cada paso8 salidas
R2Cuatro animaciones seleccionables: ping-pong, llenado y vaciado, alternado y código Gray2 bits de modo
R3Cada animación tiene su propia longitud (de 2 a 16 pasos) y se repite sin interrupción≤ 16 pasos
R4Velocidad elegible entre cuatro valores1, 2, 4 y 8 Hz
R5Cambiar o agregar una animación no debe requerir modificar el circuitosolo datos
R6Los LED no deben mostrar destellos ajenos a la animación (sin glitches)—
R7Cambiar de modo en pleno funcionamiento no puede dejar el contador en un paso inexistente—
R8El consumo total de los LED no debe superar los límites del integrado que los maneja≤ 50 mA

02 · Arquitectura

Arquitectura: un contador y una tabla

Bloques del secuenciador Un cristal y un divisor producen el reloj. El reloj avanza un contador de cuatro bits. Las salidas del contador y los dos bits de modo forman la dirección de seis bits de la ROM. La ROM entrega ocho bits de luces a un registro de salida que maneja los LED, y un bit END que borra el contador para empezar de nuevo. Cristal + divisorselector 1 a 8 Hz Contador de paso4 bits (74HC163) Selector de modo2 interruptores ROM64 palabras{modo, paso} → 8 LED + END Registrode salida(74HC574) 8 LED relojpaso (4)modo (2)LED (8)END → borrar contador
Bloques, qué hacen y de qué tema vienen.
BloqueFunciónSe estudió en
Base de tiempoCristal de 32 768 Hz, divisor y selector de cuatro velocidadesTemas 17, 33 y 34
Contador de pasoCuenta de 0 a 15 y se borra de forma síncrona cuando la ROM lo pideTemas 18 y 19
ROMTabla: para cada {modo, paso}, el patrón de luces y el bit ENDTemas 26 a 28
Registro de salidaRetiene el patrón y cambia las luces solo en el flancoTemas 13 y 14
Selector de modoDos interruptores que eligen la animaciónTema 31 (mapa de memoria)

Compará con el semáforo. Allí, la tabla de próximo estado decidía a dónde ir y un contador medía el tiempo. Acá el «próximo estado» es siempre el paso siguiente (un simple incremento) salvo cuando la palabra dice END. Es una máquina de estados degenerada en la que el único salto posible es volver a cero, y por eso alcanza un contador en lugar de una ROM de control. El costo es la flexibilidad: no hay entradas que decidan el camino.

03 · La ROM

Organizar la ROM como tabla de animaciones

La dirección de seis bits es la concatenación {modo, paso}: los dos bits altos eligen la animación y los cuatro bajos son la salida del contador. Cada animación ocupa un bloque de 16 palabras contiguas, como las páginas del tema 31.

Mapa de la ROM (64 palabras).
ModoDireccionesAnimaciónPasosQué muestra
000 a 15Ping-pong14Un LED que va de D0 a D7 y vuelve sin repetir los extremos
0116 a 31Llenado y vaciado16Barra que crece de 1 a 8 LED y vuelve a apagarse
1032 a 47Alternado2AA y 55: los pares y los impares
1148 a 63Gray16El código Gray de 4 bits repetido en los dos nibbles

Cada palabra tiene 9 bits: ocho de luces y uno de control (END). Si no hay ROM de 9 bits, se usan dos de 8 con la misma dirección, o una sola con dos mitades. Para los pasos que sobran en una animación corta (por ejemplo, los 14 pasos que no usa «alternado») la palabra se rellena con luces apagadas y END = 1: si por un cambio de modo el contador cae en una fila vacía, la próxima transición lo devuelve al paso 0 (R7).

Pensalo como tabla de verdad: la ROM es una función combinacional de seis entradas y nueve salidas, escrita por extensión, fila por fila (tema 28). No hay compuertas por diseñar: se enumera el comportamiento deseado.

04 · Longitud variable

Longitud variable con el bit END

Un contador de 4 bits recorre 16 pasos y vuelve a cero solo. Para una animación de 14 pasos, o de 2, hay que forzar la vuelta antes. La solución es agregar a cada palabra un bit que diga «este es el último paso»:

  • La salida END de la ROM se conecta a la entrada de borrado síncrono del contador (/CLR del 74HC163, con inversión si hace falta).
  • Mientras END = 0, el contador incrementa en cada flanco; cuando END = 1 en el paso actual, el próximo flanco lo lleva a 0 en lugar de a paso + 1.
  • La longitud de la animación es la posición del primer END, más uno. Cambiarla es mover ese bit en la tabla.

Como el borrado es síncrono, el último paso se muestra durante un ciclo completo y la transición ocurre en el flanco, igual que cualquier otro paso. Con un borrado asíncrono, el último paso aparecería solo un instante (y generaría su propio glitch). Es la razón por la que el 74HC163 (síncrono) es mejor para este diseño que el 74HC161 (asíncrono).

La ventaja del esquema es la autorrecuperación: como las filas vacías llevan END = 1, ni un cambio de modo ni una perturbación del contador pueden dejar al sistema atascado fuera de la secuencia. Es el mismo principio de «estados no usados al estado seguro» del tema 34, aplicado ahora a datos.

05 · Glitches

Glitches y registro de salida

Los cuatro bits del contador no cambian exactamente a la vez: cada flip-flop y cada ruta de cable tiene su propio retardo. Cuando el contador pasa de 3 (0011) a 4 (0100), puede que el bit que baja llegue después que el que sube (o al revés), y durante algunos nanosegundos la ROM recibe una dirección que no es ninguna de las dos: por ejemplo 0111. Si la ROM entrega la palabra de esa dirección, los LED muestran un patrón falso.

Una transición con glitch, en el modo ping-pong (los bits que bajan llegan tarde).
InstantePaso (binario)Dirección que ve la ROMLED
Antes del flanco0011 (3)308
Un instante después0111 (el bit 2 ya subió, el 0 y el 1 todavía no bajaron)780 (glitch)
Estabilizado0100 (4)410

El efecto a simple vista es invisible (dura nanosegundos y el ojo no lo integra), pero se convierte en problema apenas la salida maneje algo más sensible que un LED: un contador, un latch o un reloj. Y en cualquier caso es un diseño incorrecto que conviene evitar desde el principio. Hay dos soluciones:

  • Registro de salida (la estándar). Las salidas de la ROM no van a los LED sino a un 74HC574 que las captura en el flanco del reloj. El registro solo copia cuando la ROM ya estabilizó (el período de reloj es mucho más largo que el retardo de la ROM) y entrega a los LED una salida limpia, sincronizada. La animación se atrasa un ciclo, lo que no importa.
  • Código Gray en el contador. Si cada transición cambia un solo bit, no existe dirección intermedia. Funciona para una secuencia completa de 16 pasos, pero no para longitudes arbitrarias (el borrado por END cambiaría varios bits de golpe), así que como solución general se prefiere el registro.

06 · Velocidad y corriente

Velocidad y corriente

Frecuencia de reloj

El ojo necesita pasos de entre 100 ms y 1 s para seguir una animación. Del divisor del cristal (74HC4060, tema 33) se toman cuatro salidas con un selector de cuatro posiciones; el período de cada paso queda entre 125 ms y 1 s. Con 8 Hz, el ping-pong de 14 pasos tarda 1,75 s en recorrer el tablero; con 1 Hz, 14 s.

El lazo contador → ROM → registro podría trabajar a unos 4,5 MHz con tiempos típicos (20 ns del contador, 150 ns de acceso de una ROM de esa clase y 15 ns de preparación del registro, con 20 % de margen). A 8 Hz la lógica está unas 560 000 veces por debajo de su límite: la velocidad la manda el ojo, no el circuito.

Corriente de los LED

Cada salida de la familia 74HC maneja unos 25 mA como máximo, pero el integrado completo tiene un límite de unos 50 mA por las patas de alimentación. Con ocho LED rojos (tensión directa cercana a 2 V) y una caída del orden de 0,4 V en el registro:

Corriente de los LED con distintas resistencias (5 V, valores aproximados).
ResistenciaPor LEDCon los 8 encendidosComentario
330 Ω7,9 mA63,0 mASupera el límite del integrado
470 Ω5,5 mA44,3 mACerca del límite
1 kΩ2,6 mA20,8 mASeguro; LED menos brillantes, suficientes con un LED de alta eficiencia

Con LED comunes lo prudente es 1 kΩ o un buffer de corriente (un ULN2803 que maneja 500 mA por canal, o transistores). Es el R8: lo que se cumple con números, no con intuición.

07 · Armado

Armado y pruebas por etapas

Lista de componentes.
Cant.ComponenteFunción
1 + 1Cristal de 32 768 Hz y 74HC4060Base de tiempo (varias salidas del divisor)
1Selector de 4 posiciones (o un 74HC153)Elige entre 1, 2, 4 y 8 Hz
174HC163Contador de paso con borrado síncrono
1 o 2ROM de 8 bits (por ejemplo, una 28C64) o dosLED y bit END
174HC574Registro de salida de 8 bits
8LED y resistencias de 1 kΩSalida visible
2InterruptoresModo (dos bits)
varios100 nF por chip, protoboard y fuente de 5 VAlimentación
  1. Reloj. Un LED en cada posición del selector debe parpadear a 1, 2, 4 y 8 Hz. Cronometrar 60 s en la posición más lenta.
  2. Contador. Con reloj lento, ver los cuatro bits contar 0 a 15 en LED provisorios y comprobar que vuelve a 0.
  3. ROM sin programa de usuario. Con la ROM ya grabada, forzar la dirección con interruptores y comprobar tres o cuatro palabras de cada modo con un multímetro o LED.
  4. Lazo completo sin registro. Conectar la ROM a los LED y observar las cuatro animaciones. Comprobar que cada una se repite con su longitud: 14, 16, 2 y 16 pasos.
  5. Registro de salida. Intercalar el 74HC574. Con un osciloscopio o analizador lógico, mirar una salida durante la transición del paso 3 al 4 sin y con registro: sin registro aparecen picos, con registro no.
  6. Cambio de modo en marcha. Cambiar los interruptores mientras corre una animación larga: el contador debe converger a la nueva secuencia en menos de un ciclo (R7).
  7. Aceptación. Recorrer R1 a R8 con la lista a mano y anotar el resultado.

08 · Programar la ROM

Programar y verificar la ROM

El contenido de la ROM se prepara en una computadora y se graba con un programador. El formato más común de intercambio es Intel HEX: texto en el que cada línea tiene la cantidad de bytes, la dirección de inicio, un tipo, los datos y una suma de verificación. Una línea de este proyecto:

:080000000102040810204080F9

Significa: 8 bytes (08), desde la dirección 0000, de tipo datos (00), con los bytes 01 02 04 08 10 20 40 80 y la suma F9 que hace que todos los bytes de la línea sumen cero módulo 256. Es el ping-pong en su primer tramo.

  • Un solo origen. Los patrones viven en un script (el del paso 4 de abajo), no en la mano del programador. Se regenera el archivo cada vez que cambia una animación.
  • Verificación antes de grabar. Se lee el HEX de vuelta y se compara con los datos esperados; se calcula una suma de control del contenido.
  • Verificación después de grabar. El programador lee la memoria y la compara contra el archivo. Para memorias EEPROM (tema 29) y Flash (tema 30) hay además ciclos de borrado y desgaste: se graba solo cuando hace falta.

Cambiar una animación es editar una lista de bytes y volver a grabar. No se vuelve a soldar nada. Es la meta del R5.

09 · El proyecto en código

Construir, comparar, calcular y programar

Los cuatro bloques construyen la ROM, miden los glitches con y sin registro, calculan velocidades y corrientes y arman la imagen Intel HEX con su verificación.

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

Paso 1: construir la ROM

def patron(modo):
    if modo == 0:                                   # ping-pong: 0..7 y vuelta 6..1
        pos = list(range(8)) + list(range(6, 0, -1))
        return [1 << p for p in pos]
    if modo == 1:                                   # llenado y vaciado
        return [0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00]
    if modo == 2:                                   # alternado
        return [0xAA, 0x55]
    return [(n ^ (n >> 1)) * 0x11 for n in range(16)]   # Gray en dos nibbles


NOMBRES = ["ping-pong", "llenado", "alternado", "Gray"]
ROM = [0] * 64
for modo in range(4):
    p = patron(modo)
    for paso in range(16):
        if paso < len(p):
            led, end = p[paso], int(paso == len(p) - 1)
        else:
            led, end = 0x00, 1                      # filas sin usar: apagado y volver al paso 0
        ROM[(modo << 4) | paso] = (end << 8) | led

print("ROM de 64 palabras de 9 bits (bit 8 = END), dirección = {modo, paso}:")
for modo in range(4):
    p = patron(modo)
    fila = " ".join(f"{ROM[(modo << 4) | k] & 0xFF:02X}" for k in range(16))
    print(f"  modo {modo} {NOMBRES[modo]:10s} longitud {len(p):2d}: {fila}")
print(f"  total: {len(ROM)} palabras de 9 bits = {len(ROM) * 9} bits; palabras con END = 1: {sum(w >> 8 for w in ROM)}")

# ciclo del hardware: contador de paso con borrado síncrono por END
for modo in range(4):
    paso, vistos = 0, []
    for _ in range(40):
        w = ROM[(modo << 4) | paso]
        vistos.append(w & 0xFF)
        paso = 0 if (w >> 8) else paso + 1
    L = len(patron(modo))
    ok = vistos[:L] == vistos[L:2 * L] == patron(modo)
    print(f"  modo {modo}: la secuencia se repite cada {L} pasos: {ok}")

La ROM tiene 64 palabras de 9 bits (576 bits) y 20 de ellas llevan END = 1: una por cada animación (4) más las filas vacías, 2 en el ping-pong y 14 en el alternado. Cada modo se repite exactamente con su longitud (14, 16, 2 y 16 pasos): el contador con borrado por END da la secuencia que se diseñó.

Paso 2: glitches con y sin registro

def patron(modo):
    if modo == 0:                                   # ping-pong: 0..7 y vuelta 6..1
        pos = list(range(8)) + list(range(6, 0, -1))
        return [1 << p for p in pos]
    if modo == 1:                                   # llenado y vaciado
        return [0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00]
    if modo == 2:                                   # alternado
        return [0xAA, 0x55]
    return [(n ^ (n >> 1)) * 0x11 for n in range(16)]   # Gray en dos nibbles


NOMBRES = ["ping-pong", "llenado", "alternado", "Gray"]
ROM = [0] * 64
for modo in range(4):
    p = patron(modo)
    for paso in range(16):
        if paso < len(p):
            led, end = p[paso], int(paso == len(p) - 1)
        else:
            led, end = 0x00, 1                      # filas sin usar: apagado y volver al paso 0
        ROM[(modo << 4) | paso] = (end << 8) | led


# Desfasaje entre bits del contador: los bits que bajan se retrasan y la dirección pasa un instante por a|b
def glitches(modo, registrar):
    n = 0
    detalle = []
    L = len(patron(modo))
    for paso in range(L):
        a = paso
        b = 0 if paso == L - 1 else paso + 1
        inter = a | b
        wa, wb = ROM[(modo << 4) | a] & 0xFF, ROM[(modo << 4) | b] & 0xFF
        wi = ROM[(modo << 4) | inter] & 0xFF
        if not registrar and inter not in (a, b) and wi not in (wa, wb):
            n += 1
            detalle.append((a, b, inter, wi))
    return n, detalle

print("transiciones con salida espuria (bits que bajan llegan tarde, dirección intermedia = a OR b):")
for modo in range(4):
    sin, det = glitches(modo, False)
    con, _ = glitches(modo, True)
    L = len(patron(modo))
    print(f"  modo {modo} {NOMBRES[modo]:10s}: {sin:2d} de {L:2d} transiciones con glitch sin registro; {con} con registro de salida")
    for a, b, i, w in det[:2]:
        print(f"      paso {a} -> {b}: pasa por la dirección {i} y por un instante muestra {w:02X} (ni {ROM[(modo<<4)|a]&0xFF:02X} ni {ROM[(modo<<4)|b]&0xFF:02X})")

# con un contador de pasos en código Gray cambia un solo bit por transición: no hay dirección intermedia
def gray(n): return n ^ (n >> 1)
print()
print("contador de pasos en código Gray:")
malas = 0
for k in range(15):
    if bin(gray(k) ^ gray(k + 1)).count("1") != 1: malas += 1
print(f"  en 0..15 hay {malas} transiciones con más de un bit; el cierre 15 -> 0 también cambia un bit: {bin(gray(15) ^ gray(0)).count('1') == 1}")

Sin registro de salida, si los bits que bajan llegan tarde, el ping-pong tiene 6 transiciones de 14 con un destello ajeno, el llenado 7 de 16 y el Gray 7 de 16; el alternado no tiene ninguna porque solo cambia entre los pasos 0 y 1. Con el registro de salida, las tres tienen 0. Un contador en código Gray cambia un bit por transición, lo que elimina la dirección intermedia, pero solo sirve para una vuelta completa de 16 pasos.

Paso 3: velocidad y corriente

# Frecuencia máxima del lazo contador -> ROM -> registro (valores típicos de conocimiento general, a 5 V)
t_cq = 20e-9          # 74HC163: reloj -> salida
t_acc = 150e-9        # ROM tipo 28C64-15: acceso por dirección
t_su = 15e-9          # 74HC574: tiempo de preparación
t_margen = 0.2        # 20 % de margen
T = (t_cq + t_acc + t_su) * (1 + t_margen)
print(f"periodo mínimo del lazo: {T * 1e9:.0f} ns -> frecuencia máxima {1 / T / 1e6:.2f} MHz")

base = 32768
print("base de tiempo con el 74HC4060 (32 768 Hz):")
for div in (2**12, 2**13, 2**14, 2**15):
    f = base / div
    print(f"  ÷{div:5d}: {f:4.1f} Hz -> un paso cada {1000 / f:6.0f} ms; ping-pong (14 pasos) tarda {14 / f:5.2f} s; llenado (16 pasos) {16 / f:5.2f} s")
print(f"la lógica trabaja {1 / T / 8:.0f} veces más rápido de lo que hace falta a 8 Hz: el límite no es la ROM, es el ojo")

# corriente de salida: 8 LED
vcc, vled, vol = 5.0, 2.0, 0.3
print()
for r in (330, 470, 1000):
    i = (vcc - vled - 0.4) / r
    print(f"  R = {r:4d} ohm: {i * 1000:4.1f} mA por LED, {8 * i * 1000:5.1f} mA con los 8 encendidos")
print("  límite típico de la familia HC: 25 mA por pin y unos 50 mA por pata de alimentación; con 8 LED a 470 ohm ya se rozan los 50 mA")

Con los tiempos típicos usados, el lazo admite unos 4,5 MHz, muy por encima de los 8 Hz necesarios. Las velocidades de 1, 2, 4 y 8 Hz dan pasos de 1000, 500, 250 y 125 ms. Con 330 Ω los ocho LED consumen 63 mA y pasan el límite del integrado; con 470 Ω son 44 mA y con 1 kΩ, 21 mA. Los tiempos y límites salen de valores típicos de conocimiento general, no de una hoja de datos concreta.

Paso 4: la imagen para grabar

def patron(modo):
    if modo == 0:                                   # ping-pong: 0..7 y vuelta 6..1
        pos = list(range(8)) + list(range(6, 0, -1))
        return [1 << p for p in pos]
    if modo == 1:                                   # llenado y vaciado
        return [0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00]
    if modo == 2:                                   # alternado
        return [0xAA, 0x55]
    return [(n ^ (n >> 1)) * 0x11 for n in range(16)]   # Gray en dos nibbles


NOMBRES = ["ping-pong", "llenado", "alternado", "Gray"]
ROM = [0] * 64
for modo in range(4):
    p = patron(modo)
    for paso in range(16):
        if paso < len(p):
            led, end = p[paso], int(paso == len(p) - 1)
        else:
            led, end = 0x00, 1                      # filas sin usar: apagado y volver al paso 0
        ROM[(modo << 4) | paso] = (end << 8) | led


def intel_hex(datos, base=0):
    lineas = []
    for i in range(0, len(datos), 8):
        bloque = datos[i:i + 8]
        cuerpo = [len(bloque), (base + i) >> 8, (base + i) & 0xFF, 0] + list(bloque)
        cs = (-sum(cuerpo)) & 0xFF
        lineas.append(":" + "".join(f"{b:02X}" for b in cuerpo) + f"{cs:02X}")
    lineas.append(":00000001FF")
    return lineas

# dos bytes por palabra (LEDs y control) para una ROM de 8 bits: la dirección tiene un bit más
bajo = [w & 0xFF for w in ROM]
alto = [w >> 8 for w in ROM]
imagen = bajo + alto                         # primera mitad = LEDs; segunda = bit END
print(f"imagen de ROM: {len(imagen)} bytes (dos bancos de 64). Las 3 primeras líneas Intel HEX:")
for l in intel_hex(imagen)[:3]: print("  ", l)

# prueba de ida y vuelta: leer el HEX y recuperar la ROM
def leer_hex(lineas):
    mem = {}
    for l in lineas:
        n = int(l[1:3], 16); a = int(l[3:7], 16); t = int(l[7:9], 16)
        if t == 1: break
        datos = [int(l[9 + 2 * k:11 + 2 * k], 16) for k in range(n)]
        assert (sum(int(l[i:i + 2], 16) for i in range(1, len(l), 2)) & 0xFF) == 0, "checksum"
        for k, d in enumerate(datos): mem[a + k] = d
    return [mem[k] for k in range(len(mem))]
assert leer_hex(intel_hex(imagen)) == imagen
print("ida y vuelta por Intel HEX: correcta; todas las líneas con suma de verificación válida")

# edición: cambiar un patrón y ver el efecto sin tocar el hardware
ROM2 = list(ROM)
nuevo = [0x81, 0x42, 0x24, 0x18, 0x24, 0x42]           # "pupila" que cierra y abre
for paso in range(16):
    ROM2[(2 << 4) | paso] = ((paso == len(nuevo) - 1) << 8 | nuevo[paso]) if paso < len(nuevo) else 0x100
paso, vistos = 0, []
for _ in range(14):
    w = ROM2[(2 << 4) | paso]; vistos.append(f"{w & 0xFF:02X}"); paso = 0 if w >> 8 else paso + 1
print("modo 2 reprogramado (solo se cambiaron datos):", " ".join(vistos))

# verificación de integridad: suma módulo 256 como en el arranque de un equipo real
cs = (-sum(imagen)) & 0xFF
print(f"byte de verificación del contenido: {cs:02X}")
imagen2 = list(imagen); imagen2[10] ^= 0x04
print(f"con un bit invertido en la posición 10 la suma da {(-sum(imagen2)) & 0xFF:02X} (detecta el error)")

La imagen son 128 bytes (64 de luces y 64 de control). Las primeras líneas HEX coinciden con las de la sección 8 y la ida y vuelta por el formato recupera exactamente los mismos bytes, con todas las sumas de línea válidas. Reprogramar el modo 2 como «pupila» (81, 42, 24, 18, 24, 42) solo exigió cambiar datos. El byte de verificación del contenido es 8B, y al invertir un bit la suma pasa a 87, por lo que el error se detecta.

El esquema es el de todo diseño con datos: un generador, una verificación y un formato de intercambio. El circuito es genérico; la animación es el contenido.

10 · Exploración interactiva

El laboratorio: el secuenciador

El simulador es el circuito completo: contador de 4 bits, ROM de 64 palabras con bit END y, opcionalmente, registro de salida. Elegí el modo, avanzá paso a paso o reproducí. Podés programar la ROM haciendo clic en un LED (invierte ese bit del paso actual) o con el botón de END. Con «desfasaje» activado, los bits de dirección que bajan llegan tarde, y sin registro de salida el simulador cuenta los glitches y los anota.

Secuenciador de 8 LED con ROM

Secuenciador simulado Ocho LED que se encienden según el patrón de la palabra de la ROM en el paso actual. Debajo, las dieciséis palabras del modo elegido, con el paso actual resaltado y los pasos con END marcados. Una franja inferior avisa cuando la dirección pasa por un valor intermedio y los LED muestran un destello ajeno.
Dirección de la ROM000000
PalabraEND 0 · LED 01
Paso0 de 14
Longitud de la animación14 pasos
Glitches contados0
Bits de ROM programados0

Modo ping-pong, salida directa con desfasaje. Avanzá unos pasos y mirá la tabla de glitches.

Últimos 8 glitches.
N.ºTransición de pasoPaso intermedioLED (antes → destello → después)
Sin glitches registrados.

Recorrido guiado

  1. Con el modo 0 y «+1 paso», seguí el LED que se mueve de D0 a D7. En la fila de la ROM, el paso actual se resalta y el último (13) lleva END: al llegar a él, el contador vuelve a 0.
  2. Avanzá hasta el paso 3 y pasá al 4: el simulador registra un glitch (la dirección pasó por el paso 7 y por un instante los LED mostraron 80). Seguí avanzando: sale uno cada vez que cambian dos o más bits del contador.
  3. Activá «Registro de salida» y repetí el recorrido: el contador de glitches ya no sube. La animación es idéntica; solo desapareció el destello.
  4. Desactivá «Desfasaje»: sin registro tampoco hay glitches, porque todos los bits cambian a la vez. En la realidad nunca es así, y el registro es el que garantiza el resultado.
  5. Cambiá al modo 2 (alternado): solo hay dos pasos y un END en el 1. El contador vuelve a 0 a cada paso, y no hay glitches porque no cambian varios bits a la vez.
  6. Con el modo 0 en marcha, cambiá a 3 (Gray) cuando el paso sea alto. El contador conserva el paso y la ROM entrega la palabra del nuevo modo en esa posición (R7). Cuando llegue a END, se reordena sola.
  7. Programá la ROM: en el modo 2, paso 0, hacé clic en dos LED para cambiar AA por otro patrón. Los «bits de ROM programados» suben, y el hardware no cambió.
  8. Mové el END: en el modo 1, ubicate en el paso 7 (patrón FF) y usá «Invertir END». La animación ahora dura 8 pasos y la barra no se vacía. Volvé a invertirlo para recuperar el original.
Desafío: una animación de 32 pasos

Con un contador de 4 bits y 16 pasos por modo, el máximo es 16. Para una animación de 32 pasos hay que ampliar el contador a 5 bits (dos bits de modo + 5 de paso = 7 bits de dirección, 128 palabras). Los modos pasan de 4 a 4 bloques de 32 palabras. Como en el tema 31, ampliar la dirección no cambia el principio: más bits de contador, más filas de tabla, y el mismo registro de salida.

11 · Comprensión

Confusiones frecuentes

«El contador sabe cuándo termina la animación»

No lo sabe: lo dice la ROM con el bit END de la última palabra. El contador solo incrementa o se borra.

«Cambiar la animación obliga a rehacer el circuito»

Es un cambio de datos: se regenera la imagen y se vuelve a grabar la memoria. El hardware es el mismo para cualquier contenido.

«Los glitches no importan si no se ven»

Con LED, nadie los ve. Pero el mismo diseño con una salida que alimente un reloj, un contador o una señal de control puede fallar de manera intermitente y difícil de reproducir. Registrar las salidas es gratis y evita el problema.

«El registro de salida hace más lento al sistema»

Retrasa la animación un ciclo de reloj (125 ms en el caso más rápido), imperceptible, y a cambio da una salida estable. Su costo es un integrado.

«Las filas vacías de la ROM pueden quedar en cualquier valor»

No: si el contador cae en una fila vacía (por un cambio de modo), el contenido define qué pasa. Con luces apagadas y END = 1 el sistema vuelve solo a la secuencia. Con basura, podría mostrar patrones al azar o quedar sin reiniciar.

«Ocho LED se pueden manejar con cualquier resistencia»

Con 330 Ω los ocho LED consumen 63 mA, más que el límite del integrado. La corriente total se calcula siempre, no solo la de un LED.

«El borrado del contador puede ser asíncrono»

Si lo es, el último paso aparece apenas un instante y genera su propio glitch. El borrado síncrono de un 74HC163 espera el flanco y mantiene el último paso un ciclo completo.

«Un secuenciador con ROM es igual que una máquina de estados con ROM»

Se parecen (tabla más registro), pero aquí el siguiente paso no depende de ninguna entrada. En la máquina de estados del tema 34 el estado y las entradas formaban la dirección de la ROM de control; acá la dirección solo es el contador y el modo.

12 · Práctica guiada

Predecí antes de simular

1. Capacidad

Con 4 modos de 16 pasos y 9 bits por palabra, ¿cuántos bits de ROM hacen falta? ¿Qué cambia si se quieren 8 modos de 32 pasos?

Ver solución

4 × 16 × 9 = 576 bits (64 palabras). Con 8 modos de 32 pasos: dirección de 3 + 5 = 8 bits, 256 palabras, 2304 bits. El contador pasa a 5 bits y se agregan un bit de modo y un bit de paso.

2. Duración de una vuelta

El ping-pong a 2 Hz: ¿cuánto tarda en repetirse? ¿Y el alternado a 8 Hz?

Ver solución

Ping-pong: 14 pasos × 0,5 s = 7 s. Alternado: 2 pasos × 0,125 s = 0,25 s (parpadeo de 4 Hz).

3. El bit END

Se quiere acortar el llenado para que solo crezca hasta 3F, sin vaciado. ¿Qué cambia en la ROM?

Ver solución

Hay que partir del patrón: 3F es el sexto paso (índice 5). Se pone END = 1 en el paso 5 del modo 1 y las filas 6 a 15 pasan a «apagado con END = 1». La animación queda en 6 pasos (01, 03, 07, 0F, 1F, 3F), porque 10 pasos con una barra que solo crece no existen: la barra llega a 8 LED como máximo. No se toca nada de hardware.

4. Un glitch específico

En el modo 1, el contador pasa del paso 7 al 8 y los bits que bajan se retrasan. ¿Qué dirección intermedia aparece y qué patrón sale?

Ver solución

7 = 0111 y 8 = 1000. Si los bits que bajan llegan tarde, aparece 7 | 8 = 1111 = 15, y la ROM entrega la palabra del paso 15 (00). En esa transición los LED pasarían de FF a 00 por un instante y luego a 7F. El resultado depende del contenido, y por eso siempre se registra.

5. Corriente

Con LED de 2 V y 1 kΩ, ¿cuánta corriente circula por cada uno (alimentación de 5 V y 0,4 V de caída del registro)? ¿Y qué resistencia da unos 5 mA?

Ver solución

I = (5 − 2 − 0,4) / 1000 = 2,6 mA. Para 5 mA, R = 2,6 / 0,005 = 520 Ω; se usaría 470 Ω (5,5 mA por LED, 44 mA en total) o 560 Ω.

6. Diagnóstico

La animación del modo 0 muestra a veces un LED extra encendido en el centro, sin patrón. El osciloscopio muestra picos en las salidas de la ROM. ¿Qué falta?

Ver solución razonada

Hay glitches por direcciones intermedias y los LED toman la salida de la ROM directamente. Falta el registro de salida (74HC574 entre la ROM y los LED, con el mismo reloj del contador). Es posible que además falten los condensadores de 100 nF, que agravan los picos.

13 · Síntesis

Ideas para recordar

  • Un contador más una ROM generan una secuencia de salidas: la secuencia es un dato almacenado, no lógica cableada.
  • La dirección {modo, paso} concatena la animación elegida y la salida del contador; cada modo ocupa un bloque de 16 palabras.
  • El bit END de cada palabra borra el contador de forma síncrona y fija la longitud de la animación; las filas vacías llevan luces apagadas y END = 1 para recuperarse solas.
  • Al cambiar varios bits de dirección a la vez, la ROM puede ver direcciones intermedias y mostrar destellos: se evita con un registro de salida que captura en el flanco.
  • La velocidad la fija el divisor del cristal (125 ms a 1 s por paso); el lazo de lógica tiene un margen de cientos de miles de veces.
  • La corriente total de los LED se calcula y se compara con el límite del integrado; con 8 LED, 1 kΩ es seguro y 330 Ω no.
  • El contenido de la ROM se genera con un script, se exporta como Intel HEX con sumas de verificación y se verifica de ida y vuelta antes y después de grabar.
  • Comparado con el semáforo: acá la tabla de datos reemplaza la lógica de próximo estado, a costa de no tener entradas que decidan el camino.

¿Listo para el tema 36?

Antes de avanzar, explicá de memoria cómo se logra que una animación de 14 pasos se repita con un contador de 16, por qué hace falta el registro de salida y qué parte del proyecto se cambia para agregar una animación. Si lo respondés sin dudar, estás listo para el cierre del curso.

En el próximo tema cerramos el recorrido: cómo elegir bloques, depurar con cronogramas y reconocer, en un microcontrolador, los mismos periféricos que armaste acá con integrados.