21 de junio de 2010

Temporización en Step7 sin usar temporizadores SIMATIC

El número de temporizadores SIMATIC que tenemos disponibles programando en Step7 está limitado, depende de cada modelo de PLC. Por ejemplo, para un 312C tenemos 128 temporizadores, para un 313C-2DP son 256, etc. Esto es suficiente para la mayoría de las aplicaciones, pero puede ocurrir que necesitemos más. Como solución existen varias alternativas. Una sería usar temporizadores según la norma IEC, que en Step7 vienen implementados como funciones del sistema integradas (SFB). Dicha norma define dos tipos de temporizadores, TON y TOF, que no son más que un retardo a la conexión (SFB4) y retardo a la desconexión (SFB5), respectivamente. Para utilizarlos los tenemos disponibles en la biblioteca 'Standard library', bajo 'System Function Blocks'. Podemos usar tantos como queramos, pero teniendo en cuenta que para cada temporizador será necesario declarar un bloque de datos (DB) de instancia, lo cual ocupa memoria (58 bytes por cada temporizador exactamente).


Estos temporizadores no usan el formato de tiempo S5TIME propio de Step7, sino que usan el formato TIME según la norma IEC. Este formato no es más que un entero doble con signo (32 bits) donde se almacena el tiempo en milisegundos. Para saber más sobre su funcionamiento, en la ayuda de Step7 vienen perfectamente documentados.

Pero existe otra opción para realizar temporizaciones. En Step7 tenemos la función del sistema SFC64 TIME_TCK (time tick), con la que se puede leer el cronómetro del sistema de la CPU. Esto nos da la opción de construir nuestro propio temporizador a medida y es lo que voy a hacer a continuación.

La función del sistema SFC64 está disponible en la misma biblioteca que los temporizadores TON y TOF. Al llamarla nos devolverá, en formato TIME, el cronómetro del sistema, que no es más que el número de milisegundos que han transcurrido desde que el PLC ha pasado a modo RUN.

Mi temporizador lo voy a controlar con cuatro parámetros de entrada:
  • HABILIT, booleano de habilitación que servirá para activar la temporización.
  • PAUSA, booleano que permitirá pausar el tiempo mientras esté activada la temporización (igual a lo que hice en la entrada anterior con un temporizador SIMATIC).
  • REINIC, booleano que permitirá reinicializar la temporización.
  • TIEMPO, en formato TIME que será el tiempo de temporización.
Como señales de salida, nuestro temporizador nos devolverá tres parámetros:
  • TEMPORIZANDO, booleano que nos indicará que la temporización está en marcha.
  • FIN, booleano que señalará que la temporización ha finalizado.
  • T_RESTANTE, en formato TIME nos irá informando del tiempo que falta para terminar la temporización.
El funcionamiento deseado del temporizador es de retardo a la conexión, que es el tipo que, en la práctica, uso en el 90% de las ocasiones. En detalle, se puede apreciar como funciona en el siguiente ciclograma:



Actualización: también tienes el código del temporizador en este proyecto de Step7.

La programación del temporizador está hecha en un bloque de función (FB) que necesitará un bloque de datos (DB) de instancia asociado. En las siguientes capturas se puede ver la parametrización del interface de entrada (IN), salida (OUT), status (STAT) y temporal (TEMP):





En la siguiente captura está la programación en diagrama de contactos (KOP) del FB de temporización, está comentado y creo que se entiende bastante bien:


Con esto sería suficiente, pero los temporizadores son código que se usa frecuentemente y es preferible que esté lo más optimizado posible, así que lo he traducido a lista de instrucciones (AWL). Aprovechando que el lenguaje AWL es menos restrictivo con los tipos de datos he suprimido algunas variables auxiliares requiriendo, por tanto, menos memoria. El interface de entrada (IN) y salida (OUT) es idéntico a la programación en KOP, no así el de status (STAT) y el temporal (TEMP), que se han simplificado:



El código optimizado en AWL es el siguiente:
CALL "TIME_TCK" // LECTURA DEL CRONÓMETRO DEL SISTEMA
RET_VAL:=#TIME_MS

U #HABILIT // AL INICIAR EL TEMPORIZADOR Y AL RESETEAR
FP #FP1 // SE CALCULA EL TIEMPO DE FINALIZACIÓN
O #REINIC // Y SE CARGA EL TIEMPO TOTAL
SPBN SLT1 // EN EL TIEMPO RESTANTE
L #TIME_MS
L #TIEMPO
+D
T #T_FINAL
L #TIEMPO
T #T_RESTANTE

SLT1: U #HABILIT // SI HAY SEÑAL DE HABILITACIÓN,
UN #PAUSA // NO SE ESTÁ EN PAUSA,
UN #FIN // NO HA FINALIZADO LA TEMPORIZACIÓN Y
UN #REINIC // NO SE ESTÁ REINICIANDO,
= #TEMPORIZANDO // SE ESTÁ TEMPORIZANDO

U #TEMPORIZANDO // SI SE ESTÁ TEMPORIZANDO Y
U( // SE HA COMPLETADO EL TIEMPO
L #T_FINAL // HA FINALIZADO LA TEMPORIZACIÓN
L #TIME_MS
<=D
)
S #FIN

ON #HABILIT // SI NO HAY HABILITACIÓN O
O #REINIC // SI SE ESTÁ REINICIALIZANDO
R #FIN // SE QUITA LA SEÑAL DE FIN DE TEMPORIZACIÓN

U #HABILIT // SI ESTANDO HABILITADO EL TEMPORIZADOR Y
U #PAUSA // AL ENTRAR EN PAUSA
FP #FP2 // Y SI NO HA FINALIZADO LA TEMPORIZACIÓN
UN #FIN // SE GUARDA EL TIEMPO RESTANTE
SPBN SLT2
L #T_FINAL
L #TIME_MS
-D
T #T_RESTANTE

SLT2: U #HABILIT // SI HAY HABILITACIÓN
U #PAUSA // Y PAUSA
UN #FIN // Y NO HA FINALIZADO LA TEMPORIZACIÓN
SPBN SLT3 // SE RECALCULA EL TIEMPO FINAL DE TEMPORIZACIÓN
L #TIME_MS
L #T_RESTANTE
+D
T #T_FINAL

SLT3: UN #HABILIT // SI NO HAY HABILITACIÓN O
O #FIN // SI HA FINALIZADO LA TEMPORIZACIÓN,
SPBN SLT4 // EL TIEMPO RESTANTE DE TEMPORIZACIÓN
L 0 // SE PONE A CERO
T #T_RESTANTE

SLT4: U #TEMPORIZANDO // SI SE ESTÁ TEMPORIZANDO
SPBN SLT5 // SE CALCULA EL TIEMPO QUE FALTA
L #T_FINAL // PARA TERMINAR
L #TIME_MS
-D
T #T_RESTANTE

SLT5: NOP 0

En la siguiente captura de pantalla se ve el temporizador en ejecución:


Para finalizar y como curiosidad, el DB de instancia necesario en mi temporizador ocupa 54 bytes, frente a los 58 de los temporizadores IEC. Simplificando el funcionamiento de mi temporizador podría reducirse el tamaño del BD de instancia, lo cual podría ser interesante en el caso de que necesitemos ahorrar memoria.


A pesar de todo lo visto en esta entrada, pienso que es preferible usar los temporizadores SIMATIC, no consumen memoria con DB de instancia y sospecho que requieren menos recursos del PLC.

Si alguien mejora el código, realiza otro tipo de temporizador a partir de este o encuentra algún fallo, le agradecería que me lo comunicase.

3 comentarios:

  1. Aparte de esto se podrá realizar una programación por ejemplo: de 3 procesos similares, pero con diferentes variables y tenido considerado un temporizador por proceso, pero con los bloques DB y FB mas el OB lógicamente ocupar solo una dirección, como T0………T255

    ResponderEliminar
  2. Buen día, tu función está muy bien, salvo que cuando la cpu pasa a stop, la función se vuelve loca, la solución está en comprobar y recargar el tiempo restante cuando la SFC64 devuelve T#0ms o 1ms.

    Por otra parte el código se puede optimizar mucho más, el tema de crear un timer sin timer y no utilizar el ton o toff es el espacio de memoria que consume, y tu solución está bien, pero le sobra la pausa, el todas las salidas.

    Bueno, como supongo que es un ejemplo, está muy bien, pero solo como ejemplo, el la vida real es un poco peligroso este timer.

    Saludos. (No aporto solución porque no sé como añadirla en tu blog.)

    ResponderEliminar
    Respuestas
    1. Hola Amigo anónimo,

      si que el PLC pueda pasar a stop resulta problemático siempre tenemos los OB de fallo y arranque para solventar la situación.

      Usar Ton y Toff también requiere de DB de instancia con lo que la memoria consumida sería similar.

      El temporizador lo he diseñado en función de mis necesidades y la función de pausa es algo que en ocasiones me ha venido muy bien. Si consideras que se puede mejorar el código estaré encantado de echarle un vistazo y publicarlo en el blog (mi correo es: notasdeautomatizacion@gmail.com)

      Un saludo y gracias por tu comentario.

      Eliminar

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