Archive for agosto, 2010

Tipos de datos I. Tipos de datos estándar.

En esta entrada repasare los tipos de datos en Codesys y el equivalente en vb.net.

Resumen de tipos de datos estándar.

Tipo de dato Codesys vb.net Limites Uso memoria
BOOL BOOL Boolean TRUE ò FALSE 1 bit
BYTE BYTE Byte 0 a 255 8 Bit
WORD WORD UShort 0 a 65535 16 Bit
DWORD UInteger 0 a 4294967295 32 Bit
Simple integer SINT Sbyte -128 a 127 8 Bit
Unsigned Simple Integer USINT Byte 0 a 255 8 Bit
Integer INT Short -32768 a 32767 16 Bit
Unsigned integer UINT UShort 0 a 65535 16 Bit
Double integer DINT Integer -2147483648 a 2147483647 32 Bit
UDINT UInteger 0 a 4294967295 32 Bit
REAL Single* -3.402823 E38 a 3.402823 E38 32 Bit
LREAL Double* -1.79769313486231E308 a 1.79769313486232E308 64 Bit
Cadena de caracteres STRING String* Nota 1
TIME Date* T#0ms a T#71582m47s295ms 32 Bit
TIME_OF_DAY Date* TOD#00:00 a TOD#1193:02:47.295 32 Bit
Fecha DATE Date* D#1970-01-01 D#2106-02-06 32 Bit
Fecha y hora DATE_AND_TIME Date* DT#1970-01-01-00:00 a DT#2106-02-06-06:28:15 32 Bit

*Estos tipos no tienen una equivalencia exacta.

NOTA 1: El tamaño por defecto es 80, para otro numero de caracteres se debe especificar en la declaración (str:STRING(35):=’Esto es una declaración String’;). Uso de memoria [BYTE] = Tamaño + 1 Byte para carácter nulo de terminación.

Todos son bit.

Entiendo que en un principio esto puede ser un poco confuso. Para mi la clave está en pensar que todo son bit y lo único que cambia es la forma de interpretar estos bit. Para muestra un botón. En la siguiente figura puedes ver tres tipos diferentes de variables (INT, UINT, TIME) direccionadas a la misma área de memoria y como se visualizan en función del tipo. También he declarado 16 variables del tipo BOOL y los he asignados a cada bit de VarINT.

No todos son bit.

TwinCat, cuando corre en PC guarda los datos boolean en Byte. Si no utilizamos las variables direccionadas (AT %MX) no nos importara pero hay que tenerlo en cuenta cuando se direccionan.

Variables STRING.

Las variables string almacenan en BYTE el código ascii equivalente al carácter en cuestión. En la siguiente imagen puedes ver dos variables, la variable VarVer es un ARRAY (Matriz o vector) de 11 elementos (0 a 10) de tipo BYTE. La variable VarStr es una variable string(10), ambas están direccionadas en el mismo área de memoria, por lo tanto lo que escribimos en una, lo podemos ver en la otra. Como puedes comprobar en la tabla del código ascii, cada BYTE almacena el código ascii equivalente. También podréis ver que el ultimo BYTE se reserva para el caracter NUL(0).

Código ASCII.

Los 32 primeros códigos pertenecen al grupo de los no imprimibles y son utilizados para enviar códigos como retorno de carro, fin de mensaje en protocolos de comunicación, etc.

Tipos de datos de tiempo.

Creo que merecen un post exclusivo que le dedicaré en breve.

F Psicrómetro

Un psicrómetro es un aparato utilizado en meteorología para medir la humedad o contenido de vapor de agua en el aire, distinto a los higrómetros corrientes. Los psicrómetros constan de un termómetro de bulbo húmedo y un termómetro de bulbo seco. La humedad puede medirse a partir de la diferencia de temperatura entre ambos aparatos. El húmedo medirá una temperatura inferior producida por la evaporación de agua. Es importante para su correcto funcionamiento que el psicrómetro se instale aislado de vientos fuertes y de la luz solar directa.

FUENTE: Wikipedia.

Pues igual que lo hacemos con termómetros de mercurio igual lo podemos hacer con sondas y un PLC. Esto nos sirve de excusa para introducir el uso de FB con tablas de datos. Algunos procesos no pueden ser calculados de forma directa y deben ser obtenidos a través de tablas de datos, como en este caso.

En este caso vamos a usar esta tabla para calcular la humedad en función de la temperatura del bulbo seco y la diferencia con el bulbo húmedo.


Y este es la función:


FUNCTION Psicometro : INT
VAR_INPUT
	TSeco :INT;
	THumedo :INT;
END_VAR
VAR
	Hr:INT;
	Dif_S_H: INT;
END_VAR
 
TSeco := TSeco / 10;
THumedo := THumedo / 10;
 
Dif_S_H := TSeco - THumedo;
 
(*Calculamos humedad en funcion de la parte entera*)
CASE TSeco OF
	5: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 85;			2: Psicometro := 71;			3: Psicometro := 59;			4: Psicometro := 48;			5: Psicometro := 39;
		6: Psicometro := 30;			7: Psicometro := 22;			8: Psicometro := 18;			9: Psicometro := 18;			10: Psicometro := 4;
	   END_CASE ;
	6: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 85;			2: Psicometro := 72;			3: Psicometro := 61;			4: Psicometro := 50;			5: Psicometro := 41;
		6: Psicometro := 33;			7: Psicometro := 25;			8: Psicometro := 21;			9: Psicometro := 20;			10: Psicometro := 7;
	   END_CASE ;
	7: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 86;			2: Psicometro := 73;			3: Psicometro := 62;			4: Psicometro := 52;			5: Psicometro := 43;
		6: Psicometro := 35;			7: Psicometro := 28;			8: Psicometro := 24;			9: Psicometro := 23;			10: Psicometro :=10;
	   END_CASE ;
	8: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 86;			2: Psicometro := 74;			3: Psicometro := 63;			4: Psicometro := 54;			5: Psicometro := 45;
		6: Psicometro := 37;			7: Psicometro := 30;			8: Psicometro := 26;			9: Psicometro := 25;			10: Psicometro := 13;
	   END_CASE ;
	9: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 86;			2: Psicometro := 75;			3: Psicometro := 65;			4: Psicometro := 55;			5: Psicometro := 47;
		6: Psicometro := 39;			7: Psicometro := 32;			8: Psicometro := 28;			9: Psicometro := 27;			10: Psicometro := 16;
	   END_CASE;
	10: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 87;			2: Psicometro := 76;			3: Psicometro := 66;			4: Psicometro := 57;			5: Psicometro := 48;
		6: Psicometro := 41;			7: Psicometro := 34;			8: Psicometro := 30;			9: Psicometro := 29;			10: Psicometro := 18;
	    END_CASE;
	11: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 88;			2: Psicometro := 77;			3: Psicometro := 67;			4: Psicometro := 58;			5: Psicometro := 50;
		6: Psicometro := 43;			7: Psicometro := 36;			8: Psicometro := 32;			9: Psicometro := 31;			10: Psicometro := 20;
	    END_CASE;
	12: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 88;			2: Psicometro := 78;			3: Psicometro := 68;			4: Psicometro := 59;			5: Psicometro := 52;
		6: Psicometro := 44;			7: Psicometro := 38;			8: Psicometro := 34;			9: Psicometro := 33;			10: Psicometro :=22;
	    END_CASE;
	13: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 89;			2: Psicometro := 78;			3: Psicometro := 69;			4: Psicometro := 61;			5: Psicometro := 53;
		6: Psicometro := 46;			7: Psicometro := 40;			8: Psicometro := 36;			9: Psicometro := 34;			10: Psicometro :=25;
	    END_CASE;
	14: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 89;			2: Psicometro := 79;			3: Psicometro := 70;			4: Psicometro := 62;			5: Psicometro := 54;
		6: Psicometro := 47;			7: Psicometro := 41;			8: Psicometro := 37;			9: Psicometro := 36;			10: Psicometro :=26;
	    END_CASE;
	15: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 89;			2: Psicometro := 80;			3: Psicometro := 71;			4: Psicometro := 63;			5: Psicometro := 55;
		6: Psicometro := 49;			7: Psicometro := 43;			8: Psicometro := 39;			9: Psicometro := 37;			10: Psicometro :=28;
	    END_CASE;
	16: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 90;			2: Psicometro := 80;			3: Psicometro := 72;			4: Psicometro := 64;			5: Psicometro := 57;
		6: Psicometro := 50;			7: Psicometro := 44;			8: Psicometro := 40;			9: Psicometro := 39;			10: Psicometro := 30;
	    END_CASE;
	17: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 90;			2: Psicometro := 81;			3: Psicometro := 72;			4: Psicometro := 65;			5: Psicometro := 58;
		6: Psicometro := 52;			7: Psicometro := 46;			8: Psicometro := 42;			9: Psicometro := 40;			10: Psicometro :=31;
	    END_CASE;
	18: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 90;			2: Psicometro := 81;			3: Psicometro := 73;			4: Psicometro := 66;			5: Psicometro := 59;
		6: Psicometro := 53;			7: Psicometro := 47;			8: Psicometro := 43;			9: Psicometro := 41;			10: Psicometro :=33;
	    END_CASE;
	19: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 91;			2: Psicometro := 82;			3: Psicometro := 74;			4: Psicometro := 66;			5: Psicometro := 60;
		6: Psicometro := 54;			7: Psicometro := 48;			8: Psicometro := 44;			9: Psicometro := 42;			10: Psicometro :=34;
	    END_CASE;
	20: CASE Dif_S_H OF
		0: Psicometro := 100;			1: Psicometro := 91;			2: Psicometro := 82;			3: Psicometro := 74;			4: Psicometro := 67;			5: Psicometro := 61;
		6: Psicometro := 55;			7: Psicometro := 49;			8: Psicometro := 46;			9: Psicometro := 43;			10: Psicometro :=36;
	   END_CASE;
 
ELSE
		Psicometro := 0;
END_CASE;

Mediante las dos primeras instrucciones dejamos la parte entera. El Fb esta hecho para temperatura en ºC x 10, por lo tanto el ultimo dígito es el decimal que quitaremos puesto que la tabla solo contempla valores enteros.  La variable Dif_S_H almacena la diferencia entre los dos termómetros.

Lo siguiente es la primera instrucción Case mediante la cual seleccionamos la temperatura de bulbo seco, de aquí pasara a la siguiente función Case donde asignara un valor de humedad en función de la diferencia (Dif_S_H).

No se si esto puede tener una aplicación practica. Quizás sea mas interesante hacerlo en Vb.net con un par de sondas de temperatura 1 wire y un pequeño ventilador. (Me lo apunto para hacerlo un día que tenga tiempo).


Break Point en Plc Control.

En el anterior post, comprobando registros, hice un pequeño programa que controlaba una gran cantidad de registros. Poco código para mucho trabajo. Pero todo tiene sus inconvenientes. Uno de los problemas, sin duda es la depuración, puesto que el tiempo para comprobar un registro es el del ciclo de scan. Para mí, esto de la programación de PLC navega hacia la programación informática, o dicho de otra forma, cada vez se parece más. Bien pues uno de los recursos de depuración al que habremos de acostumbrarnos son los Break Point. Esto no es nada más que detener el programa en un punto determinado para, por ejemplo, comprobar el estado de las variables.

El anterior post lo he editado, la razón es que al revisar los manuales me di cuenta que las estructuras tienen la limitación de que no pueden ser direccionadas (AT %MW). Me sorprende que te permita hacerlo y no de error al compilar, pero en fin esto es lo que hay. Lo que está claro es que si dice que no se puede es mejor no hacerlo puesto que esto al final tendrá sus consecuencias. En un próximo post pondré el programa modificado.

Online in security mode.

Una de las cosas que recomiendo al que quiera trabajar con Plc Control es trabajar en modo seguro en línea. Para esto debemos ir a Project —- > Option — > Desktop y marcar la casilla Online in Security mode. De esta manera siempre nos pedirá una confirmación de la orden. Si marcamos un BreakPoint nos preguntara si realmente queremos hacerlo, al forzar un valor, etc.

Break Point.

Para detener un programa en un punto determinado solo tendremos que pinchar en la línea de programa deseado:

Una vez puesto el BreakPoint, se marca la línea en azul, el programa no se detendrá hasta que llegue a ese punto. Si esta dentro de una condición como IF, el programa continuara hasta que se cumpla la condición. Esto también nos permite saber si se cumple esta condición. Cuando el programa se detiene la línea se marca en rojo.

En la barra de estados nos aparece BP marcado en rojo. Esto es importante. Si esta marcado, cuando reiniciemos el programa, se volverá a parar y si esta desmarcado continuara normalmente. Para reiniciar el programa simplemente pulsamos en Run.

Es importante tener presente que cuando el programa se detiene en un Break Point, no se refrescan las entradas salidas, de esta manera, si una salida estaba activa, continuara activa mientras el programa este parado. Como se entenderá esto puede provocar daños considerables si se utiliza mal.

Step over.

Pasó a paso por instrucción. Una vez detenido el programa en un Break Point podemos continuar pulsando en Run o podemos hacerlos paso a paso por instrucción (el icono con dos zapatos). Esto nos permite avanzar línea a línea comprobando el programa.

Control de registros I.

Bueno, aquí estamos de nuevo, he tenido que aplicarme en terminar algunas cosas que tenía pendiente y que ya no podían esperar más. Como comprenderéis uno tiene que seguir estudiando, probando, etc. Y en ocasiones le faltan horas al día. Pensé en que me llevaría poco tiempo pero no ha sido asi. En fin vamos al grano.

He preparado una pequeña aplicación para controlar registros, en mi caso, control de temperaturas, pero igual valdría para presiones, humedad, co2, etc. La idea es comprobar que estos registros se mantengan dentro de unos márgenes, si se salen se activará una prealarma y si superan un tiempo preestablecido se activa una salida, que por ejemplo podría enviar un mail, un sms o encender una sirena.

El proyecto consta de dos partes, una aplicación para PLC y otra para PC, donde monitorizamos estos registros. Aunque parece una aplicación sencilla, he querido mostrarla en el blog ya que con apenas unas líneas de código podremos controlar una gran cantidad de registros. Además será muy sencillo variar el número de registros.

Para empezar creamos una estructura que contendrá las variables de cada registro.

Y el paso siguiente es crear una matriz con esta estructura en variables globales:

La he direccionado con %MW3000 para posteriormente leer estos registros desde vb.net. Esto no es necesario ya que existe la posibilidad de leer las variables por nombre desde vb.net. Pero como esto es un “laboratorio de pruebas”, pues pruebas.

El siguiente paso es el programa claro:

En esta primera parte del programa he creado una pequeña rutina para rellenar las variables con valores inciales:

Y este es el programa propiamente dicho:

Cada ciclo de scan revisamos un registro, si el selector esta a TRUE, comprobamos que el .Valor este dentro de rango. Esto es mayor que .Mínimo y menor que .Máximo. En caso de estar fuera de rango restamos uno al valor de la variable .Retardo. Si está a TRUE la variable Restar. Si el selector esta a FALSE forzamos el valor de las variables. Prealarma y .Alarma a FALSE y .Retardo a SpRetardo (Set Point retardo o Punto de Ajuste retardo).

Como decíamos antes, este programa está diseñado para enviar SMS. Por este motivo las alarmas se activan en secuencia. De esta manera, hasta que la variable Out no esté a FALSE no se activará la siguiente alarma. Si se producen dos alarmas consecutivas debemos enviar el primer SMS y cuando termine el siguiente.

Para modificar el número de registros a comprobar, sólo tendremos que modificar la constante NReg en el programa MAIN y el tamaño de la Matriz Reg1 en variables globales.

En las próximas entradas veremos la aplicación en vb.net y una simulación para hacer las pruebas.

EDITADO 7.08.10.

Pues hay que leer los manuales. A pesar de que el programa se compila sin error en el manual dice esto:

Así que haremos caso del manual y modificare el programa para solucionar este inconveniente.