4 de mayo de 2017

Una función de bloque (FB) para el registro de datos en PLC Siemens

En la entrada anterior expliqué cómo dibujar una gráfica en HMI con los datos almacenados en un bloque de datos (DB) en un PLC. Ahora voy a centrarme en la captura de datos en el propio PLC y para ello he desarrollado una función de bloque que recoge todo el proceso de captura.

Realizar la captura de datos de un proceso puede resultar un tema complejo ya que debemos tener en cuenta todos los factores en juego, tales como la velocidad de adquisición o la capacidad de almacenamiento disponible. La forma óptima y con la que obtendremos el mejor rendimiento es usar bloques de organización (OB) de interrupción por tiempo "Cyclic interrupt", en los que a intervalos regulares se leen las señales a analizar. En los nuevos PLC de la gama 1500 de Siemens he visto que se pueden programar OB de interrupción por tiempo con periodos de 500 μs en adelante.

En los veteranos S7-300 estos OB tienen un periodo de interrupción más largo, pueden empezar, según modelo, en el rango de 100 o 200 ms en adelante.

Sin embargo esta no es la estrategia que voy a seguir en este ejemplo, ya que el FB que he programado se llamará en el ciclo principal del PLC. Por tanto lo primero de lo que debemos asegurarnos es que el tiempo de ciclo de nuestro programa es suficiente para registrar los datos del sistema. Por ejemplo si tenemos una señal analógica proveniente de una célula de carga cuyo conversor analógico/digital tiene un tiempo de actualización de 100 ms y el tiempo de ciclo de nuestro PLC es de unos 15 ms, entonces no habrá problemas con la captura de datos.

NOTA: es importante señalar que el tiempo de ciclo de un PLC no es un valor constante y depende de la carga de programa en cada ciclo. Por lo general será suficiente asegurarse de que, mientras esté la captura de datos en marcha, no se requieran tareas pesadas al PLC tales como bucles FOR o WHILE largos.

Otro elemento a tener en cuenta es la cantidad máxima de datos a almacenar. Mi objetivo es la representación de los datos en una gráfica en un panel de Siemens y el número máximo de elementos que puede tener una tabla para ser enlazada desde el panel al PLC es de 1600 valores. Si se toma un dato en cada ciclo de scan del PLC las tablas de datos se llenan en pocos segundos, así que es necesario discriminar los datos a guardar cada cierto intervalo o el máximo valor de cada intervalo, por ejemplo.

Teniendo todo esto en cuenta he preparado un FB que utilizo cuando tengo que hacer un registro de datos. Una llamada a dicho FB tiene el siguiente aspecto:


El funcionamiento es el siguiente: cuando la señal de habilitación está activa y la Señal X se encuentra entre el Valor mínimo (X) y Valor máximo (X) se procede a la captura de datos, indicado con la salida Capturando. Cada vez que la Señal X se incremente en un Paso mínimo (X) se almacenará un nuevo dato en la tabla, salvo que esté activada la opción Guardar máximos (Y), en cuyo caso el valor que se guardará será el máximo para la Señal Y dentro del intervalo definido por el Paso mínimo (X). Una vez finalizada la captura de datos, bien porque la Señal X haya salido de la ventana de valores mínimo y máximo o porque haya caído la señal de habilitación, se activará la salida Listo durante el tiempo especificado en Tiempo pulso fin lectura. El número de puntos almacenados en las tablas lo tenemos en la salida Puntos y si se alcanza el límite de datos posible se activa la señal Desbordamiento. Para repetir una captura de datos será necesario dar un pulso a la señal de Reinicialización antes de volver a habilitar la captura.

Los datos se almacenan en tablas que deberemos crear en un bloque de datos (DB) aparte y deberán tener el formato Array[0..1599] of Real. Se pasan al FB como parámetros InOut, y al ser un tipo de datos estructurado se pasan como puntero, con lo que no se desperdicia memoria duplicando las tablas, tal y como viene explicado en la documentación:
Declare los tipos de datos estructurados en el área "InOut". Siempre que sea posible, para variables estructuradas (p. ej. del tipo de datos ARRAY, STRUCT, STRING, …) debe utilizarse el área "InOut" en la interfaz del bloque. Puesto que los parámetros de entrada/salida estructurados (InOut) se transfieren como estándar en forma de puntero, de este modo no aumenta innecesariamente la memoria de datos necesaria.

El FB está programado en lenguaje SCL en TIA Portal V14 y el código sería el siguiente:

FUNCTION_BLOCK "Captura de datos"
TITLE = Registro de datos
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      "Señal X" : Real := 0.0;   // Señal para el eje X
      "Señal Y" : Real := 0.0;   // Señal para el eje Y
      Habilitación : Bool := false;   // Habilitación par ala captura de datos
      "Paso mínimo (X)" : Real := 0.0;   // Paso mínimo en el eje X para guardar un nuevo punto
      "Guardar máximos (Y)" : Bool := false;   // 1 - Dentro de cada tramo se guarda el valor máximo registrado / 0 - Se guarda el último valor del tramo
      "Valor mínimo (X)" : Real := 0.0;   // Para que se registren datos la señal X debe ser mayor a este valor
      "Valor máximo (X)" : Real := 0.0;   // Para que se registren datos la señal X debe ser menor a este valor
      Reinicialización : Bool := false;   // Reinicialización de los datos
      "Tiempo pulso fin captura" : Time := t#1s;   // Tiempo que dura el pulso de datos listos al finalizar una captura
   END_VAR

   VAR_OUTPUT
      Capturando : Bool;   // Captura de datos en proceso
      Listo : Bool;   // Captura de datos lista
      Puntos : Int;   // Nº de puntos capturados
      Desbordamiento : Bool;   // Las tabla de datos se han llenado (pérdida de datos)
   END_VAR

   VAR_IN_OUT
      "Datos X" : Array[0..1599] of Real;   // Tabla para almacenar los datos de la señal X
      "Datos Y" : Array[0..1599] of Real;   // Tabla para almacenar los datos de la señal Y
   END_VAR

   VAR
      "Tiempo listo" {OriginalPartName := 'IEC_TIMER'; LibVersion := '1.0'} : TON_TIME;
      "FN capturando" {OriginalPartName := 'F_TRIG_1500'; LibVersion := '1.0'} : F_TRIG;
      "Aux. Capturando" : Bool := false;
      "Aux. Listo" : Bool := false;
      "Aux. Puntos" : Int := 0;
   END_VAR

   VAR_TEMP
      Index : Int;
   END_VAR

   VAR CONSTANT
      "Nº puntos máximo" : Int := 1600;   // Número máximo de elementos en las tablas de datos (máx. 1600)
   END_VAR


BEGIN
    //=============================================================================
    // Notas de automatización - notasdeautomatizacion.blogspot.com 2017
    //-----------------------------------------------------------------------------
    // Herramienta de ingeniería: TIA Portal 14
    // Funcionalidad: Capturar dos señales (X,Y) para representarlas en HMI
    //-----------------------------------------------------------------------------
    // Registro de cambios:
    // 01.00.00 04.04.2017 Primera versión - GR
    //=============================================================================
  
    REGION Reinicialización de datos
       IF #Reinicialización THEN
          FOR #Index := 0 TO #"Nº puntos máximo" - 1 DO
             #"Datos X"[#Index] := real#0.0;
             #"Datos Y"[#Index] := real#0.0;
          END_FOR;
          #Puntos := #"Aux. Puntos" := 0;
          #Capturando := #"Aux. Capturando" := false;
          #Listo := #"Aux. Listo" := false;
          #Desbordamiento := false;
          RETURN;
       END_IF;
    END_REGION
  
    REGION Captura de datos
       IF #Habilitación AND
          #"Señal X" >= #"Valor mínimo (X)"AND #"Señal X"<= #"Valor máximo (X)" AND
          #"Aux. Puntos" >= 0 AND #"Aux. Puntos" < #"Nº puntos máximo" THEN
        
          #"Aux. Capturando" := true;
        
          IF #"Aux. Puntos" = 0 THEN
             #"Datos X"[0] := #"Señal X";
             #"Datos Y"[0] := #"Señal Y";
             #"Aux. Puntos" := 1;
          ELSE
             IF #"Señal Y" > #"Datos Y"[#"Aux. Puntos"] OR NOT #"Guardar máximos (Y)" THEN
                #"Datos X"[#"Aux. Puntos"] := #"Señal X";
                #"Datos Y"[#"Aux. Puntos"] := #"Señal Y";
             END_IF;
           
             IF #"Señal X" >= #"Datos X"[#"Aux. Puntos" - 1] + #"Paso mínimo (X)" THEN
                #"Aux. Puntos" += 1;
             END_IF;
          END_IF;
       ELSE
          #"Aux. Capturando" := false;
       END_IF;
    END_REGION
  
    REGION Salidas
       #"FN capturando"(CLK := #"Aux. Capturando");
       IF #"FN capturando".Q THEN
          #"Aux. Listo" := true;
       END_IF;
     
       #"Tiempo listo"(IN := #"Aux. Listo", PT := #"Tiempo pulso fin captura");
       IF #"Tiempo listo".Q THEN
          #"Aux. Listo" := false;
       END_IF;
     
       #Capturando := #"Aux. Capturando";
       #Listo := #"Aux. Listo";
       #Puntos := #"Aux. Puntos";
     
       IF #"Aux. Puntos" >= #"Nº puntos máximo" THEN
          #Desbordamiento := true;
       END_IF;
    END_REGION
  
END_FUNCTION_BLOCK

ADVERTENCIA: Si quisieramos usar este código en versiones anteriores de TIA Portal habría que adaptarlo eliminado las regiones, las asignaciones múltiples y el operador de incremento, que son novedades en TIA Portal V14.

Al proyecto que preparé en la entrada anterior le he añadido este FB y un código de prueba donde uso como "Señal X" un temporizador y como "Señal Y" una función seno de la "Señal X", de forma que puedo hacer pruebas desde el panel:

Pantalla para simular una captura de datos y probar el FB

Resultado de la prueba en un panel real

Espero que esto le pueda resultar útil a alguien y como siempre agradeceré comentarios.

4 comentarios:

  1. Hola, me alegro que hagas nuevas publicaciones, yo he estado siguiendo varias de ellas y me han ayudado mucho. Gracia por utilizar tu tiempo para ayudar a los demás.



    ResponderEliminar
  2. Las publicaciones a mi me han sacado de algún apuro la verdad... siempre intererantes y van directas al tema.

    ResponderEliminar
  3. Muy bueno, como lo adapto y que me quede bien en TIA 13 o Tia 12 ? Vas a dejar descarga de este proyecto ?

    ResponderEliminar

Por favor, no pidas copias de programas comerciales, licencias o números de serie.