Читать книгу: «LabVIEW: Entorno gráfico de programación», страница 6

Шрифт:

Figura 3-15. Ejemplo VI para el manejo de cadenas y texto.

En el ejemplo anterior se usa un string inicial que contiene «He medido», también hay tres entradas más: un número en coma flotante, un string y un número entero. El format string se muestra en la parte superior e indica el formato de cada entrada mediante %XY, donde X es la longitud e Y el tipo de datos; además, en este string también se puede incluir texto.

Para configurar este tipo de VI se puede recurrir a la documentación para conocer la sintaxis del terminal format string. También se puede usar un asistente haciendo doble clic sobre el icono y rellenando los campos de forma correcta (Figura 3-16).

La mayoría de estos VI trabajan con expresiones regulares. Las expresiones regulares son un método para representar patrones. Se suele aplicar a textos para encontrar y manipular cadenas de texto que cumplan una determinada condición. Utilizan un complejo sistema para codificar estos patrones que puede consultarse en la ayuda de LabVIEW.

Otros VI para transformar texto en números y viceversa son los que se encuentran en Programming > Numeric > Conversion, concretamente String To Byte Array y Byte Array To String. Estos dos VI no sólo convierten un carácter de texto a un número o viceversa, sino que lo hacen con cadenas de caracteres; por lo tanto, son idóneos para transmitir y recibir señales a través de interfaces como TCP o el puerto serie.


Figura 3-16. Asistente del Format string.

3.2.4. Path

Los path sirven para indicar rutas relativas o absolutas a directorios o ficheros, tanto de la máquina local como de otra en red.

Al guardarse en memoria, se almacena un puntero a una estructura que contiene las partes que forman la ruta (subdirectorios); cada parte de la ruta se guarda como un string. De esta forma se consigue que la ruta sea independiente de la plataforma, es decir, la misma ruta podría ser entendida por LabVIEW funcionando sobre Windows, Unix o MacOS.

En la figura 3-17 se puede ver una constante que se conecta a un indicador y abajo dos nodos que representan a la ruta del VI que lo contiene y la ruta del directorio de datos de LabVIEW.


Figura 3-17. Utilización de un path.

3.2.5. Arrays

Los arrays o arreglos son un conjunto de datos ordenados y de un tipo determinado; de esta forma no puede hablarse simplemente de array, sino de array de booleanos, array de strings, etc.

El cableado de un array es del mismo color que el tipo de datos que contiene, pero más grueso y, en el caso de los numéricos, el cableado es de doble línea para dos o más dimensiones. En el terminal del Diagrama de Bloques aparecerá el tipo de datos entre corchetes.

Junto a los terminales (control, indicador o constante) de cualquier tipo de array aparecen uno o varios índices numéricos que indican el primer elemento que se muestra (nótese que no afecta al contenido, sólo a la visualización, es como un scrollbar). Estos índices también indican la dimensión del array, de manera que si sólo hay uno será de una dimensión, si hay dos índices será de dos dimensiones y así sucesivamente.

Al guardarse en memoria se guarda un puntero a una estructura que consta, en primer lugar, del tamaño de cada dimensión en cuatro bytes por cada una, y a continuación van los datos guardados en el formato que se corresponda al tipo de datos.


Figura 3-18. Representación en memoria de un array de dos dimensiones.

En la figura 3-19 hay cuatro arrays: el primero es uno vacío, al cual para asignarle un tipo, hay que arrastrar una constante a su interior; debajo de éste hay un array numérico de una dimensión; el de la parte superior a la derecha es otro array numérico, pero éste de dos dimensiones (tiene dos índices); el último es un array de strings que muestra los elementos a partir del segundo (el índice tiene un valor de 1).

Al usar un array no hay que declarar el tamaño de cada dimensión, como en otros lenguajes, como C; el array puede re-dimensionarse cuando sea necesario.


Figura 3-19. Diferentes tipos de arrays.

Los arrays, gráficas y tablas pueden exportarse desde el menú contextual al portapapeles, DIAdem o a Excel (si están instalados).

3.2.6. Clusters

Al igual que los arrays, los clusters son un tipo de datos estructurado. También son un conjunto de datos, pero a diferencia de los anteriores, los cluster pueden contener datos de varios tipos en su interior, incluidos otros clusters. El concepto es equivalente a los STRUCT en C o a los RECORD en Pascal.

La figura 3-20 muestra un cluster vacío, otro compuesto de un entero y un array de strings, y otro con un booleano, un entero y un string. Este último cluster es un tipo especial porque es el usado para describir errores (desde la versión 8.20 se muestra por defecto con un color marrón).


Figura 3-20. Clusters.

Para crear un cluster se coloca uno vacío y se arrastran a su interior otros tipos de datos. El orden de los datos en su interior es el mismo en el que se añaden, aunque puede variarse yendo a la opción Reorder Controls In Cluster del menú contextual. En el capítulo sobre la creación de la interfaz se explicará el funcionamiento de esta utilidad cuando se hable sobre el orden de tabulación, sección 13.3.2.

Si se crea un cluster cuyos datos son todos del mismo tipo, podrán aplicarse sobre el cluster las mismas operaciones que podrían aplicarse sobre los elementos de forma individual, como muestra la figura 3-21 (nótese el coertion dot). Por ejemplo, si se crea un cluster cuyos datos son numéricos se podrá sumar a otro número.


Figura 3-21. Suma entre un entero y cluster con los datos numéricos.

Los clusters son recomendables cuando en un subVI hay una gran cantidad de conexiones, pues al emplearlos se pueden agrupar y hacer la conexión más sencilla.

Para facilitar la visualización de constantes de tipo cluster en el Diagrama de Bloques, se pueden visualizar como iconos desde la versión 2010 a través de su correspondiente menú contextual.

3.2.7. Waveforms

Los waveforms son parecidos a los clusters. Se componen de otros datos, que son:

• t0: es un time stamp que indica el momento correspondiente al primer valor.

• dt: es la diferencia de tiempo entre dos valores consecutivos; se supone que ésta no varía.

• Y: un array que contiene los valores del eje vertical.

attributes: otra información que puede añadirse.


Figura 3-22. Waveforms.

3.2.8. Referencias

Las referencias (refnum) o manejadores se usan para simbolizar un objeto externo al programa; éste puede ser el contenido de un fichero (no confundir con path), una conexión TCP, otro VI, etc.

Normalmente lo primero que se hace con las referencias es abrir una conexión y luego se irá pasando secuencialmente la referencia entre los VI, nodos de propiedades o métodos que trabajan con ese objeto.

En memoria se almacenan como números de 32 bits.


Figura 3-23. Algunos tipos de referencias.

3.2.9. Variant

Los variant son un tanto especiales, pues no se trata de un tipo de datos en concreto y, además, pueden incluir propiedades. Se usan cuando los datos pueden cambiar de tipo; por ejemplo, un dato que unas veces pueda ser numeric y otras string. También se usan al trabajar con objetos ActiveX.

Además del dato, contienen el tipo, como puede verse en la figura. Para esto, hay que elegir la opción Show Type en el menú contextual del indicador.


Figura 3-24. Variant.

En memoria se almacena como un puntero a una estructura. La estructura reserva cuatro bytes para codificar el tipo de dato.

3.2.10. Dynamic

Este tipo de datos se utilizan con los VI Express. Incluye datos y atributos asociados con una señal, como el nombre, fecha, etc. Los tipos de datos dynamic, al igual que los waveform, enfatizan el hecho de que los datos son medidas y no sólo números en una columna.

3.3. Manipulación de datos

3.3.1. Manipulación de bytes y bits

Las funciones más sencillas para manipular datos son las que trabajan con bytes y bits. Éstas se encuentran en la paleta Programming > Numeric > Data Manipulation.


Figura 3-25. Paleta para manipulación de datos.

En la segunda fila de este menú están los VI para realizar rotaciones y desplazamientos. La tercera fila tiene VI para dividir y unir bytes en words y viceversa, además de intercambiar la parte alta y baja de un entero, mientas que los de la primera fila son más avanzados y se verán a continuación.

3.3.2. Otras transformaciones

En la figura 3-26 pueden verse las funciones Flatten To String y Unflatten From String.

La primera, Flatten To String (traducido como aplanar), es una función que convierte todo el bloque de memoria que ocupa el dato en un string. Se puede elegir que la información estructural también se tenga en cuenta con el terminal prepend array or string size? y el formato de los datos con byte order (bigendian, little-endian y el nativo de la plataforma). La entrada anything puede ser cualquier tipo de datos.

Unflatten From String realiza el proceso inverso. En el menú contextual se puede indicar que manejen los datos como lo hacía LabVIEW en otras versiones.


Figura 3-26. Distintas funciones para manipulación de datos.

A diferencia de los variant, cuando se aplana un dato se pierde información sobre el tipo de datos origen, no tienen formato, por lo que al ‘des-aplanar’ es necesario indicar el tipo de datos destino.

Por ejemplo un array de números de 8 bits se almacena como una ‘cabecera’ consistente en un número de 32 bits que indica su longitud y tantos bytes como elementos tenga el array. Al aplanar este array, si no se indica nada en el terminal prepend array or string size?, se considera todo como parte de los datos resultando un string cuyo valor es el resultado de anexar la ‘cabecera’ y los datos e interpretarlo todo como un texto. Si este array fuese de dos elementos con los valores 1 y 2, el resultado es un string cuyo valor hexadecimal es «0000 0002 0102».

Algunas funciones realizan el aplanado de datos automáticamente. También puede ser necesario al trabajar con librerías externas.

3.3.3. Type Cast

Hay dos tipos de conversión: la coercion (implícita) y la cast (explícita). La primera la hace automáticamente el compilador. Para realizar la segunda hay que utilizar alguna instrucción. Antes se han visto varias para transformar de un tipo concreto a otro tipo también concreto. Type Cast es la función más genérica para transformar datos de un tipo a otro, y puede verse en la figura 3-27.

El terminal x es el dato a convertir y type el tipo al que será convertido. Por defecto, si no se conecta nada, lo considera string. Esta función no realiza ningún tipo de comprobación, así que al usarla hay que tener en cuenta que las entradas type y x sean compatibles, si no el resultado puede no ser el esperado.


Figura 3-27. Función type.

Por ejemplo, este VI podría sustituir a String To Byte Array si en el terminal type se conecta un array de enteros de ocho bits.

En el menú contextual también existe la opción de manejar los datos como se hacía en la versión 4 de LabVIEW, lo que afecta únicamente a los datos booleanos porque en esta versión los guardaba ocupando únicamente un bit y desde la versión 5 ocupan un byte completo.

3.4. Variables y propiedades

3.4.1. Variables locales

Para llevar un dato desde/hacia un control/indicador se han usado cables. A veces no se puede realizar el cableado, como en bucles que funcionan en paralelo, y otras veces sencillamente se quiere escribir en un control o leer de un indicador. Para todas estas situaciones sirven las variables locales.

Las variables locales están asociadas a los controles e indicadores presentes en el Panel Frontal de un VI, mediante ellas se puede leer y escribir el valor de ese control o indicador.

Para crear una variable local se puede ir a la paleta Programming > Structures > Local Variable y después asociar esa variable a uno de los controles o indicadores que existen mediante el menú contextual > Select Item (Figura 3-28).


Figura 3-28. Variables locales.

También pueden crearse directamente a partir del Terminal. Para ello, en el Diagrama de Bloques se despliega el menú contextual y se selecciona Create > Local Variable, de la forma que indica la figura 3-29.


Figura 3-29. Creación de variables locales desde el propio Terminal.

Una vez creada la variable, se puede indicar si se usará como lectura o escritura (por defecto es escritura) con Change To Read o Change To Write. Que la variable local sea de lectura o escritura es independiente de si el terminal es un control o un indicador, que es lo que permite escribir sobre un control y leer un indicador.

Las variables locales tienen un alcance que comprende al VI en el que está colocado el control o indicador al que hacen referencia. No pueden usarse fuera de ese VI.

Como conclusión, hay que decir que en general es preferible cablear las señales porque sigue el modelo de Dataflow. Las variables locales sólo deben usarse cuando sea necesario, porque pueden aparecer problemas de no inicialización de datos, condiciones de carrera, etc.

3.4.2. Variables globales

Las variables globales se usan para compartir información entre distintos VI que se ejecutan en la misma máquina. Lo podemos considerar como un espacio de memoria compartido por varios VI.

Pueden crearse también desde la paleta de estructuras, arrastrándolo al Diagrama de Bloques y haciendo doble clic, o también desde File > New… > Global Variable.


Figura 3-30. Creación de variables globales.

Conceptualmente son como un VI normal pero sin código. Una vez abierta la variable global, hay que colocar en su Panel Frontal un control o indicador del tipo que se desee. La información se almacenaría en este nuevo ‘VI sin Diagrama de Bloques’ y podría ser usada en los VI que hagan referencia a la variable. Para usar la variable global se aplica el mismo método que para cualquier subVI.

Si se añaden varios controles o indicadores a la variable global, podrá elegirse en concreto cuál quiere usar mediante el menú contextual eligiendo la opción Select Item. Al igual que con las variables locales, también debe indicarse si se va a leer o escribir.

Como se ha dicho antes, el alcance de una variable global llega a cualquier VI. Cuando se use en varios VI a la vez, hay que prestar atención porque pueden aparecerse problemas de condición de carrera. Para más información puede consultar el capítulo 10. Una forma de evitar estas situaciones es lo que se denomina ‘variable global funcional’, que consiste en ‘embeber’ la variable global en un subVI que, además del valor, también tiene una entrada para indicar la operación: lectura o escritura.

3.4.3. Variables compartidas

Las variables compartidas (Shared Variable) introducidas en la versión 8 de LabVIEW son una forma más genérica aún de compartir información. En este caso la comunicación puede ser entre programas que pueden estar en ordenadores distintos. También se suelen utilizar para comunicar dispositivos como un compactRIO o un FieldPoint con un PC.

Con las variables compartidas el traspaso de información entre los distintos programas es transparente para el programador, que no tiene que preocuparse por el protocolo de transmisión y otros detalles.

Para utilizar variables compartidas hay que crearlas dentro de una librería de un proyecto y, a través de su menú contextual, configurar sus propiedades.

Se estudiarán en la sección 9.2.2.

3.4.4. Nodos de propiedades y métodos

Los nodos de propiedades sirven principalmente para controlar el aspecto y el estado de un terminal del Panel Frontal de forma programada, es decir, desde el Diagrama de Bloques.

Todos los terminales llevan asociadas una serie de propiedades. Hay algunas comunes como visible o Position, otras varían dependiendo del tipo de terminal.

Para crear un nodo de propiedad puede hacerse de la misma forma que para una variable local: en la opción Create del menú contextual, como indica la figura 3-31. De esta forma, se crea un nodo de propiedad para ese terminal; para seleccionar la propiedad en concreto, se hará desde el menú contextual del nodo. Al igual que con las variables, se deberá elegir si son de lectura o escritura. El nodo puede expandirse y albergar otras propiedades. En este caso el orden de ejecución es de arriba hacia abajo.


Figura 3-31. Creación de un nodo de propiedad.

Hay cientos de propiedades, así que no se pueden explicar todas en este libro, pero en la ayuda contextual se ofrece una breve descripción de cada propiedad. Algunas de las más usadas son: Visible, Position, Disabled y Bounds. La propiedad Value sirve para leer y escribir el valor de un control, pero debe evitarse y sustituirse por una variable local (o mejor aún, un cable) cuando sea posible, pues los nodos de propiedad no son tan eficientes como una simple variable. Se verán las razones en la sección 14.4.3.7.

En el menú de la figura anterior también puede verse Invoke Node, que sirve para crear un nodo muy parecido al de propiedades, en este caso de métodos. Estos nodos no están relacionados con el aspecto, sino que efectúan alguna acción, como por ejemplo reiniciar a los valores por defecto.

Estos nodos también se pueden usar de forma genérica, es decir, que a priori no esté asociado a ningún Terminal. Para ello, debe usarse Programming > Application Control > Property Node. Después hay que cablear una referencia al terminal sobre el que actuará. Las referencias se crean igual que los nodos de propiedad o las variables locales.

En la figura 3-32 pueden verse dos controles booleanos a la izquierda: se trata de dos botones. En la esquina superior derecha se usa un nodo de propiedad para detener el parpadeo (Blinking) del primero de ellos. En el centro de la imagen se hace visible o se oculta uno de los dos botones, dependiendo de cuál se elija; este nodo es genérico, por lo tanto puede actuar sobre cualquiera de los dos botones a través de sus referencias. Finalmente, en la parte inferior se muestra un nodo de métodos, en este caso Get Image, que obtiene una imagen del botón; el VI al que está conectado es Draw Flattened Pixmap y simplemente lo dibuja.


Figura 3-32. Ejemplo del uso de nodos de propiedades y métodos.

3.4.5. Referencias

En la sección 3.2.8 se ha hablado de referencias junto con el tipo de datos refnum, que no debe confundirse con las referencias a terminales del Panel Frontal, que será lo que se estudie a continuación.

Se crean, igual que las variables locales y las propiedades, en el menú Create del menú contextual. Una vez creada, puede cambiarse el terminal al que está asociada desde el menú Link to. En la figura 3-31 puede verse en el menú cómo crear referencias, y en la figura 3-32 dos nodos de referencia de los controles Boolean y Boolean 2.

Como su nombre indica, sirven para hacer una referencia al terminal al que están asociados. Estas referencias se aplican principalmente a nodos de métodos o propiedades genéricos. Pueden servir para hacer que un nodo actúe sobre uno u otro Terminal, como se muestra en la figura 3-32, pero su mayor utilidad consiste en poder usar los nodos de propiedades y métodos asociados a un terminal desde un VI distinto al que están colocados. Las referencias no tienen alcance como las variables locales, pueden pasarse a otro VI como un parámetro más. El concepto sería similar al de pasar un parámetro como un puntero en lugar de por valor.

3.5. Ejemplos

3.5.1. Ejemplo I: varios métodos para convertir la representación ASCII a su valor

3.5.1.1. Explicación teórica

Este ejemplo se explica perfectamente con el título, no necesita más descripción, aquí simplemente se justifica el motivo de incluirlo: a muchos usuarios noveles que trabajan con interfaces como el bus serie RS-232 se les presenta el problema de que lo enviado y transmitido es un string; sin embargo, deben interpretarlo como números.

En principio se puede pensar en usar las funciones de Programming > String > String/Number Conversion, pero éstas no son válidas porque lo que convierten es un carácter numérico al número que representa o viceversa. No pueden convertir un carácter a su valor ASCII; por ejemplo, en un string el carácter «1» (cuyo valor ASCII en hexadecimal es el 31h) no se convertiría a su valor ASCII (31h = 49), sino en el 1. Para realizar la conversión que queremos (carácter «1» a número 49), hay que emplear otros métodos.

3.5.1.2. Código

Para realizar este programa ya se han explicado algunos métodos. Aquí se recopilan tres de ellos.

El primero es Type Cast. En el terminal type se debe conectar una señal del mismo tipo de la que se desea obtener a la salida, en este caso un array de enteros de ocho bits.

El segundo método es usar String To Byte Array. Ésta es una función diseñada expresamente para este problema.

El último método recopilado es usar Unflatten From String. Este método aprovecha que el dato de entrada es un string; sin embargo, para transformarse al array de enteros de salida necesitaría los 32 bits iniciales que indican la dimensión de esa dimensión del array. Como el string no lo tiene, se marcará en la entrada data includes array or string size? como FALSE.

El string mostrado en la figura 3-33 es «abcdef», cuyos valores van del 97 para la «a» hasta el 102 para la «f». Los resultados se muestran a la derecha de la imagen.


Figura 3-33. VI que pasa un ASCII a su valor.

3.5.2. Ejemplo II: Carrera de fórmula 1

3.5.2.1. Explicación teórica

El objetivo de este ejemplo será crear un sencillo simulador de carreras con tres coches. Los coches avanzarán en línea recta desde la salida hasta la meta. Cuando lleguen, el primero obtendrá una medalla de oro, el segundo de plata y el tercero de bronce.

Los coches están representados por unos indicadores booleanos numerados como «1», «2» y «3». De estos botones se crearán unos nodos de propiedad en los que se seleccionará Position > Left. Al escribir en este nodo un número, el control se desplazará hasta esa coordenada, así se simulará el avance.

El núcleo del programa consistirá en tres bucles en paralelo, uno por cada coche, que se estarán ejecutando hasta que el coche correspondiente llegue a meta (coordenada 600). En cada iteración del bucle aumentará el valor de la posición un valor aleatorio entre el 1 y el 4.

Cuando todos los coches lleguen a la meta se construirá un array con el tiempo que han tardado; este tiempo servirá para que el color del fondo de la etiqueta cambie a uno que represente una de las medallas. En esta ocasión se usará un nodo de propiedad genérico y se elegirá el control a colorear seleccionando su referencia.

3.5.2.2. Código

El código para este programa se puede ver en la figura 3-34.


Figura 3-34. Código del simulador de carreras.

El programa consiste en un SEQUENCE. En el primer frame se resetean los colores de las etiquetas y en el segundo se obtiene el tiempo en la salida; el tercer frame contiene tres bucles WHILE que hacen avanzar los controles. Cuando estos bucles acaban, también se obtiene el tiempo, que se restará del anterior para calcular el tiempo invertido en el recorrido. Con los tiempos de los tres controles se crea un array en el que se busca el menor valor que corresponderá con el primer control en acabar el recorrido; la referencia de ese control se pasará al nodo que cambia el color de la etiqueta a dorado. El valor en el array se sustituirá por infinito y se procederá de igual forma para obtener el segundo y el tercer clasificado.

3.5.2.3. Resultados

En la figura 3-35 se muestra una captura de una ejecución del programa. Los controles booleanos han sido personalizados como se vio en la sección 1.2.2 para que tengan el aspecto de un coche. El número que aparece sobre el capó es su etiqueta.


Figura 3-35. El coche n° 2 va en cabeza.

Los coches tienen una longitud de 117 píxeles y la pista de carreras 717 píxeles. Los coches recorrerán 600 píxeles desde la salida a la meta.

Este ejemplo muestra el uso que se puede hacer de las propiedades de los controles para cambiar el aspecto de los mismos de forma programada. Ésta es una herramienta muy útil para mejorar la interfaz con el usuario y darle cierto grado de interactividad.

3.6. Ejercicios

1. Realizar un programa que testee el tiempo necesario para leer y escribir un dato. Comprobar si es más eficiente una variable local, una global o la propiedad value.

2. ¿Qué ocurre si en el terminal type del Type Cast del ejemplo I se usa un array de enteros de 16 bits en lugar de enteros de 8? ¿Por qué?

3. Añadir al programa del ejemplo II una opción de foto-finish (pista: ver los métodos asociados al VI).

4. Construye un VI que acepte como parámetro de entrada un dato que pueda ser de tipo numérico, booleano, array o cluster y cuya salida sea un array de strings en el que cada elemento tenga el valor de cada componente del dato de entrada. Por ejemplo, si la entrada es un array de booleanos, la salida será un array de strings con los valores 0 o 1; si la entrada es un cluster de un dato numérico y un string, la salida será un array en el que el primer elemento sea el valor del dato numérico y el segundo el del string; si la entrada es un booleano o un numérico, el array de salida lógicamente sólo tendrá un elemento del mismo valor que la entrada (Ayuda: ver en el tema 4 las funciones sobre XML).

3.7. Bibliografía

Archana Shrotriya, AN 087: Writing Win32 Dynamic Link Libraries (DLL) and Calling Them from LabVIEW, National Instruments, 1996.

Jean Pierre Drolet y Jim Kring, LabVIEW Data, Data Types and Storage Formats, 2002.

National Instruments, AN 154: LabVIEW Data Storage.

National Instruments, AN 168: LabVIEW Performance and Memory Management, 2004.

Бесплатный фрагмент закончился.

720,18 ₽

Начислим

+22

Покупайте книги и получайте бонусы в Литрес, Читай-городе и Буквоеде.

Участвовать в бонусной программе

Жанры и теги

Возрастное ограничение:
0+
Объем:
813 стр. 672 иллюстрации
ISBN:
9788426718686
Издатель:
Правообладатель:
Bookwire
Формат скачивания:
Аудио
Средний рейтинг 4,1 на основе 1051 оценок
Аудио
Средний рейтинг 4,7 на основе 291 оценок
Аудио
Средний рейтинг 4,6 на основе 1089 оценок
Аудио
Средний рейтинг 3,7 на основе 39 оценок
Аудио
Средний рейтинг 3 на основе 22 оценок
Текст, доступен аудиоформат
Средний рейтинг 4,1 на основе 111 оценок
Текст
Средний рейтинг 3,9 на основе 589 оценок
Текст, доступен аудиоформат
Средний рейтинг 3,6 на основе 46 оценок
Черновик
Средний рейтинг 4,8 на основе 1017 оценок
Текст
Средний рейтинг 0 на основе 0 оценок