Reorganizacion de libreria.

This commit is contained in:
2026-07-20 08:15:06 +02:00
parent e0b9f4a206
commit 2b9dbc1f27
280 changed files with 9799 additions and 9398 deletions
@@ -0,0 +1,219 @@
FUNCTION_BLOCK "FB15152_ZC_PARO_SEC"
TITLE = FB15152_ZC_PARO_SEC
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para la gestion de paro secuencial de dispositivos
VAR_INPUT
Pulso1Seg : Bool; // Pulso de 1 segundo
MarchaSecuenciaParo : Bool; // Orden marcha secuencia de paro
NumeroDispositivos { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Int := 4; // Numero de dispositivos
TiempoEntreEtapas { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Int := 2; // Tiempo entre etapas
ConfirmacionDisp { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Array[1..#N_MAX] of Bool; // Confirmacion activado dispositivo
END_VAR
VAR_OUTPUT
SecParoFinalizada : Bool; // Secuencia de paro completada
SecReposo : Bool; // Secuencia en reposo
ParoDispositivo { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Array[1..#N_MAX] of Bool; // Orden paro dispositivo
END_VAR
VAR
s_NumeroDispositivos { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int; // Numero de dispositivos
END_VAR
VAR RETAIN
s_EtapaActual { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int; // Etapa actual
s_Indice { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int; // Indice dispositivo actual
s_TiempoActual { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int; // Tiempo actual
END_VAR
VAR_TEMP
for_i : Int;
END_VAR
VAR CONSTANT
N_MAX : Int := 8;
REPOSO : Int := 0;
PARANDO : Int := 10;
REARMANDO : Int := 20;
FINALIZADO : Int := 30;
END_VAR
BEGIN
REGION DESCRIPCION
//=======================================================================
// (C)Copyright ZeusControl 2023 - 2026
//=======================================================================
(*
### Información del Sistema
| Hardware Compatible | Entorno de Ingeniería |
|---------------------|-----------------------|
| PLC serie 1200/1500 | TIA Portal 18 |
---
### Descripción Funcional
El bloque `FB15051_PARO_SECUENCIAL` implementa un secuenciador bidireccional para el paro ordenado de un array de dispositivos. Permite detener los dispositivos uno a uno esperando una confirmación por etapa, y rearmar la secuencia en sentido inverso si se retira la orden de marcha, continuando desde la última etapa alcanzada en lugar de reiniciar desde el inicio.
Funcionalidades principales:
- Validación del número de dispositivos: `#NumeroDispositivos` se acota entre 1 y la constante de dimensionamiento `#N_MAX`.
- Estado `REPOSO`: bloque en espera. Al recibir `#MarchaSecuenciaParo := TRUE` se inicializa el índice y se transita a la etapa `PARANDO`.
- Estado `PARANDO`: avanza secuencialmente por los dispositivos de menor a mayor índice. Cada dispositivo se considera parado cuando se cumple `#ConfirmacionDisp[i] = TRUE` durante `#TiempoEntreEtapas` segundos. Al confirmar, se incrementa el índice hasta superar `#s_NumeroDispositivos`, momento en el que se transita a `FINALIZADO`. Si durante esta etapa se desactiva `#MarchaSecuenciaParo`, se invierte el sentido y se pasa a `REARMANDO` sin perder la posición alcanzada.
- Estado `REARMANDO`: retrocede secuencialmente por los dispositivos de mayor a menor índice. Cada dispositivo se considera rearmado cuando `#ConfirmacionDisp[i] = FALSE` durante `#TiempoEntreEtapas` segundos. Al rearmar, se decrementa el índice hasta alcanzar 1, momento en el que se transita a `REPOSO`. Si durante esta etapa se vuelve a activar `#MarchaSecuenciaParo`, se invierte nuevamente el sentido y se pasa a `PARANDO` desde la posición actual.
- Estado `FINALIZADO`: secuencia de paro completa. Al retirar `#MarchaSecuenciaParo`, se rearman los dispositivos en orden inverso empezando desde el último, transitando a `REARMANDO`.
- Mapeado dinámico de salidas: para cada dispositivo se activa `#ParoDispositivo[i] := TRUE` si su índice es menor o igual al puntero actual y la etapa es `PARANDO`; en el resto de casos se mantiene en `FALSE`. Esto garantiza que los dispositivos ya parados en la fase actual permanezcan parados durante el rearmado inverso de los posteriores.
- Señales de estado: `#SecReposo` indica que la secuencia está en `REPOSO` y `#SecParoFinalizada` que ha terminado (`FINALIZADO`).
- Contadores de tiempo por etapa del tipo `ZC_TIEMPO_ETAPA` con base de tiempo en segundos (`#Pulso1Seg`).
> **Restricciones:** PLC serie 1200/1500.
---
### Dependencias Requeridas
| Tipo | Elementos |
|------|-----------|
| FC | - |
| FB | - |
| DB | - |
| UDT | `ZC_TIEMPO_ETAPA` |
---
### Historial de Cambios
| Versión | Fecha | Técnico | Cambios |
|----------|------------|---------|---------|
| 00.00.01 | 24.05.2023 | (ABH) | Primera versión. |
| 00.00.02 | 15.12.2023 | (HCR) | Se aumentan los dispositivos de 4 a 8. |
| 00.00.03 | 18.12.2023 | (ABH) | Se cambia UDT tiempo etapa a `ZC_TIEMPO_ETAPA`. Se añade salida `SecReposo` para indicar que está en reposo. Se añade gestión de etapas para que, en caso de estar con orden de paro y se dé marcha, siga la secuencia donde le toque evitando tener que pararla por completo y volverla a arrancar. |
| 01.00.00 | 03.07.2026 | (ABH) | Cambio a SCL. Se refactoriza logicas para estandarizar. Se utiliza constante N_MAX para redimensionar. |
*)
END_REGION DESCRIPCION
// ==========================================================================================================
REGION LIMITES
#s_NumeroDispositivos := #NumeroDispositivos;
// Limite de seguridad
IF #s_NumeroDispositivos > #N_MAX THEN
#s_NumeroDispositivos := #N_MAX;
ELSIF #s_NumeroDispositivos < 1 THEN
#s_NumeroDispositivos := 1;
END_IF;
END_REGION LIMITES
// ==========================================================================================================
REGION SECUENCIADOR_BIDIRECCIONAL
CASE #s_EtapaActual OF
#REPOSO:
#s_Indice := 1;
#s_TiempoActual := 0;
IF #MarchaSecuenciaParo THEN
#s_EtapaActual := #PARANDO;
END_IF;
#PARANDO:
// Contador de tiempo con confirmacion de dispositivo
IF #ConfirmacionDisp[#s_Indice] AND #Pulso1Seg THEN
#s_TiempoActual += 1;
END_IF;
// Tiempo cumplido
IF (#s_TiempoActual >= #TiempoEntreEtapas) THEN
#s_TiempoActual := 0;
#s_Indice += 1; // Avanzamos al siguiente dispositivo
// Comprobación de fin de secuencia de paro
IF #s_Indice > #s_NumeroDispositivos THEN
#s_EtapaActual := #FINALIZADO;
END_IF;
END_IF;
// Si se desactiva la orden de marcha de la secuencia, comenzamos el rearme inverso
IF NOT #MarchaSecuenciaParo THEN
#s_TiempoActual := 0;
#s_EtapaActual := #REARMANDO;
END_IF;
#REARMANDO:
// Límite de seguridad inferior
IF #s_Indice < 1 THEN
#s_EtapaActual := #REPOSO;
RETURN;
END_IF;
// Contador de tiempo sin confirmacion de dispositivo
IF NOT #ConfirmacionDisp[#s_Indice] AND #Pulso1Seg THEN
#s_TiempoActual += 1;
END_IF;
// Tiempo cumplido
IF (#s_TiempoActual >= #TiempoEntreEtapas) THEN
#s_TiempoActual := 0;
#s_Indice -= 1; // Avanzamos al dispositivo anterior
IF #s_Indice < 1 THEN
#s_EtapaActual := #REPOSO;
END_IF;
END_IF;
// Si se vuelve a dar marcha, invertimos dirección nuevamente
IF #MarchaSecuenciaParo THEN
#s_TiempoActual := 0;
#s_EtapaActual := #PARANDO;
END_IF;
#FINALIZADO:
IF NOT #MarchaSecuenciaParo THEN
#s_TiempoActual := 0;
// Empezamos a rearmar desde el último dispositivo que se paro
#s_Indice := #s_NumeroDispositivos;
#s_EtapaActual := #REARMANDO;
END_IF;
ELSE
#s_EtapaActual := #REPOSO;
END_CASE;
END_REGION SECUENCIADOR_BIDIRECCIONAL
// ==========================================================================================================
REGION MAPEADO_DINAMICO_DE_SALIDAS
#SecReposo := (#s_EtapaActual = #REPOSO);
#SecParoFinalizada := (#s_EtapaActual = #FINALIZADO);
// Mapeo vectorial de comandos físicos
FOR #for_i := 1 TO #N_MAX DO
// Si el índice iterativo es menor que nuestro puntero de etapa actual,
// significa que ya hemos pasado por él en la secuencia de paro y debe estar detenido.
IF #for_i < #s_Indice THEN
#ParoDispositivo[#for_i] := TRUE;
// Si el índice coincide con el puntero y estamos parando, forzamos la salida a TRUE
ELSIF (#for_i = #s_Indice) AND (#s_EtapaActual = #PARANDO) THEN
#ParoDispositivo[#for_i] := TRUE;
// Para el resto de condiciones
ELSE
#ParoDispositivo[#for_i] := FALSE;
END_IF;
END_FOR;
END_REGION MAPEADO_DINAMICO_DE_SALIDAS
END_FUNCTION_BLOCK
@@ -0,0 +1,216 @@
FUNCTION_BLOCK "FB15153_ZC_MARCHA_SEC_B_MEM"
TITLE = FB15153_ZC_MARCHA_SEC_B_MEM
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para la gestion de activacion de las bombas de de una maquina de membranas
VAR_INPUT
Pulso1Seg : Bool; // Pulso de 1 segundo
MarchaSecuencia : Bool; // Orden de marcha secuencia
EstadoBombaPresionVF : Bool; // Estado bomba Presion (Variador)
EstadoBombaPresion : Bool; // Estado bomba Presion
TiempoEntreBombas : Int := 10; // SP Tiempo entre bombas
NumeroBombasPresion : Int := 2; // Numero de bombas presion (1 o 2)
NumeroModulos : Int := 6; // Numero de modulos
END_VAR
VAR_OUTPUT
MarchaBombaPresionVF : Bool; // Activacion bomba Presion (Variador)
MarchaBombaPresion : Bool; // Activacion bomba Presion
MarchaBombaModulo : Array[1..#N_MAX] of Bool; // Activacion bomba Modulo
END_VAR
VAR RETAIN
s_TonPresion { S7_SetPoint := 'False'} : Array[1..2] of "UDT_ZC_DISP_TON";
s_TonModulos { S7_SetPoint := 'False'} : Array[1..#N_MAX] of "UDT_ZC_DISP_TON";
END_VAR
VAR_TEMP
for_i : Int;
t_NumBombasPresion : Int; // Numero de bombas presion
t_NumModulos : Int; // Numero de modulos
t_BombasPresionOk : Bool; // Bombas presion arrancadas Ok
END_VAR
VAR CONSTANT
N_MAX : Int := 6;
END_VAR
BEGIN
REGION DESCRIPCION
(*
###### (C)Copyright ZeusControl 2023 - 2026
---
### Información del Sistema
| Hardware Compatible | Entorno de Ingeniería |
|---------------------|-----------------------|
| PLC serie 1200/1500 | TIA Portal 18 |
---
> **Restricciones:** Ninguna.
---
### Descripción Funcional
Bloque de gestión de marcha secuencial de bombas de una máquina de membranas. Implementa el arranque escalonado, en cascada y temporizado, de las bombas de presión y de las bombas de los módulos de la máquina, respetando el número de bombas y módulos configurados y utilizando temporizadores individuales no retentivos.
Acciones detalladas:
- Limita el número de bombas de presión activas (`t_NumBombasPresion`) al rango válido `1``2`, acotando la entrada `NumeroBombasPresion`.
- Limita el número de módulos activos (`t_NumModulos`) al rango válido `1``N_MAX`, acotando la entrada `NumeroModulos`.
- Traslada el setpoint de temporización `TiempoEntreBombas` a todos los temporizadores de bombas de presión (`s_TonPresion[1..2]`) y de módulos (`s_TonModulos[1..N_MAX]`).
- Gestiona el arranque de las bombas de presión mediante dos temporizadores en cascada: primero la bomba de variador (`s_TonPresion[1]`) y, tras su confirmación y solo si hay 2 bombas configuradas, la segunda bomba de presión (`s_TonPresion[2]`).
- Calcula el flag `t_BombasPresionOk`, que indica que el conjunto de bombas de presión requerido está en marcha: con 1 bomba exige confirmación del variador, con 2 bombas exige confirmación de ambas.
- Arranca el módulo 1 (`s_TonModulos[1]`) directamente cuando las bombas de presión están OK.
- Arranca los módulos `2` a `N_MAX` en cascada, de forma que cada módulo espera a la confirmación del módulo anterior y a las bombas de presión OK; los módulos no configurados se fuerzan a `FALSE` por seguridad.
- Ejecuta los temporizadores llamando a la `FC` de temporización individual, lo que permite disponer de un `SP`, una `IN`, una salida `Q` y un tiempo transcurrido independientes por instancia.
- Genera las salidas finales: `MarchaBombaPresionVF` (variador), `MarchaBombaPresion` (segunda bomba) y `MarchaBombaModulo[1..N_MAX]` a partir de las salidas `Q` de los temporizadores correspondientes.
---
### Dependencias Requeridas
| Tipo | Elementos |
|------|-----------|
| FC | `FC2928_ZC_TON_INDV` |
| FB | - |
| DB | - |
| UDT | - |
---
### Historial de Cambios
| Versión | Fecha | Técnico | Cambios |
|----------|------------|---------|---------|
| 01.00.00 | 09.05.2023 | (ABH) | Primera version. |
| 01.00.01 | 19.05.2023 | (ABH) | Se añade parámetro de entrada para límite de número de bombas de presión. |
| 01.00.02 | 02.10.2023 | (ABH) | Se añade `FC22028_TON_INV` para gestión de temporizadores. |
| 01.00.03 | 02.11.2023 | (ABH) | Se añade gestión para 6 módulos. |
| 01.00.03 | 06.07.2026 | (ABH) | Cambio a SCL. Se refactoriza numero de modulos.|
*)
END_REGION DESCRIPCION
// ==========================================================================================================
REGION LIMITES
// Limite numero de bombas presion
#t_NumBombasPresion := #NumeroBombasPresion;
IF #t_NumBombasPresion < 1 THEN
#t_NumBombasPresion := 1;
END_IF;
IF #t_NumBombasPresion > 2 THEN
#t_NumBombasPresion := 2;
END_IF;
// Limite numero de bombas modulos
#t_NumModulos := #NumeroModulos;
IF #t_NumModulos < 1 THEN
#t_NumModulos := 1;
END_IF;
IF #t_NumModulos > #N_MAX THEN
#t_NumModulos := #N_MAX;
END_IF;
END_REGION LIMITES
// ==========================================================================================================
REGION TRASPASO_DE_PARAMETROS
// Traspaso de tiempos bomba presion
FOR #for_i := 1 TO 2 DO
#s_TonPresion[#for_i].SP := #TiempoEntreBombas;
END_FOR;
// Traspaso de tiempos bomba modulos
FOR #for_i := 1 TO #N_MAX DO
#s_TonModulos[#for_i].SP := #TiempoEntreBombas;
END_FOR;
END_REGION TRASPASO_DE_PARAMETROS
// ==========================================================================================================
REGION GESTION_BOMBAS_PRESION
// Temporizador bomba Presion (Variador)
#s_TonPresion[1].IN := #MarchaSecuencia;
// Temporizador bomba Presion
#s_TonPresion[2].IN :=
(#t_NumBombasPresion = 2) AND
#EstadoBombaPresionVF AND
#s_TonPresion[1].Q;
// Bombas presion arrancadas Ok
IF #t_NumBombasPresion = 1 THEN
#t_BombasPresionOk := #EstadoBombaPresionVF AND #s_TonPresion[1].Q;
ELSE
#t_BombasPresionOk := #EstadoBombaPresion AND #s_TonPresion[2].Q;
END_IF;
END_REGION GESTION_BOMBAS_PRESION
// ==========================================================================================================
REGION GESTION_BOMBAS_MODULOS
// El modulo 1 arranca directamente si las bombas de presion estan OK
#s_TonModulos[1].IN := #t_BombasPresionOk;
// Los modulos 2 a N_MAX arrancan en cascada
FOR #for_i := 2 TO #N_MAX DO
IF #for_i <= #t_NumModulos THEN
// Si el módulo está dentro de la configuración, evalúa la cascada (Módulo anterior Q + bombas presion Ok)
#s_TonModulos[#for_i].IN := #s_TonModulos[#for_i - 1].Q AND #t_BombasPresionOk;
ELSE
// Forzado de seguridad a FALSE para módulos no instalados/configurados en esta máquina
#s_TonModulos[#for_i].IN := FALSE;
END_IF;
END_FOR;
END_REGION GESTION_BOMBAS_MODULOS
// ==========================================================================================================
REGION GESTION_TEMPORIZADORES
// Temporizadores bombas presion
FOR #for_i := 1 TO 2 DO
"FC2928_ZC_TON_INDV"(Pulso1seg := #Pulso1Seg,
TON := #s_TonPresion[#for_i]);
END_FOR;
// Temporizadores bombas modulos
FOR #for_i := 1 TO #N_MAX DO
"FC2928_ZC_TON_INDV"(Pulso1seg := #Pulso1Seg,
TON := #s_TonModulos[#for_i]);
END_FOR;
END_REGION GESTION_TEMPORIZADORES
// ==========================================================================================================
REGION SALIDAS
// Bombas presion
#MarchaBombaPresionVF := #s_TonPresion[1].Q;
#MarchaBombaPresion := #s_TonPresion[2].Q;
// Bombas modulos
FOR #for_i := 1 TO #N_MAX DO
#MarchaBombaModulo[#for_i] := #s_TonModulos[#for_i].Q;
END_FOR;
END_REGION SALIDAS
END_FUNCTION_BLOCK
@@ -0,0 +1,403 @@
FUNCTION "FC15151_ZC_MARCHA_PARO_SEC" : Void
TITLE = FC15151_ZC_MARCHA_PARO_SEC
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Funcion para la gestion de marcha/paro de dispositivos secuencialmente
VAR_INPUT
Pulso1Seg : Bool; // Pulso de 1 segundo
Seguridad : Bool; // Estado seguridades ok
Marcha : Bool; // Orden de marcha
END_VAR
VAR_IN_OUT
MP_SEC : "UDT_ZC_MARCHA_PARO_SEC";
END_VAR
VAR CONSTANT
REPOSO : Int := 0;
MARCHA_1 : Int := 10;
MARCHA_2 : Int := 20;
MARCHA_3 : Int := 30;
MARCHA_4 : Int := 40;
MARCHA_5 : Int := 50;
MARCHA_6 : Int := 60;
MARCHA_7 : Int := 70;
MARCHA_8 : Int := 80;
END_VAR
BEGIN
REGION DESCRIPCION
(*
###### (C)Copyright ZeusControl 2023 - 2025
---
### Información del Sistema
| Hardware Compatible | Entorno de Ingeniería |
|---------------------|-----------------------|
| PLC serie 1200/1500 | TIA Portal 18 |
---
> **Restricciones:** Ninguna.
---
### Descripción Funcional
Función encargada de la gestión de secuencias de arranque y parada escalonada de hasta 8 dispositivos de forma temporizada.
- Evaluar dinámicamente los parámetros de configuración, limitando el número de elementos de la secuencia a un rango válido entre 1 y 8 mediante la variable `NumElementos`.
- Gestionar el traspaso del tiempo de espera entre etapas, aplicando de forma automática los parámetros `TiempoEntreMarcha` o `TiempoEntreParo` según el estado de la orden activa en la entrada `Marcha`.
- Ejecutar una máquina de estados para la transición secuencial de las etapas de operación, controlando el tiempo de permanencia en cada fase mediante la señal base de tiempo `Pulso1Seg`.
- Monitorizar de forma continua la señal de `Seguridad`, forzando el reinicio seguro de la máquina de estados a la etapa de reposo y limpiando los temporizadores en caso de pérdida.
- Calcular y activar las señales de salida operativas, incluyendo los bits individuales de activación por dispositivo (`M[1]` a `M[8]`) y las confirmaciones de ciclo finalizado (`SecMarchaCompletada` y `SecParoCompletada`).
---
### Dependencias Requeridas
| Tipo | Elementos |
|------|-----------|
| FC | - |
| FB | - |
| DB | - |
| UDT | ´UDT_ZC_MARCHA_PARO_SEC´ |
---
### Historial de Cambios
| Versión | Fecha | Técnico | Cambios |
|----------|------------|---------|---------|
| 01.00.00 | 24.05.2023 | (ABH) | Primera version. |
| 01.00.01 | 28.07.2023 | (ABH) | Se añade traspaso de Set Point de tiempo de paso dentro del FC. |
| 01.00.02 | 14.03.2025 | (ABH) | Se separan los tiempos de arranque de marcha y paro. |
*)
END_REGION DESCRIPCION
// ==========================================================================================================
REGION TRASPASO_PARAMETROS
// Limite de numero de elementos
IF #MP_SEC.NumElementos < 1 THEN
#MP_SEC.NumElementos := 1;
END_IF;
IF #MP_SEC.NumElementos > 8 THEN
#MP_SEC.NumElementos := 8;
END_IF;
// Traspaso de set point tiempo etapa
IF #Marcha THEN
#MP_SEC.Tiempo.SetPoint := #MP_SEC.TiempoEntreMarcha;
ELSE
#MP_SEC.Tiempo.SetPoint := #MP_SEC.TiempoEntreParo;
END_IF;
// Seguridad
IF NOT #Seguridad THEN
#MP_SEC.Etapa := #MP_SEC.Tiempo.Actual := 0;
END_IF;
END_REGION TRASPASO_PARAMETROS
// ==========================================================================================================
REGION SECUENCIA
CASE #MP_SEC.Etapa OF
// ==========================================================================================================
#REPOSO:
IF #Marcha AND #Seguridad THEN
#MP_SEC.Etapa := #MARCHA_1;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
// ==========================================================================================================
#MARCHA_1:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 1 THEN
#MP_SEC.Etapa := #MARCHA_2;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #REPOSO;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_2:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 2 THEN
#MP_SEC.Etapa := #MARCHA_3;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_1;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_3:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 3 THEN
#MP_SEC.Etapa := #MARCHA_4;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_2;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_4:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 4 THEN
#MP_SEC.Etapa := #MARCHA_5;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_3;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_5:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 5 THEN
#MP_SEC.Etapa := #MARCHA_6;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_4;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_6:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 6 THEN
#MP_SEC.Etapa := #MARCHA_7;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_5;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_7:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, si hay mas elementos saltamos a la siguiente etapa, de lo contrario, reseteamos el tiempo de etapa
IF #Marcha THEN
IF #MP_SEC.NumElementos > 7 THEN
#MP_SEC.Etapa := #MARCHA_8;
#MP_SEC.Tiempo.Actual := 0;
ELSE
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
ELSE
#MP_SEC.Etapa := #MARCHA_6;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
// ==========================================================================================================
#MARCHA_8:
// Activacion tiempo de etapa
#MP_SEC.Tiempo.Activar := TRUE;
// Con tiempo de etapa cumplido
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint THEN
// Estando en marcha, reseteamos el tiempo de etapa
IF #Marcha THEN
#MP_SEC.Tiempo.Activar := FALSE;
ELSE
#MP_SEC.Etapa := #MARCHA_7;
#MP_SEC.Tiempo.Actual := 0;
END_IF;
END_IF;
ELSE
#MP_SEC.Etapa := #REPOSO;
END_CASE;
END_REGION SECUENCIA
// ==========================================================================================================
REGION TIEMPO_DE_ETAPA
IF #MP_SEC.Tiempo.Activar THEN
IF #Pulso1Seg THEN
#MP_SEC.Tiempo.Actual += 1;
END_IF;
#MP_SEC.Tiempo.Restante := #MP_SEC.Tiempo.SetPoint - #MP_SEC.Tiempo.Actual;
IF #MP_SEC.Tiempo.Restante <= 0 THEN
#MP_SEC.Tiempo.Restante := 0;
END_IF;
#MP_SEC.Tiempo.Activar := FALSE;
END_IF;
END_REGION TIEMPO_DE_ETAPA
// ==========================================================================================================
REGION SALIDAS
// Secuencia paro completada
#MP_SEC.SecParoCompletada := #MP_SEC.Etapa = 0;
// Secuencia Marcha completada
#MP_SEC.SecMarchaCompletada := FALSE;
CASE #MP_SEC.NumElementos OF
1:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 10 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
2:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 20 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
3:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 30 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
4:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 40 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
5:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 50 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
6:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 60 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
7:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 70 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
8:
IF #MP_SEC.Tiempo.Actual >= #MP_SEC.Tiempo.SetPoint AND #MP_SEC.Etapa = 80 THEN
#MP_SEC.SecMarchaCompletada := TRUE;
END_IF;
END_CASE;
// Bit marcha elementos
#MP_SEC.M[1] := #MP_SEC.Etapa >= 10;
#MP_SEC.M[2] := #MP_SEC.Etapa >= 20;
#MP_SEC.M[3] := #MP_SEC.Etapa >= 30;
#MP_SEC.M[4] := #MP_SEC.Etapa >= 40;
#MP_SEC.M[5] := #MP_SEC.Etapa >= 50;
#MP_SEC.M[6] := #MP_SEC.Etapa >= 60;
#MP_SEC.M[7] := #MP_SEC.Etapa >= 70;
#MP_SEC.M[8] := #MP_SEC.Etapa >= 80;
END_REGION
END_FUNCTION
@@ -0,0 +1,70 @@
FUNCTION "FC4_ZC_ENT_DISPONIBILIDAD" : Bool
TITLE = FC4_ZC_DISPONIBILIDAD_ENTIDAD
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Funcion para comprobar disponibilidad de las entidades.
VAR_INPUT
Entidad : Int; // Numero de entidad a gestionar
END_VAR
BEGIN
REGION DESCRIPCION
(*
###### (C)Copyright ZeusControl 2025 - 2025
---
### Información del Sistema
| Hardware Compatible | Entorno de Ingeniería |
|---------------------|-----------------------|
| PLC serie 1200/1500 | TIA Portal 18 |
---
> **Restricciones:** Ninguna.
---
### Descripción Funcional
Función encargada de evaluar y determinar la disponibilidad operativa de las entidades del sistema.
Las tareas que realiza son las siguientes:
- Calcular el estado de disponibilidad de la entidad correspondiente en función del valor recibido en la entrada `Entidad`.
- Verificar y restringir, por motivos de seguridad, el valor de la entrada `Entidad` para garantizar que no exceda los límites definidos en el array de entidades.
---
### Dependencias Requeridas
| Tipo | Elementos |
|------|-----------|
| FC | `FC4_ZC_DISPONIBILIDAD_ENTIDAD` |
| FB | - |
| DB | `DB6_ENTIDAD` |
| UDT | - |
---
### Historial de Cambios
| Versión | Fecha | Técnico | Cambios |
|----------|------------|---------|---------|
| 01.00.00 | 14.03.2025 | (ABH) | Primera version. |
*)
END_REGION DESCRIPCION
// ==========================================================================================================
REGION GESTION_DISPONIBILIDAD
// Comprobacion de limites de la entrada Entidad. En caso de estar fuera de indices, devolvemos un FALSE.
// En caso de estar dentro de limites, devolvemos el estado de la entidad
IF #Entidad < 1 OR #Entidad > "N_MAX_ENTIDAD" THEN
#FC4_ZC_ENT_DISPONIBILIDAD := FALSE;
ELSE
#FC4_ZC_ENT_DISPONIBILIDAD := "DB6_ENTIDAD".ENT[#Entidad].Estado.Disponible;
END_IF;
END_REGION GESTION_DISPONIBILIDAD
END_FUNCTION
@@ -0,0 +1,280 @@
FUNCTION "FC6_ZC_ENT_ESTADO" : Void
TITLE = FC6_ZC_ESTADO_ENTIDAD
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : AketzaBarragues
FAMILY : ZeusControl
VERSION : 1.0
//Funcion para gestion de estados de entidades.
VAR_INPUT
Entidad : Int; // Numero de entidad a gestionar
TipoProceso : Int; // Tipo de proceso
CodigoProducto : Int; // Codigo de producto
END_VAR
VAR_OUTPUT
TipoError : Int; // 1= Error / 2= Manual
DispNumero : Int; // Numero de dispositivo HMI
END_VAR
VAR_TEMP
for_i : Int;
t_DispError : Bool;
t_DispManual : Bool;
t_DispNumero : Int;
END_VAR
VAR CONSTANT
DISP_V : Int := 1;
DISP_M : Int := 2;
DISP_M_VF : Int := 3;
DISP_M_SINA : Int := 4;
END_VAR
BEGIN
REGION DESCRIPCION
(*
###### (C)Copyright ZeusControl 2020 - 2026
---
### Información del Sistema
| Hardware Compatible | Entorno de Ingeniería |
|---------------------|-----------------------|
| PLC serie 1200/1500 | TIA Portal 18 |
---
> **Restricciones:** Ninguna.
---
### Descripción Funcional
Función para la gestión integral de estados, disponibilidad y supervisión de los dispositivos asociados a una entidad.
Las tareas que realiza son las siguientes:
- **Supervisión de dispositivos:** Escaneo cíclico de los dispositivos vinculados a la entidad (Válvulas, Motores, Variadores y Sinamics) mediante un bucle `FOR`.
- Verificación de alarmas generales (`Alarmas_General`) y estados de mando manual (`Estado_AutoMan`) en cada equipo.
- Identificación del tipo de incidencia en las salidas `TipoError` (1 para Error, 2 para Manual) y reporte del índice del dispositivo afectado en `DispNumero`.
- **Cálculo de disponibilidad:** Determinación del estado `Disponible` basándose en la ausencia de alarmas, mandos manuales, capturas activas y estados de proceso (Producción, CIP, SIP, Standby).
- Actualización del estado `Capturada` si la entidad tiene una asignación distinta de cero.
- **Gestión de códigos de estado:** Asignación dinámica del código numérico `CodEstado` según la fase de operación actual (Producción: 1000, CIP: 2000, SIP: 3000, Standby: 4000).
- Refinamiento del código según el contenido detectado (Producto: +10, Agua: +20, Vacío: +30).
- Registro de estados de limpieza (Sucia: 10000, Limpia: 11000, Esterilizada: 12000).
- **Sincronización de producto:** Actualización de la variable `Producto` con el valor de entrada `CodigoProducto` siempre que la entidad tenga un estado activo.
---
### Dependencias Requeridas
| Tipo | Elementos |
|------|-----------|
| FC | - |
| FB | - |
| DB | `DB2010_V`, `DB2015_M`, `DB2016_M_VF`, `DB2017_M_SINA`, `DB6_ENTIDAD` |
| UDT | - |
---
### Historial de Cambios
| Versión | Fecha | Técnico | Cambios |
|----------|------------|---------|---------|
| 00.00.01 | 15.10.2020 | (ABH) | Primera version. |
| 00.00.02 | 02.02.2021 | (ABH) | Modificado para uso como funcion. Se elimina bucle `FOR` para revisar solamente la entidad que se pasa como entrada. |
| 00.00.03 | 02.12.2022 | (ABH) | Se modifica el UDT para estandarizacion. |
| 00.00.01 | 15.10.2025 | (ABH) | Se añade gestion de codigo de estado. |
| 00.00.05 | 10.03.2025 | (ABH) | Se añade gestion de codigo de producto a las entidades. |
| 00.00.06 | 24.04.2025 | (HCR) | Se añade gestion de idioma. |
| 00.00.07 | 11.09.2025 | (ABH) | Se eliminan las constantes de idioma dentro del `FC`. Se utilizan constantes globales. |
| 01.00.00 | 26.03.2026 | (ABH) | Se elimina idioma. Se añaden constantes de tipo de dispositivo. |
*)
END_REGION DESCRIPCION
// ==========================================================================================================
REGION GESTION_ENTIDADES
IF "DB6_ENTIDAD".ENT[#Entidad].Habilitar THEN
// Asignacion de estado entidad capturada
"DB6_ENTIDAD".ENT[#Entidad].Estado.Capturada := "DB6_ENTIDAD".ENT[#Entidad].Asignacion <> 0;
// ==========================================================================================================
REGION COMPROBACION_DISPOSITIVOS
// Reset de estados
"DB6_ENTIDAD".ENT[#Entidad].Alarma.Dispositivo := "DB6_ENTIDAD".ENT[#Entidad].Alarma.Manual := #t_DispError := #t_DispManual := FALSE;
// Comprobacion de estado de dispositivo declarados dentro de la entidad
FOR #for_i := 1 TO "N_MAX_ENTIDAD_DISPOSITIVOS" DO
// Se revisan solamente las entidades declaradas
IF "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Tipo <> 0 AND "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num <> 0 THEN
CASE "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Tipo OF
#DISP_V:
// ==========================================================================================================
REGION VALVULA
IF "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num <= "N_MAX_DISP_V" THEN
// Comprobacion de errores o dispositivo en manual
#t_DispError := "DB2010_V".V["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Alarmas_General;
#t_DispManual := "DB2010_V".V["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Estado_AutoMan;
IF #t_DispError OR #t_DispManual THEN
#t_DispNumero := (#DISP_V * 1000) + "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num;
END_IF;
END_IF;
END_REGION VALVULA
#DISP_M:
// ==========================================================================================================
REGION MOTOR
IF "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num <= "N_MAX_DISP_M" THEN
// Comprobacion de errores o dispositivo en manual
#t_DispError := "DB2015_M".M["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Alarmas_General;
#t_DispManual := "DB2015_M".M["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Estado_AutoMan;
IF #t_DispError OR #t_DispManual THEN
#t_DispNumero := (#DISP_M * 1000) + "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num;
END_IF;
END_IF;
END_REGION MOTOR
#DISP_M_SINA:
// ==========================================================================================================
REGION MOTOR_SINAMICS
IF "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num <= "N_MAX_DISP_M_SINA" THEN
// Comprobacion de errores o dispositivo en manual
#t_DispError := "DB2017_M_SINA".M_SINA["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Alarmas_General;
#t_DispManual := "DB2017_M_SINA".M_SINA["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Estado_AutoMan;
IF #t_DispError OR #t_DispManual THEN
#t_DispNumero := (#DISP_M_SINA * 1000) + "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num;
END_IF;
END_IF;
END_REGION MOTOR_SINAMICS
#DISP_M_VF:
// ==========================================================================================================
REGION MOTOR_VARIADOR
IF "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num <= "N_MAX_DISP_M_VF" THEN
// Comprobacion de errores o dispositivo en manual
#t_DispError := "DB2016_M_VF".M_VF["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Alarmas_General;
#t_DispManual := "DB2016_M_VF".M_VF["DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num].Estado_AutoMan;
IF #t_DispError OR #t_DispManual THEN
#t_DispNumero := (#DISP_M_VF * 1000) + "DB6_ENTIDAD".ENT[#Entidad].Dispositivo[#for_i].Num;
END_IF;
END_IF;
END_REGION MOTOR_VARIADOR
ELSE
#t_DispError := #t_DispManual := FALSE;
END_CASE;
END_IF;
IF #t_DispError THEN
// Activacion de estado en error
"DB6_ENTIDAD".ENT[#Entidad].Alarma.Dispositivo := TRUE;
#TipoError := 1;
#DispNumero := #t_DispNumero;
EXIT;
ELSIF #t_DispManual THEN
// Activacion de estado en manual
"DB6_ENTIDAD".ENT[#Entidad].Alarma.Manual := TRUE;
#TipoError := 2;
#DispNumero := #t_DispNumero;
EXIT;
END_IF;
END_FOR;
END_REGION COMPROBACION_DISPOSITIVOS
// ==========================================================================================================
REGION ASIGNACION_ESTADOS
// Asignacion de estado disponible
"DB6_ENTIDAD".ENT[#Entidad].Estado.Disponible :=
("DB6_ENTIDAD".ENT[#Entidad].Asignacion = 0)
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Alarma.Dispositivo
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Alarma.Manual
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Estado.EnProduccion
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Estado.EnCIP
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Estado.EnSIP
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Estado.EnStandby
AND NOT "DB6_ENTIDAD".ENT[#Entidad].Estado.Capturada;
// Asignacion de codigo de estado
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 0;
IF "DB6_ENTIDAD".ENT[#Entidad].Estado.EnProduccion THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 1000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.EnCIP THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 2000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.EnSIP THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 3000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.EnStandby THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 4000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.Sucia THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 10000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.Limpia THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 11000;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.Esterilizada THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 12000;
END_IF;
IF (*ENT[#Entidad].Estado.CodEstado >= 1000 AND *)"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado <= 4999 THEN
IF "DB6_ENTIDAD".ENT[#Entidad].Estado.ConProducto THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := "DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado + 10;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.ConAgua THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := "DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado + 20;
ELSIF "DB6_ENTIDAD".ENT[#Entidad].Estado.Vacia THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := "DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado + 30;
END_IF;
END_IF;
// Asignacion de codigo de producto
IF "DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado <> 0 THEN
"DB6_ENTIDAD".ENT[#Entidad].Estado.Producto := #CodigoProducto;
ELSE
"DB6_ENTIDAD".ENT[#Entidad].Estado.CodEstado := 0;
END_IF;
END_REGION ASIGNACION_ESTADOS
ELSE
"DB6_ENTIDAD".ENT[#Entidad].Estado.Disponible := FALSE;
"DB6_ENTIDAD".ENT[#Entidad].Asignacion := 0;
END_IF;
END_REGION GESTION_ENTIDADES
END_FUNCTION