Funciones lógicas en LabVIEW

El bit es la mínima cantidad de información posible, puesto que éste almacena únicamente un posible valor, que podemos representar de varias formas: como verdadero o falso, activo-desactivado, 0 ó 1, etc. El operar con este tipo de información constituye la plataforma sobre la que se fundamenta la lógica computacional moderna, en definitiva de los microprocesadores actuales. Recibe el nombre de Lógica Booleana en honor quien la inventó en el siglo XIX, George Boole. En este artículo veremos el uso de las Funciones lógicas en LabVIEW.

Consideremos que los dos posibles valores que puede tomar un bit de información son 0 ó 1. Con los bits podemos realizar varias operaciones. Una forma de representar estas operaciones es mediante unos símbolos que se denominan puertas u operadores lógicos. Dichos operadores requieren de uno o más bits como entrada y producen una salida que depende de ellos y del propio operador. La relación entre los bits de entrada y el resultado producido se pueden representar en una tabla, que se denomina tabla de verdad. La tabla de verdad no nos indica más que el valor que obtendremos a la salida de la función lógica dependiendo de los valores que ésta tenga a su entrada.

Los sistemas digitales se construyen mediante combinación de puertas lógicas. De ellas, las más comunes son NOT, AND, OR, NAND, NOR y XOR.

La puerta lógica más simple es el inversor, también denominado NOT. El resultado de una inversión es cambiar el valor de entrada a su opuesto: si a la entrada tenemos un 0, el resultado será un 1, y viceversa. La tabla de verdad del inversor es la siguiente:

NOT (~)

I O
0 1
1 0
Desde el punto de vista lógico NOT es la única puerta lógica que trabaja sobre una única entrada. En electrónica existen también otras funciones de una sola entrada, los denominados buffers, pero aquí los obviaremos dado que los buffers son transparentes en el sentido lógico.
AND (&)

A B A&B
0 0 0
0 1 0
1 0 0
1 1 1
La salida de la puerta AND es únicamente uno cuando TODAS las entradas lo son. Esto puede generalizarse para el caso en el que el AND es de más de 2 entradas.
OR (|)

A B A|B
0 0 0
0 1 1
1 0 1
1 1 1
La salida de la puerta OR es activa siempre que exista algún una entrada activa. lo mismo puede decirse si la puerta OR es de más de 2 entradas.
NAND

A B NAND
0 0 1
0 1 1
1 0 1
1 1 0
La puerta NAND realiza la función inversa de la AND, por lo que podría construirse enlazando un AND y un NOT. Cuando todas las entradas son activas, el resultado es un cero, en caso contrario la salida es uno.
NOR

A B NOR
0 0 1
0 1 0
1 0 0
1 1 0
La puerta NOR realiza la función inversa de la OR, por lo que sólo produce un uno cuando las dos entradas son cero.
XOR (^)

A B A^B
0 0 0
0 1 1
1 0 1
1 1 0
La función XOR, también llamada OR-Exclusivo, produce un uno siempre que las entradas difieren.

La paleta de funciones booleanas en LabVIEW tiene el siguiente aspecto:

Paleta de funciones Booleanas en LabVIEW
Hagamos un ejemplo minimalista para mostrar las funciones booleanas anteriores. En el Panel Frontal hemos dibujado unas flechas, no son más que meros elementos decorativos. Partiendo de las dos señales booleanas A y B realizamos las operaciones lógicas nombradas anteriormente.

Panel Frontal de las funciones Booleanas en LabVIEW
En el diagrama de bloques queremos hacer patente que las funciones NAND y NOR son las versiones negadas de las AND y OR respectivamente. Es decir,

A NAND B = NOT (A AND B)
A NOR B = NOT (A OR B)
Diagrama de bloques de las funciones lógicas empleadas
Si ejecutamos el programa vemos que el color de los indicadores de salida va cambiando en función de los valores de las señales de entrada X e Y según la función aplicada. Hemos elegido el color verde claro para el valor TRUE y oscuro para FALSE.

En el ejemplo anterior hemos realizado estas operaciones trabajando con unas entradas de tipo boolean. Este es el funcionamiento más habitual para este tipo de operadores. Pero estas funciones lógicas también pueden aplicarse sobre otros tipos de datos. Dentro del ámbito de los lenguajes de programación se denomina polimorfismo al hecho de posibilitar que un mismo interfaz pueda ser empleado sobre diferentes tipos de datos. En nuestro caso podemos decir que las funciones lógicas que nos ofrece LabVIEW son polimórficas, queriendo decir con ello que el mismo símbolo nos va a permitir operar no sólo con variables de entrada de tipo boolean, sino que también permite trabajar con otro tipo de datos. Si aplicamos el NOT a una matriz obtendremos una matriz cuyos elementos serán los negados de los originales, elemento a elemento. En general, podemos aplicar estos operadores sobre arrays de booleans, sobre clusters de booleans, números, arrays numéricos o matrices.

Veamos con otro ejemplo una de las aplicaciones típicas de los operadores numéricos: las máscaras. Las máscaras nos permiten extraer cierto tipo de información del dato sobre el que se aplica. Supongamos que tenemos una secuencia de 8 bit como 01101011 y queremos saber cuáles de los 4 de mayor peso están a uno. Del resto de la secuencia no nos interesa conocer nada, por lo que podemos anularla. Para ello podemos aplicar la función lógica AND con un patrón de 8 bits en el que ponemos a 1 los 4 bits de más peso, tal que 11110000. El resultado 01100000 es un AND que se ejecuta bit a bit.

01101011 AND 11110000 = 01100000
En el siguiente ejemplo de LabVIEW realizamos la máscara del dato de entrada, lo que es equivalente a aplicar la función AND. Al ejecutarlo podemos modificar tanto el valor de entrada como el de la máscara. A pesar de que nosotros introducimos el valor de los datos como enteros, se muestra su valor en binario para que veamos cómo se están realizando las operaciones bit a bit.

Máscara sobre datos de entrada, panel frontal y diagrama de bloques
Los ejemplos anteriores de LabVIEW se han ejecutado en el ordenador. Ahora vamos a implementar un pequeño ejemplo práctico pero trabajando sobre un LEGO MINDSTORMS NXT. Hemos conectado un servomotor en el puerto A del robot NXT. Nuestro objetivo es hacer un sencillo programa que nos permita controlar dicho servomotores con dos pulsadores.

Vamos a crear un pequeño interfaz que deliberadamente nos obligue a hacer uso de funciones lógicas. Para ello activaremos el motor según dos posibles pulsadores:

  • Un pulsador lo hará avanzar en un sentido, y que denominaremos como pulsador P1 (FWD).
  • El segundo pulsador lo hará avanzar en sentido inverso, pulsador P2 (BACK).

Por la forma en la que lo planteamos se van a producir -deliberadamente- 4 casos posibles, según estén pulsados o no cada uno de los dos pulsadores. Podemos representar en una tabla como las anteriores lo que puede suceder:

Control motor

P1 P2 Resultado
0 0 Motor detenido
0 1 Motor retrocede
1 0 Motor avanza
1 1 …¿?
Lo que debe hacer el motor NXT en los tres primeros casos es en cierta medida “lógico”, pero …¿que debe hacer el motor en el caso de que los dos pulsadores estén presionados simultáneamente, indicando cada uno de ellos que haga lo contrario de lo que dice el otro? Como el problema lo definimos nosotros, vamos a decidir que en este caso el motor se detenga, igual que en el primer caso.
Por tanto vemos que vamos a crear tres posibles comportamientos:
  • El motor se detiene.
  • El motor avanza.
  • El motor retrocede.

Ahora reescribamos, para cada uno de los resultados, la misma tabla anterior. Empecemos por la tabla en la que el motor avanza. Así, la siguiente tabla representará cuándo el motor va a avanzar. Si avanza, lo representaremos con un 1 lógico, en caso contrario, con un cero.

Motor avanza

P1 P2 Resultado
0 0 0
0 1 0
1 0 1 (motor avanza!!!)
1 1 0
Según la tabla anterior, veíamos que el motor sólo avanzaba en uno de los 4 posibles casos, que es lo que representa esta tabla. Por lo tanto, veamos en qué única circunstancia se va a producir el hecho de avanza: sólo cuando el pulsador P1 está pulsado y, además, P2 no lo está. Esto podemos escribirlo en la siguiente ecuación:
Avanzar = P1 AND (NOT P2)

Podemos razonar del mismo modo para el caso en el que el motor debe retroceder, y obtenemos que sólo se produce el retroceso cuando P1 no está pulsado, pero sí lo está P2, es decir:

Retroceder = (NOT P1) AND P2
El caso en el que se detiene el motor es un poco más complicado, porque puede darse en dos situaciones posibles, en la primera o en la última, es decir:

Detener = ((NOT P1) AND (NOT P2)) OR (P1 AND P2)
Dado que ya tenemos las ecuaciones lógicas que van a controlar el control de lo motores, podemos implementar el programa en LabVIEW. Como cualquier problema, éste puede resolverse de muchas formas posibles. Nosotros hemos elegido con finalidad didáctica el controlar el motor mediante una estructura case.

Programa de control del motor NXT
Y lo que se ejecuta en los otros dos casos del case es:

Casos alternativos para el control del motor
Y el panel frontal que hemos preparado es el que sigue:

Panel Frontal del control del motor
El programa consta de varias partes:

  • Una primera en la que construyo las funciones lógicas de Avanzar, Retroceder y Detener partiendo de las señales de los pulsadores P1 y P2, tal como he explicado antes. Para comprobar que su funcionamiento es correcto he añadido unos indicadores que muestran su valor en función del estado de los pulsadores. He añadido también dos comentarios para indicar Not P1 y Not P2 con objeto de facilitar la lectura.
  • Con lo anterior ya disponemos de las tres funciones, pero como vamos a trabajar con un case para controlar el estado del motor del NXT… ¿Cómo relaciono Función Build Arraydichas señales con la entrada de control del case? La solución por la que he optado es por la de agrupar las tres señales en un array de tres elementos y convertir a continuación dicho array en un valor numérico, que es el que controlará el caso a ejecutar. Para construir dicho array de booleansFunción Boolean Array To Number hago uso del icono Build Array, que podemos encontrar en la paleta de funciones de Array. El siguiente paso en transformar ese valor numérico, porque un array no puede emplearse para controlar los casos de un case. Empleo la función Boolean Array To Number. Para comprobar qué valor se está asociando muestro el valor numérico con el indicador que llamo Número.
  • A la estructura Case debemos añadirle un caso adicional, porque tal como lo introducimos en el diagrama de bloques sólo tiene dos casos posibles. Además debemos nombrar cada uno de los casos según nos aparezcan los valores en Número, y debemos hacerlos coincidir con según la ejecución adecuada. Para poder ejecutar el programa y observar qué valores ha asignado LabVIEW a esos casos, podemos realizar una primera ejecución asignando a los casos los valores 1, 2 y 3. Debemos además asignar el caso Detener como Default.
  • Todo lo anterior se ejecuta en el interior de un while con su correspondiente botón para detener el programa.

Si todo es correcto:

  • Cuando presionemos P1 debe iluminarse el LED de Avanzar y el motor girar en un sentido.
  • Cuando presionemos P2 debe iluminarse el LED de Retroceder y el motor girar en el sentido contrario al anterior.
  • Cuando presionamos los dos pulsadores o cuando ninguno está presionado, debe iluminarse el LED Detener y el motor debe detenerse.

* Ejecución en modo Remoto: Este programa debe ejecutarse en el PC sin descargar el programa en el NXT, sino mediante control directo desde el LabVIEW en tiempo real, porque la estructura case con casos enumerados no puede compilarse para el NXT.

Para cualquier duda, como siempre, podéis acudir al foro.

Comments are closed.