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

