Los circuitos secuenciales incorporan memoria: sus salidas dependen de las entradas actuales y del estado almacenado. El reloj, los flip-flops, los registros y los contadores permiten construir sistemas digitales que evolucionan con el tiempo.
Un circuito combinacional calcula una salida a partir de las entradas presentes. Si las entradas vuelven a ser iguales, la salida también; no conserva información del pasado.
Muchos sistemas necesitan recordar: un contador debe conocer su valor anterior, un teclado debe registrar una pulsación y un protocolo debe saber en qué etapa se encuentra. Los circuitos secuenciales añaden elementos de almacenamiento para representar ese estado.
El estado es la información interna que resume lo relevante del pasado para determinar el comportamiento futuro. En un circuito secuencial, el estado suele almacenarse en uno o varios bits.
La función g actualiza la memoria. Esta separación entre estado actual, entrada, salida y estado siguiente también aparece en programas con variables, objetos y máquinas de estados.
Un reloj o clock es una señal periódica que coordina cuándo se actualizan los elementos de memoria. En muchos diseños síncronos, los cambios de estado ocurren solo en un flanco de subida o de bajada.
El reloj no hace que un circuito sea correcto por sí solo. Deben respetarse tiempos de propagación y de estabilidad para que cada elemento capture datos confiables.
Un latch es normalmente sensible a un nivel de habilitación: mientras está habilitado puede reflejar cambios en su entrada. Un flip-flop captura un valor en un instante asociado al flanco del reloj.
En explicaciones introductorias a veces se usan como sinónimos, pero distinguirlos es importante al diseñar hardware. Los sistemas síncronos modernos usan con frecuencia flip-flops controlados por reloj.
El latch SR es uno de los elementos de memoria más simples. Tiene entradas S (set, establecer) y R (reset, borrar), y una salida Q que almacena un bit.
| S | R | Q siguiente | Acción |
|---|---|---|---|
| 0 | 0 | Q actual | mantener |
| 1 | 0 | 1 | set |
| 0 | 1 | 0 | reset |
| 1 | 1 | no válido | estado prohibido en la versión NOR activa en alto |
La última combinación no debe utilizarse en el latch SR construido con puertas NOR. Puede dejar las salidas complementarias en una condición inconsistente y producir un estado posterior impredecible.
El latch D evita la combinación prohibida del SR. Tiene una entrada de datos D y una habilitación E. Cuando E está activa, Q sigue a D; cuando E no está activa, Q conserva su valor.
El latch D es útil cuando se desea que la memoria sea transparente durante una fase controlada. Para capturar datos en un único instante se prefiere un flip-flop D.
El flip-flop D captura el valor de D en el flanco activo del reloj y lo mantiene hasta el próximo flanco activo. Es el bloque básico de muchos registros.
La regla parece simple, pero permite separar un cálculo en etapas. La lógica combinacional prepara el dato y el flip-flop lo registra de manera coordinada.
class FlipFlopD {
constructor(valorInicial = false) {
this.q = valorInicial;
}
flancoDeReloj(d) {
this.q = Boolean(d);
return this.q;
}
salida() {
return this.q;
}
}
const memoria = new FlipFlopD();
console.log(memoria.salida()); // false
console.log(memoria.flancoDeReloj(true)); // true
console.log(memoria.salida()); // trueEl método flancoDeReloj representa el único momento en que se actualiza el estado. Cambiar una variable de entrada entre llamadas no altera Q hasta simular otro flanco.
El flip-flop JK generaliza la idea del SR y resuelve su combinación prohibida. Con J = K = 1, la salida cambia al valor opuesto, es decir, conmuta.
| J | K | Q siguiente | Acción |
|---|---|---|---|
| 0 | 0 | Q actual | mantener |
| 0 | 1 | 0 | reset |
| 1 | 0 | 1 | set |
| 1 | 1 | ¬Q actual | conmutar |
La capacidad de conmutar hace útil al JK en contadores y divisores de frecuencia. En diseños modernos suele describirse el comportamiento con flip-flops D y lógica adicional.
El flip-flop T tiene una entrada T de toggle. Si T es 0, mantiene el estado; si T es 1, invierte la salida en cada flanco de reloj.
Un T que conmuta en cada flanco produce una señal con la mitad de frecuencia que el reloj. Encadenar varios permite construir contadores binarios sencillos.
Para que un flip-flop capture correctamente D, la entrada debe permanecer estable durante una ventana temporal alrededor del flanco del reloj.
Estas restricciones vinculan la frecuencia máxima del reloj con el retraso de la lógica combinacional. Son propiedades físicas del componente, no reglas visibles en una tabla de verdad ideal.
Si una entrada cambia demasiado cerca del flanco, un flip-flop puede entrar temporalmente en metastabilidad: no se comporta de inmediato como un 0 o un 1 estable. No se puede eliminar por completo, pero se puede reducir su riesgo.
Los botones, sensores y señales provenientes de otro dominio de reloj requieren atención especial. El modelo booleano por sí solo no representa estos problemas de tiempo.
Un registro es un conjunto de flip-flops que almacena varios bits a la vez. Un registro de 8 bits tiene ocho flip-flops D que capturan un byte en el mismo flanco de reloj.
Los registros guardan operandos, direcciones, instrucciones y resultados intermedios. Son componentes fundamentales de procesadores y controladores digitales.
Un registro de desplazamiento conecta la salida de un flip-flop con la entrada del siguiente. En cada pulso, los bits se desplazan una posición y puede entrar un nuevo bit por un extremo.
Estos registros se usan para convertir datos serie/paralelo, retrasar señales y generar secuencias. La dirección y el orden de bits son detalles críticos del diseño.
Un contador recorre una secuencia de estados con cada pulso de reloj. Un contador binario de tres bits recorre de 000 a 111 y luego vuelve a 000.
Los contadores se usan en temporizadores, direcciones de memoria, generadores de secuencia y divisores de frecuencia. El módulo puede ser una potencia de dos o un valor arbitrario con lógica de reinicio adecuada.
class ContadorModulo {
constructor(modulo) {
if (!Number.isInteger(modulo) || modulo <= 0) throw new Error("módulo inválido");
this.modulo = modulo;
this.valor = 0;
}
flancoDeReloj(reset = false) {
this.valor = reset ? 0 : (this.valor + 1) % this.modulo;
return this.valor;
}
}
const contador = new ContadorModulo(4);
console.log(contador.flancoDeReloj()); // 1
console.log(contador.flancoDeReloj()); // 2
console.log(contador.flancoDeReloj()); // 3
console.log(contador.flancoDeReloj()); // 0La clase representa el estado como un número, mientras que el hardware real lo codifica con varios flip-flops. La operación módulo expresa el retorno al estado inicial.
Una máquina de estados finitos tiene un número limitado de estados y reglas de transición. Los circuitos secuenciales son una forma de implementar estas máquinas.
En una máquina de Moore las salidas dependen solo del estado; en una máquina de Mealy dependen del estado y de las entradas. Esta distinción ayuda a diseñar controladores y protocolos.
class PuertaAutomatica {
constructor() {
this.estado = "cerrada";
}
flancoDeReloj({ credencialValida, cerrar }) {
if (this.estado === "cerrada" && credencialValida) this.estado = "abierta";
else if (this.estado === "abierta" && cerrar) this.estado = "cerrada";
return this.estado;
}
}
const puerta = new PuertaAutomatica();
console.log(puerta.flancoDeReloj({ credencialValida: true, cerrar: false })); // abierta
console.log(puerta.flancoDeReloj({ credencialValida: false, cerrar: true })); // cerradaEsta simulación modela una transición por llamada, como si cada llamada fuera un pulso de reloj. Un sistema real también debe definir qué ocurre con señales simultáneas, fallos y entradas no previstas.
Un diseño síncrono separa la lógica en dos partes: lógica combinacional que calcula el próximo estado y flip-flops que registran ese estado en el flanco del reloj.
Esta organización facilita razonar sobre el tiempo: hay un ciclo completo de reloj para que la lógica combinacional produzca un valor estable antes de que el estado vuelva a capturarse.
Variables que persisten entre iteraciones, objetos con campos mutables y máquinas de estados de una interfaz son análogos de memoria en software. Su resultado depende de llamadas anteriores, no solo de los argumentos actuales.
Hacer explícitos los estados y transiciones mejora la prueba y el mantenimiento. Es la misma disciplina que exige un circuito secuencial bien definido.
Los circuitos secuenciales añaden tiempo y memoria a la lógica booleana. En el próximo tema iniciaremos la teoría de grafos, otra herramienta esencial para modelar conexiones, redes y dependencias en programación.