Skip to content

CT18: Fundamentos. Sistema Unario

Juan Gonzalez-Gomez edited this page Aug 21, 2024 · 704 revisions

Descripción

Utilización del sistema unario para entender los fundamentos de la electrónica digital y comprender, con ejemplos de circuitos reales, cómo emergen características de mayor abstracción. Viajaremos al centro de los fundamentos

  • Icestudio: Todos los ejemplos se han probado con Icestudio-0.12. Usa esta versión o superior
  • Ejemplos: Todos los ejemplos de este cuaderno técnico están accesibles en su repositorio en github

Contenido

Introducción

La electrónica digital se entiende muy bien si descendemos a los fundamentos. Una vez entendidos estos fundamentos se puede pasar a la siguiente fase: su optimización, para crear circuitos más complejos usando menos recursos. Pero esto NO es el objetivo de este cuaderno. Empezaremos primero por entender los fundamentos

Los circuitos digitales trabajan con números. Con la tecnología actual, estos números se representan en el sitema binario, donde tenemos dígitos que toman sólo 2 valores: 0 y 1. PERO existe un sistema de representación todavía más fundamental. Más básico. Es el sistema unario. En este sistema sólo se utiliza un único símbolo, que denominamos marca

En esta figura se muestra la cuenta del 1 al 5 en Decimal y en Unario, usando como marca un círculo verde 🟢️

PERO se puede utilizar cualquier otra marca: raya vertical, cuadrado, el número 1, una X, cuentas de un ábaco...

Todas las marcas tienen el mismo peso, es decir, valen lo mismo con independencia de la posición en la que se encuentren. Su valor representa SIEMPRE una unidad. Por ejemplo, en el número unario 🟢️🟢️🟢️🟢️, la primera marca vale 1 (la de la izquierda), lo mismo que la última marca (la de la derecha) y lo mismo que el resto de marcas

Los números unarios típicamente se escriben en horizontal, de izquierda a derecha, igual que los números en decimal, pero como las marcas tienen el mismo peso en realidad se pueden escribir al revés. Son simétricos. También se podrían escribir en vertical, de arriba a abajo o de abajo a arriba. O en cualquier otra disposición

Contando en unario

El sistema unario es la forma más básica de contar. Y también es la más natural. No es necesario saber escribir, ni practicar, ni tener conocimientos avanzados... En el mundo real las marcas son Objetos físicos. Así, por ejemplo, imaginemos que un niño tiene unos cuantos caramelos

Cada caramelo es una marca. Para contarlos basta con cogerlos uno a uno y colocarlos en una línea horizontal. Esa línea es su representación en el sistema unario

Ahora establecemos una correspondencia uno-uno entre el objeto físico y una marca. Podemos contar los mismos caramelos pero sin tenerlos físicamente. Contamos las marcas y sabemos que cada marca representa un caramelo

Esto representa un salto en la abstracción. En vez de caramelos físicos, el niño ahora tiene unas marcas para representarlos. Esto le permite anotarlo en su cuaderno, o en un lugar físico diferente de donde están los caramelos. Pero esta abstracción es aún más potente, porque las marcas ya no sólo representan estos caramelos, sino que pueden representar cualquier otro objeto físico

Si además de los caramelos, el niño quiere contar las monedas que tiene en su hucha, usará también esas marcas. Esos números unarios, con sus marcas, pueden representar infinitas cosas. El sistema de numeración unario, que nace de lo físico, pasa a ser algo más potente y abstracto que permite contar cualquier otra cosa

Pensemos en otro ejemplo. El sistema Unario todos lo hemos usado en el colegio para la elección de delegados. Se anotan en una pizarra los nombres de los candidatos y se van colocando barras verticales (Marcas) por cada uno de los votos. El que más marcas tenga es el que más votos tienen y por tanto será nombrado delegado

Otro uso muy típico, que se ve en el cine, es la cuenta de los días de un preso en la cárcel, o de un naúfrago en la pared de una gruta en una isla desierta (Robinson Crusoe)

En estas cuetas es habitual agrupar las marcas en grupos de 5, de las cuales una de las marcas se pone en diagonal para indicar que ese grupo de 5 días está completo. Da igual si las marcas son diferentes, ya que todas tienen el mismo peso: valen lo mismo: la unidad. Es indiferente si unas se escriben con orientaciones distintas. Sigue siendo un sistema unario

Otro ejemplo de uso del sistema Unario, que hemos usado todos alguna vez, es contar con los dedos. En este caso los dedos son las marcas de nuestro sistema unario. En esta imagen se muestra una mano que cuenta hasta 3. Al final tiene 3 dedos estirados. Representa el número unario 🟢️🟢️🟢️

Como tenemos 10 dedos, con este sistema podemos contar fácilmente hasta 10

Por último, una curiosidad. El sistema de numeración Romano NO es UNARIO, pero sí es una evolución a partir de él. La representación de los números 1, 2 y 3 se hace en UNARIO, usando el símbolo I: I, II, III. ¡Es una cuenta unaria!

Otros usos del sistema unario

El sistema Unario lo utilizamos más de lo que creemos. Está entre nosotros, pero no nos damos cuenta, o no nos hemos parado a reflexionar sobre ello

Pensemos en el ejemplo de contar pasajeros sentados en un avión. Para contarlos y dejar un registro, podríamos tener una hoja en la que vayamos poniendo una marca (cruz, check, raya...) por cada pasajero. Esto sería una cuenta en Unario. En vez de eso, en muchas líneas aéreas utilizan contadores mecánicos. La azafata se va desplazando por el pasillo y va pulsando un botón por cada pasajero. Así, la marca es el click que hace el aparato

El resultado de la cuenta, obviamente, NO se muestra en Unario, sino en decimal. Pero la manera de contar es UNARIA: un click por cada pasajero (Todos los click valen la unidad)

El sistema unario tiene una propiedad muy interesante: Su longitud crece con el número. Es decir, que cada número es más largo que el anterior. Esto es debido a que todas las marcas valen lo mismo: la unidad. Y esta propiedad hace que sea muy fácil comparar los números unarios y determinar cuál es mayor: el más largo. Esto se aprovecha para expresar cosas como la capacidad de la batería de nuestro teléfono móvil. Cada rectángulo representa una marca

Esta misma idea también la vemos para expresar la cobertura de la wifi y de los datos, también en los teléfonos móviles. En estos casos, además de las marcas, que se muestran en color más oscuro, también se muestran los huecos donde estarán las siguientes marcas. De esta forma se puede saber cuántas marcas forman el total (Expresión del tanto por ciento en sistema Unario). En el caso de los datos el valor máximo, típicamente, son 5 marcas, mientas que para la wifi sólo 4

Los vúmetros son dispositivos que indican el nivel de una señal de audio en unidades de volumen. También se conocen como indicadores de volumen. Los vúmetros digitales expresan el volumen en el sistema UNARIO. En este dibujo se muestra un vúmetro que tiene 12 canales. Por cada canal se usan 14 marcas para expresar el nivel de volúmen

Las barras de progreso tienen su base también en el sistema unario. Crecen hacia la derecha añadiendo marcas verticales muy juntas. La diferencia es que hay muchas marcas, que son muy estrechas, dando una sensación de continuidad en el crecimiento de la barra

Un uso peculiar del sistema unario es el empleado en el mensaje para comunicarnos con inteligencias extraterrestres, publicado en el artículo científico: "A Beacon in the Galaxy: Updated Arecibo Message for Potential FAST and SETI Projects"

Este es el aspecto de la primera página del mensaje que proponen enviar para comunicarnos con los extraterrestres que pudiera haber en nuestra galaxia:

Se definen unos símbolos para codificar números en el sistema decimal, y con ellos expresar números primos y operaciones matemáticas. Para introducir estos símbolos se utiliza el sistema unario. Las marcas son cuadrados pequeños, que se apilan formando dos líneas de 5 cuadros, en una matriz de 5x2 cuadrados

En esta imagen se muestran todos los símbolos (Como curiosidd se muestra también el símbolo igual, que aparece mucho en el mensaje original)

El sistema unario lo utiliza el matemático Roger Penrose en su famoso libro La nueva mente del emperador para explicarnos los fundamentos de la computación y las máquinas de Turing (Capítulo 2: Algoritmos y máquinas de Turing. Pag. 56). Utiliza el ejemplo de una máquina de Turing que es capaz de calcular el máximo común divisor de dos números, usando el algoritmo de Euclides. Esta máquina sólo usa los símbolos 1 y 0 para la cinta. Los números se introducen en el sistema Unario, usando como marcas el símbolo 1. El símbolo 0 se utiliza como separador entre ambos números (Y su significado es: no hay marca)

Tras finalizar la máquina, se obtiene el resultado en la cinta también en Unario. El resultado es 2, por lo que aparece codificado en Unario en la cinta como 11

Penrose primero describe la codificación de los números, y más adelante nos explica que "Este primitivo sistema de numeración se llama sistema unario". El objetivo es profundizar en los fundamentos de la computación. Justifica el utilizar el sistema unario de la siguiente manera: "...estamos interesados en la cuestión de acerca de qué operaciones pueden realizarse en principio algorítmicamente. Lo que es algorítmico si utilizamos una notación para los números es también algorítmico si utilizamos las otra. La única diferenia reside en el detalle y la complicación de los casos". Es decir, que el usar un sistema unario o decimal, NO afecta a la parte algorítmica

Más adelante indica que: "Por supuesto, la representación del número n simplemente como n puntos resulta muy poco eficaz cuando intervienen números muy grandes, razón por la que normalmente utilizamos una notación más compata como lo es la notación estándar (decimal). Sin embargo aquí no estamos demasiado interesados por la eficacia de las operaciones o las notaciones"

Más adelante trataremos este tema, en el apartado Limitaciones del sistema unario

Definiciones

Hay tres conceptos que nos interesa conocer: Tamaño, Posición y Alineamiento

Primero los veremos para el sistema binario porque lo conocemos muy bien, y luego lo aplicaremos al unario

El tamaño de los números binarios se define en bits. Cada bit es uno de los dígitos del número. Así, por ejemplo, estos números tienen todos un tamaño de 4 bits: 0000, 0110, 1111... Dado un número binario de n bits, puede representar en total 2 elevado a n valores. Para el caso de 4 bits, serán 16 valores, desde el 0 hasta el 15

En esta figura se muestra el número 3 usando 4 bits (Su tamaño es 4 bits)

Cada bit ocupa una posición. Estas posiciones se numeran desde la derecha comenzando por 0. Así, el dígito d0 es el que está más a la derecha, y en este ejemplo, el dígito d3 el que está más a la izquierda

El sistema binario es posicional. Esto significa que los bits tienen un valor diferente, según la posición que ocupan. En el ejemplo del número 3, el bit d0 tiene un peso de 1, el bit d1 un peso de 2. Por eso, si añadimos 0s en la derecha, el número cambia (No se puede hacer). Si añadimos ceros por la izquierda, el valor no cambia. Esto nos lleva al concepto de alineación. En el sistema binario diremos que los bits están alineados a la derecha. Indicando que el bit d0 está SIEMPRE en la derecha, con un peso de 1

Ahora veremos estos conceptos para el sistema Unario. El tamaño nos indica la cantidad máxima de marcas que tiene el número. Recordamos que sólo hay una marca: 1. Pero, como el sistema unario lo vamos a utilizar en circuitos digitales, donde todo se implementa mediante bits (0s y 1s), usaremos el 0 para indicar ausencia de marca. Así, lo siguientes son números de 4 marcas: 0000, 1000, 1100, 1111...

Un número de n marcas puede representar en total n+1 valores, desde el 0 hasta el n (el 0 es la ausencia de marcas). En esta figura se muestra un ejemplo de representanción del número 3, usando un sistema unario de tamaño 4 marcas

Las posiciones de las marcas las numeramos igual que en el sistema binario: La marca de la derecha es la d0, mientras que la de la izquierda (en el ejemplo de tamaño 4) es la d3. Sin embargo, en el sistema unario TODAS LAS MARCAS valen 1, por lo que es indiferente si añadimos ceros por la izquierda o por la derecha: el número NO cambia

Esto hace que tengamos dos posibilidades para representar los números unarios: comenzar por la izquierda o comenzar por la derecha. Típicamente, cuando escribimos los Unarios en un papel o una pizarra, lo hacemos comenzando por la izquierda (Decimos que el número está alineado a la izquierda). Pero Lo podríamos hacer empezando por la derecha, igual que en el sistema binario

En este ejemplo de 5 marcas vemos que los números alineados a la izquierda tienen un 1 en la posición de la izquierda d4 (descartando el 0), mientras que los números alineados a la derecha tienen un 1 en la posición d0 (descartando también el 0)

Números constantes

Construiremos circuitos para trabajar con números unarios desde lo más básico: con números constantes de tamaño fijo

Ejemplo 1: Número constante. Alineación izquierda

En este ejemplo se muestra el número 3, usando un sistema unario de 4 marcas, con alineación a la izquierda, en los LEDs de la placa AP-LED8

Lo hacemos usando los bloques constantes de un bit 1, conectándolos directamente a los LEDs. La marca de la izquierda está en la posición d3, y se saca por el LED izquierdo (conectado al pin D7 de la Alhambra-II). La marca de la derecha está en la posición d0, y se saca por el LED conectado al pin D4

(Ej-01-cte.ice)

El resultado lo vemos en este escenario:

Ejemplo 2: Número constante. Alineación izquierda. Bus

Se muestra el número 2, usando un tamaño de 4 marcas y alineación izquierda. La diferencia con el ejemplo anterior es que se usa un BUS para llevar el número a los LEDs. La marca de la posición d0 se lleva por el bit de menos peso del bus, y la posición d3 por el bit de mayor peso. Siempre que trabajemos con buses se usará esta disposición

(Ej-02-cte.ice)

Este es el resultado:

Bloques constantes

Para trabajar con constantes unarias es más cómodo utilizar bloques constantes, que nos sacan directamente un BUS con la constante en cuestión, en vez de tener que construirlo nosotros usando bloques Join, como hemos visto en el ejemplo 2

Tenemos dos formas de expresar constantes unarias: usando bloques k o bloques ku. En esta imagen se muestra el número unario 111 expresado con estos dos bloques, de tamaño de 4 marcas. En ambos casos el número unario está SIEMPRE alineado a la derecha (como lo números en binario)

Bloques k

La primera forma es usando las constantes genéricas (bloques k) de la colección iceK. En Verilog NO hay una manera de expresar números en Unario explícitamente, por lo que hay que utilizar la notación binaria: 'b. Por ejemplo, para expresar el número unario 111 de tamaño 4 marcas hay que usar esta notación: 'b111. También se puede expresar el tamaño como prefijo: 4'b111

El número obtenido en el bus está alineado a la derecha: La primera marca es la situada en la derecha (posición d0)

El inconveniente de usar bloques k es que la notación es ambigua: no se sabe si el número está en unario o en binario. Hay que indicarlo explícitamente con comentarios

Bloques ku

La otra forma es utilizar los bloques ku de la colección iceUnary. El número unario a expresar hay que meterlo entre comillas (""), ya que en verilog no hay una manera explícita para indicar notación unaria. Por ejemplo, para expresar el número 111 hay que ponerlo de esta manera: "111"

El número obtenido en el bus está alineado a la derecha: La primera marca es la situada en la derecha (posición d0)

La ventaja de este bloque es que se indica explícitamente que el número es unario, y así NO hay ambigüedad en los circuitos

Ambos bloques consumen exactamente los mismos recursos

Ejemplo 3: Número constante. Bloque Ku

Se muestra el número unario 111 de tamaño de 4 marcas en los LEDs de menor peso de la placa AP-LED8, alineado a la derecha, utilizando el bloque ku

(Ej-03-cte.ice)

Y este es el resultado:

Ejemplo 4: Dos Número constantes

Se muestra el número unario 111 de 4 marcas de tamaño, dos veces. En los 4 LEDs de la derecha se muestra el número alineado a la derecha, y en los 4 LEDs de mayor peso se muestra alineado a la izquierda

El número obtenido del bloque constante ku está alineado a la derecha. Para obtener el correspondiente alineado a la izquierda se utiliza el bloque reversal de la colección iceWires

(Ej-04-cte.ice)

Este es el resultado:

Números variables

Los números unarios que hemos visto hasta ahora son fijos: Es decir, no cambian con el tiempo. Siempre tienen el mismo valor. Esto es interesante para aprender sobre el sistema unario

El siguiente paso es utilizar números en unario variables, es decir, con la capacidad de cambiar con el tiempo. En electrónica digital esto lo realizamos con registros. Da igual si el número está expresado en unario o binario, lo que necesitamos es un elemento que permita almacenarlo, y que este valor almacenado se pueda sustituir por otro

Aunque se pueden crear registros específicos en unario, nosotros utilizaremos los registros estándar de la colección iceRegs. Para almacenar un número unario de tamaño n marcas, necesitamos un registro de n bits

Ejemplo 5: Almacenando un número de 4 marcas

Se usa un registro de 4 bits para almacenar un número unario de 4 marcas. Inicialmente está almacenado el número 0 (ninguna marca). Al apretar el pulsador sw1 se captura el número unario 111 en el registro. Este número proviene del bloque constante ku, por lo que está alineado a la derecha. La salida del registro se muestra en los 4 LEDs de menor peso de la placa AP-LED8

(Ej-05-reg.ice)

El resultado es que inicialmente los LEDs están apagados, y al apretar el pulsador se muestra el número 111 en los LEDs. El registro ha cambiado de 0000 a 0111. ¡Ya tenemos nuestro primero número unario variable!

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Ejemplo 6: Secuencia de dos números de 4 marcas

En un registro de 4 bits se almacenan, alternativamente, los valores unarios 11 y 1111, y se muestran en los LEDs. El resultado es que se muestra una secuencia de dos valores en los LEDs, que cambian cada segundo. Los números unarios están alineados a la derecha

(Ej-06-reg.ice)

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Contando

El sistema unario nos permite construir muy fácilmente contadores, que dotan a nuestros circuitos digitales de la propiedad de contar. Con esta nueva habilidad podemos contar eventos discretos, como la pulsación de botones, activaciones de sensores, número de repeticiones (bucles) a realizar... Y también nos permite contar eventos de tiempo, con los que adquirimos la capacidad de medir el tiempo (cronometrar)

Vamos a construir los circuitos más básicos para contar, utilizando el sistema unario

Ejemplo 7: Contador unario de 1 marca

Empezamos por el contador mínimo: uno que sólo cuenta hasta 1. Utilizaremos el pulsador SW1 para generar el evento discreto de contar

Este contador lo implementamos en unario, usando una única marca variable. Por ello utilizamos un registro de 1 bit: el biestable D

El biestable D representa una marca unaria, que inicialmente está a 0 (NO hay marca). Por su entada d metemos la marca constante (1). Esta es la marca que se capturará en el biestable cuando se aprieta el pulsador

Este es el circuito:

(Ej-07-cont-1-mark.ice)

Al arrancar el circuito no hay ninguna marca, por lo que el LED 7 (de la izquierda) está apagado. Al apretar el pulsador este LED se enciende: Hemos contado de 0 a 1. Como estamos usando un número usario de tamaño 1, al volver a apretar el pulsador ya NO cuenta más, porque el contador a llegado a su valor máximo 1

En este video de youtube vemos el funcionamiento:

Click to see the youtube video

Ejemplo 8: Contador unario de 2 marcas

Ampliamos el contador anterior para utilizar un número unario de 2 marcas. El contador empieza en 0 y cuenta 1 y 11. Al llegar a su valor máximo ya no se incrementa más. El evento que contamos es, igual que en el ejemplo anterior, la pulsación del botón SW1

Si nos fijamos en cómo se hace la cuenta unaria, esta operación de incremento en una unidad no es más que poner a 1 el siguiente biestable. Es decir, que basta con añadir un biestable D por la derecha al contador de 1 marca, conectado al biestable anterior. Un contador de 2 marcas lo constuimos conectando en cascada 2 biestables D. El biestable de la izquierda lo conectamos a la marca constante 1

(Ej-08-cont-2-marks.ice)

Parimos del estado inicial, en el que los LEDs están apagados. Al apretar el pulsador una vez el contador pasa a valer 1. Con la segunda pulsación cambia a 11. Sucesivas pulsaciones no tienen efecto, ya que se ha alcanzado el valor máximo

En este vídeo de Youtube lo vemos en funcionamiento:

Click to see the youtube video

Ejemplo 9: Contador unario de 3 marcas

En vez de utilizar biestables D discretos encadenados, los circuitos se simplifican si utilizamos los registros de desplazamiento a la derecha (SR) de la colección iceSRegs

Para implementar un contador unario de 3 marcas utilizamos un Registro de desplazamiento a la derecha de 3 bits. La salida en paralelo de este registro es la que sacamos por los LEDs

El pulsador SW1 lo conectamos a su entrada de shift, para realizar el desplazamiento que se añada la siguiente marca

(Ej-09-cont-3-marks.ice)

El funcionamiento es exactamente el mismo que si usásemos biestables D, y consume los mismos recursos, pero ahora está más simplificado. En este Vídeo de Youtubue se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 10: Contador unario de 3 marcas. Alineación derecha

Para tener un contador unario alineado a la derecha, una opción es utilizar el bloque reversal de la colección icewires, que ya conocemos. Pero otra posibilidad es utilizar un Registro de desplazamiento a la izquierda. Este ejemplo es un contador unario de 3 marcas, alineado a la derecha, que se incrementa al apretar el pulsador SW1

(Ej-10-cont-3-marks.ice)

En este vídeo de Youtube se muestra el funcionamiento:

Click to see the youtube video

Ejemplo 11: Contador unario de 4 marcas. Segundero

En este ejemplo se muestra un contador unario de 4 marcas, que cuenta de 0 a 1111, y que se incrementa cada segundo. Es decir, evoluciona automáticamente, por tiempo, y no por la ocurrencia de un evento, como en el ejemplo anterior

Cuando la cuenta llega a su valor máximo (1111), permanece con ese valor

(Ej-11-cont-4-marks.ice)

Al observar su funcionamiento se aprecia que en realidad es una barra de progreso, que crece cada segundo. En este vídeo de youtube se muestra su funcionamiento

Click to see the youtube video

Ejemplo 12: Dos contadores unarios de 4 marcas con alineación izquierda y derecha

En este ejemplo se tiene un contador de 4 marcas que se incrementa cada segundo. En los LEDs se muestran dos contadores: uno alineado a la izquierda y otro a la derecha. Para obtener la alineación a la derecha se utiliza el bloque reversal

(Ej-12-cont-4-marks.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Controladores

Los controladores son la parte de los circuitos que genera las micro-órdenes (señales de control) para gobernar el comportamiento del circuito. Por ejemplo, si estamos diseñando un transmisor serie, necesitamos un controlador que lleve la cuenta de cuántos bits se han transmitido para saber cuándo se ha completado la transmisión, y detenerse. O en el caso de un receptor serie, es el controlador el que cuenta los bits recibidos para determinar cuándo se ha recibido el dato completo, y devolverlo por su salida

En general, los controladores los divimos en dos tipos, según cuándo se realiza la acción de control:

  • Control por eventos: La acción se realiza cuando ocurren n eventos. Por ejemplo la recepción de n bits. O cuando se ha pulsado el botón n veces
  • Control por tiempo: La acción se realiza transcurrido un cierto tiempo: n ciclos o n unidades de tiempo. Por ejemplo encender una alarma transcurridos 4 segundos

Ambos tipos de controladores se realizan muy fácilmente usando los contadores unarios que ya conocemos

En los ejemplos de las siguientes secciones, la acción a disparar será la secuencia del coche fantástico (Knight Rider) en los LEDs

Ejemplo 13: Acción a disparar: Coche fantástico

En este ejemplo se reproduce la secuencia del coche fantástico en los LEDs, sin esperar tiempo ni eventos. Al arrancar el circuito empieza la secuencia

(Ej-13-active.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Control por eventos

En estos controladores se dispara una acción cuando han ocurrido n eventos. Para nosotros los eventos son tics en una señal. En los ejemplos utilizaremos el evento: "Pulsación de un botón"

Estos controladores los implementaremos utilizando un contador unario de n marcas

Ejemplo 14: Disparar acción al apretar el pulsador

En este ejemplo se ejecuta la secuencia del coche fantáscico cuando se aprieta el pulsador SW1 una vez. Para que el controlador lleve la cuenta utilizamos un contador unario de 1 marca: Un biestable D con su entrada de datos conectada a 1. La salida de este biestable es la señal que arranca la secuencia en los LEDs

(Ej-14-active-1-pulsacion.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 15: Disparar acción al apretar el pulsador 2 veces

Ahora queremos disparar la acción al apretar el pulsador 2 veces. El ejemplo es igual que el 14, pero ponemos un contador unario de 2 marcas. La secuencia del coche fantástico se reproduce al cabo de dos pulsaciones

En los LEDs verdes se muestra la cuenta interna del controlador: el número de veces que se ha apretado el pulsador

(Ej-15-active-2-pulsacion.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 16: Disparar acción al apretar el pulsador 4 veces

Se dispara la acción al apretar el pulsador 4 veces. El ejemplo es igual que los anteriores, pero usando ahora un contador unario de 4 marcas

(Ej-16-active-4-pulsacion.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Control por tiempo

En estos controladores la acción se dispara cuando transcurre un cierto tiempo. Para ello el controlador debe llevar la cuenta del tiempo transcurrido. En readlidad, estos controladores son exactamente iguales que los controlados por eventos. La diferencia es que los eventos que se cuentan representan tiempo.

Por ejemplo, si queremos disparar una acción transcurridos 4 segundos, necesitamos un componente que genere eventos de tiempo (tics) cada segundo, y usamos un contador unario de 4 marcas para contar estos segundos

Por ello, todo lo aprendido hasta ahora nos sirve para construir controladores por tiempo

Ejemplo 17: Disparar acción al transcurrir 8 segundos

La animación del coche fantástico se reproduce en los LEDs transcuridos 8 segundos de la inicialización del circuito. El controlador lo compone un contador unario de 8 marcas que cuenta los segundos, hasta 8. El componente corazón emite un tic cada segundo. La cuenta unaria se muestra también en los LEDs verdes de la Alhambra II

(Ej-17-active-4-seg.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Repeticiones

La conexión en cadena de biestables D nos da la capacidad de contar en unario. Con esta capacidad podemos crear controladores que disparen acciones al cabo de n eventos o de cierto tiempo. Sin embargo son controladores muy limitados, ya que sólo funcionan 1 vez. Cuando la cuenta llega al máximo, permanece ahí

Si por ejemplo estamos diseñando el controlador para un circuito de transmisión de datos, sólo podríamos enviar un dato. El contador llegaría a su valor máximo y ya no se incrementaría más. Para que sea un controlador funcional necesitamos que esta operación de contador se pueda repetir

Para lograr repeticiones hay que inicializar el contador unario. Se lleva a su estado inicial (0, sin marcas) para que pueda volver a contar de nuevo. Para lograr esto basta con utilizar Biestables D con entrada de reset y actuar adecuadamente sobre esta nueva entrada

La inicialización a 0 lo hacemos utilizando una puerta and conectada a la entrada rst de los biestables D. La condición de inicialización es que el contador esté en su cuenta máxima (marca de la derecha debe estar activada) y que llegue un evento. Esto provoca que se inicialicen los biestables, y que todo vuelva a comenzar

Vamos a ver esta idea con ejemplos sencillos

Ejemplo 18: Contador unario de 1 marca y reset manual

Empezamos por el ejemplo más sencillo posible: un contador unario de 1 marca, conectado al LED 7. Con el pulsador SW1 se incrementa el contador. Cuando llega a 1 ya no se incrementa más, aunque pulsemos SW1. Con el pulsador SW2 lo reseteamos, para poder así volver a contar manualmente

(Ej-18-cont-rst-1-mark.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 19: Contador de 2 marcas con reset automático

En este contador de 2 marcas el reset se realiza automáticamente cuando llega a su valor máximo y se ha apretado el botón SW1 de contar. El resultado es que el contador que nunca para, contando 0 ,1 y 11 de manera cíclica, con cada pulsación de SW1

(Ej-19-cont-rst-2-mark.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 20: Segundero de 4 marcas, con reinicio automático

Haremos ahora un contador unario de 4 marcas que se incrementa cada segundo. Pero esta acción se repite indefinidamente. Cuando alcanza su valor máximo 1111, vuelve a comenzar

(Ej-20-cont-rst-4-mark.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 21: Cambio de estado de un led cada 3 pulsaciones

Los contadores unarios con reset son cíclicos: empiezan en 0 (sin marca), llegan a su valor máximo y vuelven a empezar. Cada vez que vuelven a 0 decimos que han completado un ciclo. La señal de reset que se genera indica que el ciclo ha finalizado. Por eso utilizamos esta señal como acción

En este ejemplo la acción a realizar es cambiar el LED de estado cada 3 pulsaciones. Utilizamos un contador de 2 marcas, que puede estar en tres estados diferentes: 0 (sin marcas), 1 y 11, y vuelve a comenzar el ciclo

El resultado es que cada 3 eventos (pulsación botón) se genera la señal rst(tic), repetidamente. Así el LED permanece encendido durante 3 eventos, y apagado durante otros 3

(Ej-21-cont-3-toggle-led.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 22: Cambio de estado de un led cada 3 segundos

Este ejemplo es similar al anterior, pero ahora el evento es de tiempo (un tic cada segundo). Por ello, cada 3 segundos el LED cambia de estado

(Ej-22-cont-3-toggle-led-time.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Contadores unarios módulo M

Los contadores cíclicos que sólo pueden estar en M estados se denominan contadores módulo M. En nuestro caso estamos trabajando con contadores unarios módulo M. Así, un contador módulo 4 sólo puede tener 4 valores diferentes. Nos da igual dónde empieza el ciclo y la cantidad de marcas.

Los siguientes ejemplos son contadores módulo 4:

  • Contador de 4 marcas que cuenta 1, 11, 111, 1111 y vuelve a empezar
  • Contador de 8 marcas que cuenta 111, 1111, 11111, 111111 y vuelve a empezar
  • Contador de 3 marcas que cuenta 0 (sin marcas), 1, 11 y 111

El convenio que hemos utilizado hasta ahora para los números unarios es que cuentan a partir de 0 (sin marca). En estos caso, el número de estados posibles siempre es el número de marcas + 1. Así, un contador unario de 4 marcas, tiene 5 estados: 0, 1, 11, 111 y 1111

Pero si NO tenemos en cuenta el 0, y siempre empezamos a contar a partir de 1, entonces un contador de n marcas tiene n estados
Según la aplicación, utilizaremos contadores unarios empezando en 0 ó en 1

En realidad lo que hemos hecho en el apartado anterior de Repeticiones son Contadores módulo M, y por tanto ya los conocemos, pero aprovecharemos para hacer un par de ejemplos utilizando esta nueva terminología

Ejemplo 23: Contador unario módulo 4 de 3 marcas

En este ejemplo se muestra un contador módulo 4 de 3 marcas en los LEDs, que realiza la cuenta 0 (sin marca), 1, 11, 111 y vuelve a comenzar. Cambia de estado cada segundo

Como tenemos en cuenta el 0, sólo necesitamos 3 marcas para que sea módulo 4

(Ej-23-cont-modulo-4.ice)

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Ejemplo 24: Contador unario módulo 4 de 4 marcas

Ahora usamos un contador unario módulo 4 pero de 4 marcas. No se usa el 0. La secuencia que realiza el contador es: 1, 11, 111, y 1111. Al llegar a la última vuelve a comenzar

Como ahora NO tenemos en cuenta el 0, para que sea un contador módulo 4 necesitamos 4 marcas

(Ej-24-cont-modulo-4.ice)

Para la implementación del contador unario de 4 marcas se utiliza un registo de desplazamiento a la derecha, pero inicializado con el valor 1. Como estamos usando un unario con alineación a la izquierda, el valor para la inicialización es: 'b1000

En este video de Youtube se muestra su funcionamiento:

Click to see the youtube video

Observamos cómo la primera marca, la de la izquierda, siempre está presente en toda la secuencia. Por ello el LED de la izquierda siempre está encendido

Señales periódicas

En el Cuaderno técnico 13: Señales periódicas y temporización se trató en profundidad el tema de la generación de las señales periódicas, y se definió la terminología. En este apartado nos centraremos en los fundamentos para ver como todo nace del sistema unario

Ejemplo 25: Señal de periodo T=2 ciclos

Empezamos por generar la señal más rápida posible: una que tiene de periodo 2 ciclos de reloj del sistema. Por ello necesitamos un contador módulo 2 (unario), que tiene 2 estados. La salida del biestable de la derecha es la señal a generar

La señal generada es como se muestra en esta figura

El periodo de esta señal es de 2 ciclos, o lo que es lo mismo, su frecuencia es la mitad (F/2) de la del sistema: 12Mhz/2 = 6Mhz

Este es el circuito:

(Ej-25-periodica-T2.ice)

Para visualizar esta señal periódica usamos el LEDOscopio de 8 bits, que mostramos en los LEDs de la placa AP-LED8. El LED de la izquierda (D7) representa el ciclo 0, y el de la derecha (D0) el ciclo 7:

Ejemplo 26: Señal de periodo T=2 ciclos(II)

En este ejemplo se genera la misma señal que el ejemplo 25: Un señal periódica de periodo T=2 ciclos, pero usando un contador unario del sistema módulo 2 de 2 marcas. Por ello tiene que inicializarse con el valor 'b10

(Ej-26-periodica-T2.ice)

La señal que se obtiene es exactamente la misma que en el ejemplo 25

Ejemplo 27: Señal de periodo T=4 ciclos

Para consolidar esta parte de generación de señales periódicas, vamos a obtener una de periodo T=4, utilizando un contador unario del sistema módulo 4, de 4 marcas

Este es el circuito:

(Ej-27-periodica-T4.ice)

Y esto es lo que se obtiene en el LEDOscopio:

Limitaciones del sistema unario

El sistema uniario es muy intuitivo y muy sencillo de entender. Y con él se pueden realizar todas las operaciones aritméticas básicas. Sin embargo tiene una liminación: funciona muy bien para números bajos, pero es muy poco eficiente para números altos

Si por ejemplo queremos representar el número 2000.... ¡Necesitmos escribir dos mil marcas!! Esto es algo inviable. Y si lo queremos almacenar en nuestros circuitos, necesitamos un registro de 2000 biestables!!!

También, por ejemplo, si partimos de una señal de reloj del sistema de 12Mhz, y queremos obtener a partir de ella una señal de 1Hz, tenemos que construir un divisor de 12.000.000, de forma que 12Mhz / 12.000.000 = 1Hz. Para construir este divisor necesitamos un contador Módulo 12 millones... para lo que necesitamos almacenar 12 millones de marcas... es decir.... necesitamos ¡¡12 millones de biestables!!

Recopilamos estos dos problemas en forma de retos:

  • Reto 1: ¿Cómo almacenar el número 2000 en unario?
  • Reto 2: ¿Cómo generar una señal de 1Hz en unario? (Divisor entre 12 millones)

Necesitamos otra manera más potente de codificar los números, que precise de muchísimos menos biestables D

Ábaco

En el sistema unario todas las marcas valen la unidad, por lo que si queremos representar por ejemplo el número 2000, ¡¡necesitamos colocar dos mil marcas!!

Para solventar las limitaciones, el siguiente paso es agrupar las marcas en grupos que tengan diferentes valores. Estos valores pueden ser los que nosotros queramos, pero típicamente usamos el sistema decimal, por lo que agrupamos en grupos de 10 (decenas, centenas, unidades de millar...). Así es como se disponen en los dispositivos mecánicos denominados ábacos

Estudiaremos el funcionamiento de estos ábacos, paso a paso, para replicar su comportamiento electrónicamente

Ábaco decimal

Los ábacos decimales son los típicos. Constan de varias filas. En cada fila hay 10 cuentas. La primera fila son las unidades, la segunda las decenas, la tercera las centenas...

Utilizaremos el sistema unario con alineación a la izquierda. Las cuentas que están en la derecha es como si NO existiesen. Para entender su funcionamiento iremos construyéndolo poco a poco

Ábaco de unidades

Comenzamos con un ábaco decimal de unidades. Está formado por una única fila que tiene 10 cuentas, lo que nos permite contar desde el 0 hasta el 10. En nuestros diagramas estas cuentas las dibujaremos en color verde (🟢️):

En esta figura se muestra cómo se realiza la cuenta desde el 0 hasta el 10:

Observamos que en total hay 11 valores, del 0 al 10. Esto lo utilizaremos más adelante para construir el ábaco optimizado y luego implementarlo mediante circuitos

Ábaco de unidades y decenas

Ahora añadimos a nuestro ábaco una segunda fila, con 10 cuentas, donde cada cuenta vale 10: es decir, representan las decenas.

En esta figura se muestra la cuenta desde 10 hasta 20:

En estos ábacos vemos que hay algunos números que se pueden representar de dos formas diferentes. Decimos que hay redundancia. Por ejemplo el número 20 lo podemos representar con 10 unidades y 1 decena. Pero también con 2 decenas. El número 10 también es redundante: lo podemos representar medaite 10 unidades, ó medinte una decena

Cuando se usan estos ábacos físicos, cada vez que hay 10 cuentas de unidades en la izquierda, se llevan a la derecha y se incrementan las decenas. De manera que el número 10, lo representaremos siempre con 0 unidades y 1 decena. El 20 con 0 unidades y 2 decenas. Más adelante eliminaremos esta redundancia para crear ábacos más optimizados y que sean más fáciles de implementar electrónicamente

Ábaco decimal optimizado

Antes de seguir construyendo el ábaco, aprovechamos para optimizarlo. Hemos visto que hay números redundantes: se pueden representar mediante 2 configuraciones de cuentas diferentes. Esto NO representa un problema cuando estamos usando el ábaco físico, PERO si eliminamos esta redundancia los circuios se simplifican

En el ábaco decimal optimizado utilizamos en cada fila 9 cuentas. El sistema sigue siendo decimal (base 10), ya que en total en cada fila hay 10 estados: el 0 (ninguna marca) hasta el 9 (9 marcas en la izquierda)

En esta figura se muestra la cuenta desde el 0 hasta el 10, y se puede ver cómo el 10 sólo se representa de una única manera

En esta otra figura se muestra la cuenta desde el 10 hasta el 20, y comprobamos también cómo el 20 ya NO es redundante

El valor máximo de este ábaco es de 99. Pero como se incluye el 0, en total puede representar 100 números (del 0 al 99). Aquí es donde vemos cómo las limitaciones se han reducido. Antes necesitaríamos 99 marcas para representar este número en Unario. Con el ábaco optimizado sólo necesitamos 18. ¡Nos hemos ahorrado 81 marcas!

Ejemplo 28: Contador manual módulo 10

Comenzamos implementando la primera fila del ábaco decimal optimizado: las unidades. Colocamos 9 Biestables y construimos un contador unario módulo 10, que se incrementa cada vez que apretamos el pulsador SW1. El resultado se muestra en 9 LEDs, conectados a los pines de D8 a D0

(Ej-28-abaco-cont-M10.ice)

Este es el escenario. Colocamos la placa AP-LED8. Pero como sólo tiene 8 LEDs (y necesitamos nueve) conectamos otra placa de 6 LEDs en los pines D13-D8. El contador se muestra en los 9 LEDs empezando desde la derecha

La primera vez que se aprieta el pulsador SW1 el contador vale 1, y se enciende el LED de la izquierda:

Sucesivas pulsaciones incrementan las unidades hasta llegar al valor máximo de 9:

Una nueva pulsación (la décima) hace que el contador se reinicie a 0, por lo que todos los LEDs se apagan

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Ejemplo 29: Contador módulo 100. Cuenta de 10 segundos

Ahora implementamos las decenas. Utilizamos un registro de desplazamiento a la derecha de 9 biestables, que se desplaza cada vez que se incrementa 10 veces (decenas). La señal inc10 se usa para incrementar las decenas y para poner a 0 las unidades. Las decenas las mostramos en 9 LEDs: Los LEDs verdes del 0 al 7 y usamos el LED D13 de la placa de 6 LEDs

En vez de manualmente, las unidades se incrementan cada 100ms, por lo que las decenas se activan cada 10x100ms = 1 segundo. Este es el circuito:

(Ej-29-abaco-cont-M100.ice)

El escenario es el mismo que el del ejemplo anterior. Ahora el LED D13 se usamo como LED d8 de las Decenas

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Reto del número 2000

Ya estamos listos para responder al reto planteado en los apartado anteriores... En el sistema Unario, ¿Cómo podemos representar el número 2000?. Si usamos el sistema unario puro, necesitamos 2000 marcas (2000 biestables). Esto es totalmente inviable. Por ello hay que utilizar el sistema del ábaco. Necesitamos 4 filas de 9 marcas: unidades (x1), decenas (x10), centenas (x100) y unidades de millar (x1000)

En total necesitamos 4x9 = 36 marcas. Es decir, que para representar el número 2000 necesitamos 36 Biestables D. Hemos pasado de 2000 a 36!! Un ahorro muy considerable. Aunque este número todavía se puede obtimizar mucho más, usando el sistema binario natural, ahora ya sí es viable, y se pueden implementar circuitos que manejen estas cantidades

Reto de la señal de 1Hz

El reto consiste en generar una señal de 1Hz para hacer parpadear un LED, a partir de la señal de reloj del sistema, que es de 12Mhz. Para lograrlo necesitamos construir un divisor entre 12 millones, aplicado a la señal de reloj del sistema. Este divisor lo implementamos con un contador módulo 12 millones... para lo cual necesitamos ¡¡12 millones de Biestables D!!

Esto es inviable. Para solucionarlo utilizaremos marcas con diferentes pesos, como en el ábaco, e iremos dividiendo las señales obtenidas. Directamente podemos utilizar un ábaco decimal, pero usamos filas con distintos números de marcas, para hacer divisiones de distintos números

Iremos resolviendo el reto paso a paso, usando varios circuitos intermedios, para medirlos y entender perfectamente lo que está sucediendo

Ejemplo 30: Señal de 1Mhz

Empezamos generando una señal de 1Mhz. Para ello basta con construir un divisor entre 12. Dado que la señal de reloj del sistema es de 12Mhz, al dividirlo entre 12 obtenemos una señal de 1Mhz

El divisor entre 12 lo implementamos con un contador unario módulo 12. Pero utilizaremos un ábaco optimizado, por lo que sólo necesitamos 11 marcas (11 marcas + 0 = 12 estados). Este es el circuito:

(Ej-30-senal-1Mhz-divisor-12.ice)

La señal fila1 es la que se activa cuando se ha completado la fila 1 del ábaco, que es de 11 marcas. Es esta señal la que utilizamos para resetear el contador. Y es la señal que divide entre 12 la del reloj, por lo que debe durar 12 ciclos de reloj. La medimos con el Analizador lógico. Estos con los resultados:

Observamos que efectivamente la señal fila1 dura 12 ciclos de reloj, que se corresponde con una señal de frecuencia 1Mhz (Periodo de 1µs)

Ejemplo 31: Señal de 100Khz

Seguimos con nuestro viaje a la generación de la señal de 1 Hz. Ya tenemos una de 1Mhz. El siguiente paso es dividirlo entre 10 para obtener una señal de 100Khz. Así, lo que tenemos son dos divisores encadenados. Partimos de una señal de 12Mhz y la dividimos entre 12 y luego entre 10. Matemáticamente escribimos: F/12/10 = F * 1/12 * 1/10 = F * 1 / 120. Es decir, que al encadenar los divisores obtenemos un nuevo divisor que realiza una división igual al producto de las divisiones. En nuestro caso es una división entre 120

Para este segundo divisor usamos un contador unario optimizado de 9 marcas

En nuestro "abaco" tenemos ahora dos filas. La fila1 de 11 marcas, para dividir entre 12. La fila2 de 9 marcas, para dividir entre 10

(Ej-31-senal-100Khz.ice)

Este segundo divisor lo denominamos de "decenas" (aunque el valor de cada marca es de 12). Se incrementa cuando llega un tic por la señal de fila1, a diferencia del primer divisor que se incrementa con cada ciclo del sistema. Cuando se completa la fila 2 Y también la fila1 es cuando el segundo contador da la vuelta (y se activa fila2)

Esta señal es la que medimos con el analizador lógico icerok

Vemos que efectivamente la señal obtenida es de 100Khz, y cada periodo dura 120 ciclos (es el divisor)

Ejemplo 32: Señal de 10Khz

Añadimos una nueva fila en el ábaco (fila 3), con 9 marcas para dividir entre 10 la señal de 100Khz de la fila anterior, obteniendo la señal de 10Khz. La fila 3 es similar a la 2 (copy & paste), cambiando los nombres de las etiquetas

(Ej-32-senal-10Khz.ice)

Lo medimos con el analizador lógico icerok:

Y comprobamos que efectivamente la señal es de 10Khz

Ejemplo 33: Señal de 1Khz

Añadimos la fila 4, con 9 marcas para dividir entre 10 la señal de 10Khz de la fila anterior, obteniendo la señal de 1Khz. La fila 4 es similar a la 3 (copy & paste), cambiando los nombres de las etiquetas

(Ej-33-senal-1Khz.ice)

Lo medimos con el analizador lógico icerok:

Cálculo para obtener la señal de 1Hz

Podríamos seguir haciendo ejemplos para generar el resto de señales y medirlas, pero mejor pasamos a la solución final. En vez de hacer un divisor entre 12 millones, lo haremos de la mitad: 6 millones, y esta señal resultalte la pasamos por un biestable T para generar la señal final de 1Hz con ciclo de trabajo del 50%: medio segundo el LED encendido, y medio segundo apagado

Para obtener esta señal final utilizamos estos divisores: 12, 5x10 y 5. Los ponemos en forma de ábaco. Usamos un ábaco optimizado, con diferentes números de cuentas. Por ello estas cantidades son 11, 5x9 y 4

Se cumple que 6_000_000 = 12 * 10 * 10 * 10 * 10 * 10 * 5

Ejemplo 34: Señal de 1Hz

Implementamos el ábaco mostrado en la sección anterior. Las filas de la 2 a la 6 son iguales (copy & paste): Son divisores entre 10, para lo que se usan registro de desplazamiento a la derecha con reset de 9 bits. La fila 1 es un divisor entre 12, implementado con registros de desplazamiento del sistema. La fila 7 es un divisor entre 5 (en vez de 10) para obtener la señal final de 2Hz. Se trata de una señal periódica normalizada, que la pasamos por un biestble T para obtener la señal final de 1Hz: fila7

(Ej-34-senal-1Hz.ice)

El analizador lógico interno icerok del sistema toma muestras de las señales a la velocidad de 12Mhz. Como la memoria máxima interna en la Alhambra II es de 16Kb, sólo nos da para almacenar hasta 1.3ms. Señales con duraciones mayores a ese tiempo NO SE PUEDEN MEDIR

Para solucionar este probelma hay dos opciones:

  • 1) Utilizar un analizador lógico externo
  • 2) Comparar la señal con otra de referencia que previamente haya sido medida

Es este circuito utilizamos la opción 2. Usamos un corazón de 1Hz, que ha sido diseñado en el Cuaderno técnico: CT13: Señales periódicas y temporización y medido. La señal final fila 7 se saca por el D0, y la del corazón por D1. Visualmente comprobamos que laten a la misma frecuencia

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Tablas

Las tablas nos sirven para almacenar números constantes, y seleccionar en cada momento qué valor queremos leer. Para ello hay que referenciar la fila de la tabla. Vamos a ver cómo podemos hacer esto usando únicamente números unarios

Los valores almacenados en la tabla pueden ser cualesquiera, en la codificación que queramos. Pero, ya que este cuaderno técnico es sobre el sistema unario, lo que almacenaremos serán también números unarios. Y en los ejemplos usaremos números unarios de 8 marcas

Ejemplo 35: Tabla de una única fila

Empezamos por la tabla más sencilla: una que sólo tiene una única fila. La denotaremos como la fila 0

Fila Valor
0 🟢️🟢️🟢️

Esta tabla es en realidad una única constante, y ya sabríamos cómo mostrarla en los leds, usando el bloque ku. Este es el circuito que almacena el valor "111" y lo muestra en los LEDs

(Ej-35-tabla-filasx1.ice)

Y este es el resultado. El número está alineado a la derecha:

Ejemplo 36: Tabla de dos filas

Vamos a implementar ahora una tabla de 2 elementos, situados en la fila 0 y la fila 1. Almacenamos los números unarios 🟢️🟢️🟢️ y 🟢️🟢️🟢️🟢️🟢️🟢️, de 8 marcas. Utilizamos un Multiplexor 2-1 de 8 bits. Por cada una de sus entradas se introducen las constantes a almacenar. Podríamos usar el bloque ku como en el ejemplo anterior, pero en este caso vamos a utilizar la constante genérica de 8 bits (para enfatizar la idea de que esta tabla puede contener cualquier tipo de número, y no sólo unarios)

(Ej-36-tabla-filasx2.ice)

Como la tabla tiene sólo dos filas, usamos un número unario de 1 marca para su selección. Este número es equivalente en binario, por lo que el circuito en realidad no es exclusivo de la numeración unaria

En este vídeo de Youtube lo vemos en funcionamiento. Por defecto se muestra en los LEDs el número de la fila 0, que es 🟢️🟢️🟢️ (alineado a la derecha). Al apretar el pulsador SW1 se muestra el de la fila 1: 🟢️🟢️🟢️🟢️🟢️🟢️

Click to see the youtube video

Ejemplo 37: Tabla de tres filas

Usamos ahora un número unario de 2 marcas para direccionar una tabla de 3 filas. No podemos usar un multiplexor 4-1 porque por su entrada hay que introducir un número binario de 2 bits... que es diferente al unario de 2 marcas. La manera de implementar tablas de más de 2 filas es usando multiplexores 2-1 en cascada

(Ej-37-tabla-filasx3.ice)

En estas estructuras la prioridad siempre está en la derecha. A medida que el número unario crece, se van sacando por los LEDs la constante de más a la derecha

La tabla ahora la estamos direccionando con un contador unario Módulo 3, que tiene 2 marcas. Este contador lo incrementamos con un pulsador, y en los LEDs se ve la secuencia almacenada: 0, 🟢️🟢️🟢️ y 🟢️🟢️🟢️🟢️🟢️🟢️

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Ejemplo 38: Tabla de cinco filas

Ahora implementamos una tabla de cinco filas, con 5 valores unarios de 8 marcas: 0, 🟢️🟢️🟢️️️, 🟢️🟢️🟢️️️🟢️🟢️, 🟢️🟢️🟢️️️🟢️🟢️🟢️️️, 🟢️🟢️🟢️🟢️🟢️️️🟢️🟢️🟢️️️
Se utiliza un contador unario módulo 5, que tiene 4 marcas. Este contador se incrementa automáticamente cada segundo. Su valor se muestra en los LEDs verdes y se usa para direccionar la tabla

(Ej-38-tabla-filasx5.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Operaciones Aritméticas: Incremento y Decremento

El sistema unario es muy básic PERO tiene la misma potencia que el sistema decimal. Es decir, que con él podemos realizar CUALQUIER OPERACIÓN ARITMÉTICA. Hemos visto que tiene limitaciones para trabajar con números grandes, pero aquí estamos interesados en los fundamentos

De todas las operaciones, sólo veremos las dos más básicas: Incrementos y decrementos en la cantidad de 1 unidad. Es decir, veremos las operaciones de sumar 1 y restar 1. El resto de operaciones lo dejamos para futuros cuadernos técnicos sobre los fundamentos de la electróncia

Si sabemos sumar 1, basta con repetir esta operación para sumar cantidades mayores. No importa ahora si esto es poco eficiente

En el sistema unario, la operación de incremento se realiza añadiendo una marca (bien a la izquierda o a la derecha, según la alineación utilizada). Esto se implementa mediante una operación de desplazamiento de bits

De igual forma, la operación de decremento se realiza eliminando una marca. Esto también lo conseguimos utilizando operaciones de desplazamiento de bits

Las operaciones de desplazamiento las podemos realizar de varias formas: usando circuitos combinacionales o secuenciales. Veremos ejemplos de ambos tipos

Incremento/decremento combinacional

Estas operaciones las realizamos con los bloques de desplazamiento combinaciones SL1 y SR1 de la colección iceWires. Por ejemplo, si estamos trabajando con números de 4 marcas, usamos estos bloques:

Ejemplo 39: Incremento/decremento de un numero de 4 marcas

Partimos del número unario 🟢️🟢️🟢️️️ almacenado en un registro de 4 marcas (hemos usado notación binaria). El número está alineado a la derecha. Por un lado se incrementa añadiendo un 1 por la izquierda (usando un desplazador a la izquierda), y por el otro se decrementa introduciendo un 0 por la izquierda y desplazando a la derecha

(Ej-39-incdec-comb.ice)

En los 4 LEDs conectados en D3-D0 se muestra el número incrementado, que será 🟢️🟢️🟢️️️🟢️. En los 4 LEDs conectados en D11-D8 se muestra el número decrementado: 🟢️🟢️. En los LEDs del 0 al 4 se muestra el número original: 🟢️🟢️🟢️️️

Este es el resultado:

Incremento/decremento secuencial

Las operaciones de incremento y decremento también se pueden realizar utilizando circuitos secuenciales. Tenemos dos maneras de hacerlo: utilizando registros junto a los circuitos combinacionales de desplazamiento visto en el apartado anterior, o bien usando registros de desplazamiento (como hemos visto al crear contadores)

Registro + desplazamiento combinacional

Esta es la estructura clásica para implementar contadores y en general cualquier circuito secuencial que tiene que realizar alguna operación. Por un lado se utiliza un registro que almacena el número (el estado), al que se le conecta a su salida el circuito combinacional que realiza la operación en cuestión. El nuevo valor se coloca a la entrada del registro y se actualiza en el siguiente ciclo

En el caso de incremento/decremento unario, colocamos un registro para almacenar el número unario de n marcas. A su salida conectamos un circuito combinacional de desplazamiento (hacia la izquierda o derecha) e introducimos el resultado por la entrada del registro

Ejemplo 40: Contadores ascendente y descendente

Lo vemos mejor con un ejemplo. Implementamos dos contadores independientes, uno ascendente y otro descendente, de 6 marcas. El ascendente se muestra en los LEDs de la derecha D5-D0, y el descendente en los de la izquierda: D13-D8. Con el pulsador SW2 se incrementa el contador ascendente, y con SW1 se actualiza el descendente

(Ej-40-incdec-seq1.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Registros de desplazamiento

Otro opción para implementar las operaciones de incremento y decremento es utilizar registros de desplazamiento a izquierda y derecha, de la colección iceSRegs. Es la opción que hemos utilizado hasta ahora, y es la más cómoda y sencilla

Ejemplo 41: Contadores ascendente y descendente

Repetimos el ejemplo anterior (40): dos contadores independientes, uno ascendente y otro descendente, pero usando registros de desplazamiento

(Ej-41-incdec-seq2.ice)

El funcionamiento es exactamente el mismo que el apartado anterior. El vídeo es el mismo:

Click to see the youtube video

Ejemplo 42: Contador con incremento/decremento manual

En este ejemplo implementamos un contador unario de 14 marcas, con incremento/decremento manual usando los botones SW1 y SW2. Lo que se simula es un controlador de volumen (o una barra de progreso), que se controla con los pulsadores

Se utiliza un registro de desplazamiento derecha-izquierda para implementar las operaciones de incremento/decremento

(Ej-42-incdec-volumen.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Conversiones entre Unario y Binario

El sistema unario es muy útil para entender los fundamentos de la electrónica digitial, y así poder diseñar circuitos sin tener muchos conocimientos. ¡El sistema unario es muy intuitivo!

Pero como vimos en la parte de limitaciones, SOLO nos vale para números relativamente pequeños. Si queremos trabajar con números más grandes, o hacer circuito más óptimizados, lo que se usa es el sistema binario natural

Muchas veces podemos tener lo mejor de ambos mundos. Usar el sistema unario en contraladores, para que sean más sencillos de hacer y mantener, pero usar el sistema binario en otras partes del circuito. Por ello necesitamos realizar conversiones entre ambos. La conversión de unario a binario la denominamos codificación, mientras que el proceso inverso, de binario a unario, lo llamamos decodificación

Cuando usamos números unarios de 1 ó 2 marcas, no hay ahorro si usamos el sistema binario: necesitamos los mismos bits (bit = marca en este caso). Pero a partir de 3 marcas empieza el ahorro de bits al usar binario. Y este ahorro además crece exponencialmente con el tamaño del número

Numero Marcas unario bits binario Ahorro (bits)
3 3 2 1
4-7 4-7 3 1-4
8-15 8-15 4 4-11
16-31 16-31 5 11-26
32-63 32-63 6 26-57
64 64-127 7 57-120
128 128-255 8 120-247
256 256-511 9 247-502
512 512-1023 10 502-1013
1024 1024-2047 11 1013-2036
2048 2048-2095 12 2036-2083
4096 4096-8191 13 2083-8178
8192 8192-16383 14 8178-16369
16384 16384-32767 15 16369-32752
32768 32768-65535 16 32752-65519

Dado que usamos biestables para implementar las marcas y los bits, la columna de ahorra nos da intuición sobre los recursos que nos ahorramos usando un sistema u otro. Hasta el 15 el ahorro es limitado. Es mejor el binario pero tampoco se consumen tantos recursos. Pero por ejemplo para el número 1024 el ahorro es aproximadamente de 1000 biestables!!! En este caso No es que ahorremos, es que 1000 biestables son demasiados...

Para realizar las conversiones vamos a utilizar los bloques encoder-u y decoder-u de la colección iceUnary

Codificador unario

El codificador unario recibe por su entrada un número unario de n marcas y genera por su salida un número binario de m bits. Es un codificador porque reduce el número de bits de la entrada (o en el caso peor los iguala). Pasa de más bits a menos bits, pero el número es el mismo

Este es el aspecto del bloque:

Ejemplo 43: Codificador unario de 7 marcas

En este ejemplo se utiliza un contador unario de 7 marcas que se incrementa al apretar el pulsador SW1. Su salida se muestra por los LEDs D6-D0. El valor unario se codifica en binario y se muestra por los LEDs 2-0. Se utiliza alineación derecha

Este es el circuito:

(Ej-43-encoder-7-3.ice)

En esta imagen los vemos en acción. En los LEDs de la derecha (rojos) vemos el número 11111 (Alineación derecha) y en los LEDs verdes vemos el número binario: 101. Es el número 5 en decimal

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Decodificador unario

El decodificador unario recibe por su entrada un número binario de n bits y genera por su salida un número unario de m marcas. Es un decodificador porque aumenta el número de bits de la entrada (o en el caso peor los iguala). Pasa de menos bits a más bits, pero el número es el mismo

Este es el aspecto del bloque:

Ejemplo 44: Decodificador unario de 4 bits

En este ejemplo se utiliza un contador unario de 7 marcas que se incrementa al apretar el pulsador SW1. Su salida se muestra por los LEDs D6-D0. El valor unario se codifica en binario y se muestra por los LEDs 2-0. Se utiliza alineación derecha

Este es el circuito:

(Ej-44-decoder-4-15.ice)

En esta imagen los vemos en acción. En los LEDs Verdes vemos el número binario 1010 (Alineación derecha) y en los LEDs rojos vemos el número unario: 1111111111. Es el número 10 en decimal

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Codificación one-hot

La codificación one-hot es extremadamente útil, y se utiliza muchísimo en los circuitos digitales. Lo utilizamos cuándo queremos que un momento determinado haya una única parte activa, y el resto desactivadas. Nos permite expresar la idea de secuencialidad: Primero activa esto, luego esto, luego esto otro, etc. Esta idea se representa mediante una ficha que se mueve por un tablero de juego. Las casillas son biestables y sólo hay 1 partícula

Para entender mejor la codificación one-hot, partiremos del sistema unario que ya conocemos, y lo vamos a ir modificando hasta llegar a esta codificación. La idea importante es que la codificación one-hot es en realidad un tipo de sistema unario

Partimos de un sistema unario de 4 marcas. Añadimos una restricción: SIEMPRE tiene que haber al menos una marca. Es decir, que el número "sin marcas", que en el unario normal lo interpretamos como el 0, ahora no existe. Esta es la cuenta que nos queda:

* 🟢️
* 🟢️🟢️
* 🟢️🟢️🟢️
* 🟢️🟢️🟢️🟢️

En total podemos representamos 4 números. Ahora supongamos que con este sistema queremos representar el 0. Usamos el primero número. Es decir, cuando hay sólo 1 marca, tenemos el 0, con 2 marcas el 1, con 3 marcas el 2 y con 4 marcas el 3. Los números que representamos van del 0 al 3:

* 0: 🟢️
* 1: 🟢️🟢️
* 2: 🟢️🟢️🟢️
* 3: 🟢️🟢️🟢️🟢️

Ahora "simplificamos" este sistema y dibujamos sólo la marca final, de más a la derecha. Las marcas de la izquierda las sustituimos por espacios:

* 0: 🟢️
* 1:  🟢️
* 2:   🟢️
* 3*    🟢️

El número queda ahora representado por la posición de la marca derecha. El aspecto es un poco raro, pero al fin y al cabo es un sistema unario, con las mismas propiedades

Ahora cambiamos la alineación a la derecha, ya que es lo estándar para la codificación one-hot (pero sería válido también usar la alineación izquierda). Al ser un sistema unario ambas representaciones son equivalentes (las marcas valen siempre la unidad)

* 0:    🟢️
* 1:   🟢️
* 2:  🟢️
* 3: 🟢️

La marca activa (one-hot) la representamos con el símbolo 1 y la ausencia de marca por el símbolo 0.

* 0: 0001
* 1: 0010
* 2: 0100
* 3: 1000

Así es como nos queda la codificación one-hot definitiva:

Numero d3 d2 d1 d0 one-hot
0 0 0 0 1 0001
1 0 0 1 0 0010
2 0 1 0 0 0100
3 1 0 0 0 1000

Aquí vemos una propiedad muy interesante: El número que representa es en realidad ¡La posición de la marca! (Comenzando por 0)

Num/Posicion 3 2 1 0
0 0 0 0 1
1 0 0 1 0
2 0 1 0 1
3 1 0 0 0

Esta es la codificación que utilizaremos para construir máquinas de estado, mapear periféricos en la memoria o representar la posición de una partícula moviéndose por los LEDs... entre otras cosas

Como la codificación one-hot es un sistema unario, tiene sus mismas limitaciones. Sus usos están limitados a números pequeños. Para números grandes es poco eficiente

Movimiento de una partícula en los LEDs

Una partícula física tiene la propiedad de que en un instante de tiempo está en una posición (x). Supongamos ahora una partícula que se mueve por un eje horizontal en 8 posiciones discretas, desde x=0 hasta x=7. Su posición inicial la representamos en codificación one-hot como 00000001 (Vemos que el 1 está a la derecha). En otro instante de tiempo, el que sea, la partícula estará en otra posición. Por ejemplo: 00001000

El 1 representa la partícula. Como en la codifiación one-hot sólo puede haber un único 1, esto cuadra perfectamente con el comportamiento de la partícula

Una partícula moviéndose de izquierda a derecha la representamos así:

  • Instante t0: 00000001
  • Instante t1: 00000010
  • Instante t2: 00000100
  • ...
  • Instante t7: 10000000

El 1 representa a la partícula, y el 0 al resto de posiciones del espacio no ocupadas por la partícula. Basta con mostrar este número directamente en unos LEDs para dibujar la partícula (no hay que hacer ningún cálculo adicional). Por eso esta codificación es muy interesante para desplazar partículas por LEDs

Ejemplo 45: Desplazamiento de un LED de izquierda a derecha

Utilizamos un registro de desplazamiento de 8 bits, inicializado con la posición de origen del LED: 00000001. Cada segundo el registro se desplaza a la izquierda, generando el siguiente número (one-hot) y mostrándolo en los LEDs. El efecto es que "vemos" el LED moviéndose

(Ej-45-one-hot-LEDs.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Para que la partícula se vuelva a mover hay que apretar el botón de reset

Ejemplo 46: Movimiento izquierda-derecha manual de un LED

En este ejemplo se desplaza el LED manualmente al apretar las teclas SW1 o SW2. Se utiliza un registro de desplazamiento izquierda-derecha inicializado con el valor one-hot 00010000

(Ej-46-one-hot-LEDs-manual.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Si la partícula sale fuera de los LEDs, se pierde. En ese caso hay que apretar el pulsador de Reset para volver al estado inicial

Tablero de juego y bucles espaciales

Imaginemos que tenemos un tablero de juego muy sencillo, en el que sólo hay 8 casillas situadas horizontalmente. En el juego sólo hay un jugador, que tiene sólo una ficha. Esta ficha, en un momento dado, sólo puede estar en una de las casillas. Este tipo de situaciones se codifican fácilmente usando one-hot

De hecho, esto es equivalente a la posición de la partícula que hemos visto en el apartado anterior

Las casillas del tablero se implementan con biestables D conectados en cascada, y la ficha es un 1 que se desplaza por estos biestables-casillas. Nada nos impide conectar la casilla de la izquierda con la de la derecha, formando un bucle espacial. La consecuencia de esto es que la ficha o partícula ahora se desplazará indefinidamente por este tablero. Al llegar a la izquierda vuelve a aparecer por la derecha

En realidad sería más adecuado representarlo como una tablero circular, en vez de lineal. La ficha da vueltas indefinidamente en este bucle espacial...

Ejemplo 47: Desplazamiento circular de un LED

Modificamos el ejemplo 47, donde el LED se mueve de derecha a izquierda, para que ahora lo haga indefinidmente, en un movimiento circular. Sólo hay que conectar la salida so del registro con la entrada si

(Ej-47-one-hot-LEDs-circular.ice)

En este vídeo de Youtube lo vemos en funcionamiento

Click to see the youtube video

Contador módulo M y señales periódicas

Los contadores módulo M se implementan muy fácilmente con la codificación one-hot: Sólo hay que realizar un bucle espacial, conectando su salida serie con la entrada serie, como hemos visto en el apartado anterior. Y ya está.

Un contador módulo M se implementa en one-hot con un registro de desplazamiento de M bits

Una vez que disponemos de un contador módulo M, ya podemos generar señales periódicas. Esto se desarrolló más extensamente en el Cuaderno ténico 13: Señales periódicas y temporización

Pero ahora ya conocemos los fundamentos. Sabemos desde donde arranca todo: del sistema unario

Ábaco one-hot

Si queremos representar números más grandes con one-hot, igual que hicimos con el sistema unario natural, utilizamos un ábaco. Cada fila es un número one-hot, y cada fila tiene un peso. Estos ábacos hay que representarlos con las casillas de un tablero de juego (en vez de cuentas en una barra). En cada fila sólo puede haber una ficha

Ábaco decimal de unidades

Empezamos por lo más sencillo. Un único ábaco que sólo tiene una fila, que representa las unidades, pero en codificación one-hot.

Para contar movemos la ficha con la mano, a la posición deseada. En esta figura se muestra la cuenta hasta 9, empezando por el 0

Ábaco decimal de unidades y decenas

Añadimos una fila nueva, que representa las decenas. Ahora necesitamos 2 fichas: una para las unidades y otra para las decenas.

En esta figura se muestra la cuenta del 0 al 19:

Al llegar al 10, la ficha verde se lleva a la posición 0 y se mueve la ficha azul una casilla a la izquierda

Con este ábaco podemos contar desde 0 a 99. En total necesitamos 20 Biestables!! (Frente a los 99 que necesitaríamos si no usamos el ábaco)

Reto numero 2000

¿Cómo representamos el número 2000 en one-hot? Necesitaríamos un total de 2001 Biestables. Esto es inviable. Por eso hay que usar un ábaco decimal con 4 filas: Unidades, decenas, centenas y unidades de millar

En total, para representar el número 2000 necesitamos 4x10 = 40 Biestables. Aunque se podrían usar sólo 3 casillas para las unidades de millar, quedando un total de 3 x 10 + 3 = 33 Biestables

Ejemplo 48: Señal de 1Mhz

Como partimos de una señal del sistema de 12Mhz, para obtener una señal de 1Mhz necesitamos construir un divisor entre 12: 12Mhz / 12 = 1Mhz

El divisor entre 12 lo construimos con un contador módulo 12, para lo que necesitamos 12 Biestables. Usamos un registro de desplazamiento a la izquierda de 12 bits, conectado formando un bucle espacial

(Ej-48-one-hot-1Mhz.ice)

Lo medimos y obtenemos el mismo resultado que con el ábaco unario, como era de esperar (Ejemplo 30)

Ejemplo 49: Señal de 100Khz

Para generar una señal de 100Khz a partir de 12Mhz hay que dividir entre 12 y 10. El cálculo es el siguiente: 12Mhz = 12 * 10 * 100Khz
Construimos un ábaco que tiene 12 biestables en las unidades y 10 en las "decenas"

(Ej-49-one-hot-100Khz.ice)

Hay que conectar los dos contadores módulo M en serie. Al usar one-hot, la construcción del ábaco es más sencilla. No hay que usar registros de desplazamiento con reset

Lo medimos y obtenemos el mismo resultado que con el ábaco unario, como era de esperar (Ejemplo 31)

Ejemplo 50: Señal 1Hz

Para obtener una señal de 1Hz a partir de la de 12Mhz utilizamos divisores encadenados. Vamos a generar una señal de 2Hz y luego la pasamos por un biestable T para obtener la final de 1Hz con un ciclo de trabajo del 50% (0.5 segundo a 1 y 0.5 segundos a 0). Descomponemos la señal de 12Mhz en sus factores:

12Mhz = 12 * 10 * 10 * 10 * 10 * 10 * 5 * 2 Hz

Necesitamos un total de 7 contadores módulo M. El primero es módulo 12, los siguientes cinco son de módulo 10 y el último de módulo 5. Este es el ábaco para realizar el ćalculo:

Y este es el circuito en el que están todos los contadores módulo M encadenados:

(Ej-50-one-hot-1hz.ice)

El resultado es el mismo que el obtenido con el ábaco unario, del ejemplo 34

Para comprobar el funcionamiento, igual que hicimos en el ejemplo 34, comparamos la señal obtenida con una de referencia que sabemos que es exactamente de 1Hz

En este vídeo de Youtube vemos el funcionamiento:

Click to see the youtube video

Conclusiones

El sistema unario es la forma más básica de representar números. Sólo necesitamos un único símbolo, que se repite por la izquierda o por la derecha para generar números mayores. En los circuitos digitales basta con utilizar biestables D enadenados para implementar estos números (tanto en unario puro como en codificación one-hot). Realizando desplazamientos a la derecha (o izquierda) nos aparece la capacidad de incrementar estos números en una unidad. Y así nace la propiedad de contar, que nos permite contar eventos. Si estos eventos son de tiempo, lo que logramos es cronometrar

Estos contadores simples los convertimos en cíclicos añadiendo una entrada de reset (en sistema unario puro) o bucle espacial (en one-hot). Con esto emergen los contadores módulo M, que nos dotan de las nuevas capacidades para repetir y generar señales periódicas

El poder incrementa un número en una unidad nos permite secuencializar tareas en el tiempo: primero activa esto, luego esto, luego esto otro... permitiendonos hacer controladores de manera muy sencilla e intuitiva

El sistema unario, por ser tan básico y fundamental, está limitado a su uso con números pequeños. Para representar números mayores necesitamos colocar varios unarios en paralelo, y dotar de valores mayores a sus marcas, construyendo ábacos

El siguiente paso será pasar al sistema binario, donde la eficiencia es mucho mayor. La implementación de contadores y contadores módulo M es más compleja, debido a esta codificación binaria, pero hemos visto que a nivel fundamental estos elementos son muy sencillos en unario

Ya tenemos la base fundamental para aprender a realizar controladores más complejos, basados en autómatas finitos. Al igual que los contadores, estos autómatas se implementan muy fácilmente (y de manera muy intutitiva) usando el sistema unario

Estas ideas están reflejadas en este mapa mental

Todavía nos quedan muchos caminos por explorar... y muchos otros nuevos que irán apareciendo. Pero eso será en otros cuadernos técnicos

Autor

Licencia

Enlaces

Clone this wiki locally