(SCL) Uso di Time Delay Interrupt (S7-300 e S7-400)

Vediamo un esempio di utilizzo del “Time Delay Interrupt” con un richiamo ciclico, ovvero su come è possibile utilizzare un “Time Delay Interrupt” (OB20) al posto di un “Cycle Time Interrupt”.

Se utilizziamo un “Cycle Time Interrupt” in un S7-300 o S7-400 non è possibile modificare in run-time il periodo di esecuzione dell’interrupt (OB35); infatti l’unico metodo (nel caso di S7-300 e S7-400) per modificare il periodo è quello di modificare le impostazioni Hw in Step7 (In TIA Portal: tasto destro su proprietà->Interrupt->Cyclic Interrupt e impostare il tempo in millisecondi su Execution).

Quindi per ovviare a questo problema si può utilizzare un “Time Delay Interrupt” che viene richiamato ciclicamente (il cui periodo di esecuzione può essere appunto cambiato anche in run-time) nel seguente modo:

Creo un OB20 (ad esempio in LAD) e all’interno dello stesso OB20 uso l’istruzione “SRT_DIND” (Start time-delay Interrupt):

ob20_1

Come si può vedere tale istruzione attiva (o meglio riattiva) l’OB20 dopo un intervallo di tempo pari al tempo memorizzato nella variabile time1 all’interno del blocco dati “Dati” (variabile di tipo “Time”); ovviamente modificando il contenuto della variabile “Dati”.time1 viene modificato il periodo di esecuzione dell’OB20 (e tale operazione può essere effettuata anche in run-time).

Ovviamente l’OB20 deve essere attivato una prima volta all’interno di OB1 (oppure da una FC o FB richiamata all’interno di OB1), ossia ad esempio:

main_time_delay_interrupt2

Adesso supponiamo di volere controllare una pompa che ha la funzione di svuotare un serbatoio.

1)Quando viene premuto un pulsante “Start” viene inizializzato il valore iniziale del livello del liquido all’interno del serbatoio (ovviamente solo nel fronte di salita)
2)ad ogni secondo viene effettuata una differenza tra il livello iniziale e quello attuale
3)se tale differenza è maggiore del setpoint la pompa viene spenta
4)la pompa rimane accesa fino a quando non è verificata la condizione al punto 3 oppure fino a quando non viene premuto il pulsante di stop.

Come possiamo vedere è sicuramente possibile eseguire il controllo di questa pompa usando un “Time Delay Interrupt” (che verrà eseguito ogni secondo dopo che è stato premuto il pulsante “Start” e fino a quando non viene premuto il pulsante “Stop”).

Quindi se utilizziamo l’SCL (le operazioni sono le stesse anche in LAD) possiamo fare così:

uso un blocco dati dove salvo alcune variabili che mi serviranno dopo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DATA_BLOCK "Dati"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   STRUCT 
      livello_iniziale : Int;
      cycle_interrupt : Time;
      ret_val_srt : Int;
      ret_val_can : Int;
      Acquisizione_old : Bool;
   END_STRUCT;
 
 
BEGIN
 
END_DATA_BLOCK

Creo una funzione per il controllo della pompa che richiamerò nell’OB20:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FUNCTION "Controllo_pompa" : Void
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      Esecuzione : Bool;
      livello_attuale : Int;
      livello_iniziale : Int;
      set_point : Int;
   END_VAR
 
   VAR_OUTPUT 
      out : Bool;
   END_VAR
 
 
BEGIN
    IF #Esecuzione THEN
        IF (#livello_iniziale - #livello_attuale) >= #set_point THEN
            #out := 0;
        ELSE
            #out := 1;
        END_IF;
    ELSE
        #out := 0;
    END_IF;
 
END_FUNCTION

Come detto richiamo tale funzione nell’OB20, e sempre nell’OB20 richiamo la funzione “SRT_DINT” che riattiva lo stesso OB20 dopo il tempo contenuto in “Dati”.cycle_interrupt (e quindi OB20 verrà eseguito ciclicamente)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ORGANIZATION_BLOCK "Delay_interrupt"
TITLE = "Time Delay Interrupt"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_TEMP 
      OB20_EV_CLASS : Byte;   // Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
      OB20_STRT_INF : Byte;   // 16#21 (OB 20 has started)
      OB20_PRIORITY : Byte;   // Priority of OB Execution
      OB20_OB_NUMBR : Byte;   // 20 (Organization block 20, OB20)
      OB20_RESERVED_1 : Byte;   // Reserved for system
      OB20_RESERVED_2 : Byte;   // Reserved for system
      OB20_SIGN : Word;   // Identifier input (SIGN) attached to SRT_DINT
      OB20_DTIME : Time;   // Delay time (DTIME) input to SRT_DINT instruction
      OB20_DATE_TIME : Date_And_Time;   // Date and time OB20 started
   END_VAR
 
 
BEGIN
    //rieseguo ciclicamente l'OB20 dopo il tempo salvato in "Dati".Cycle_interrupt
    "Dati".ret_val_srt := SRT_DINT(OB_NR := 20, DTIME := "Dati".cycle_interrupt, SIGN := 0);
 
 
    "Controllo_pompa"(Esecuzione := "Acquisizione",
                      livello_attuale := "livello",
                      livello_iniziale := "Dati".livello_iniziale,
                      set_point := 100,
                      out => "pompa");
 
END_ORGANIZATION_BLOCK

E infine il Main :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ORGANIZATION_BLOCK "Main"
TITLE = "Main Program Sweep (Cycle)"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_TEMP 
      OB1_EV_CLASS : Byte;   // Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
      OB1_SCAN_1 : Byte;   // 1 (Cold restart scan 1 of OB 1), 3 (Scan 2-n of OB 1)
      OB1_PRIORITY : Byte;   // Priority of OB Execution
      OB1_OB_NUMBR : Byte;   // 1 (Organization block 1, OB1)
      OB1_RESERVED_1 : Byte;   // Reserved for system
      OB1_RESERVED_2 : Byte;   // Reserved for system
      OB1_PREV_CYCLE : Int;   // Cycle time of previous OB1 scan (milliseconds)
      OB1_MIN_CYCLE : Int;   // Minimum cycle time of OB1 (milliseconds)
      OB1_MAX_CYCLE : Int;   // Maximum cycle time of OB1 (milliseconds)
      OB1_DATE_TIME : Date_And_Time;   // Date and time OB1 started
   END_VAR
 
 
BEGIN
    //Scelgo il periodo di esecuzione dell'OB20
	"Dati".cycle_interrupt := T#1s;
	
	IF "stop" THEN
	    "Acquisizione" := 0;
	    "pompa" := 0;
	ELSIF "start" THEN
	    "Acquisizione" := 1;
	END_IF;
 
	//siccome non è presente un R_Trig in SCL per S7-300 allora ne costruisco uno io,
	//ovvero inizializzo il livello iniziale del serbatoio e attivo l'interrupt OB20 solo in 
    //caso di positive Edge detector dell'input "Acquisizione"
	IF "Acquisizione" AND NOT "Dati".Acquisizione_old THEN
	    "Dati".ret_val_srt := SRT_DINT(OB_NR := 20, DTIME := "Dati".cycle_interrupt, SIGN := 0);
	    "Dati".livello_iniziale := "livello";
	END_IF;
	"Dati".Acquisizione_old := "Acquisizione";
 
    //disattivo l'OB20 se è stato premuto il pulsante di Stop
	IF NOT "Acquisizione" THEN
	    "Dati".ret_val_can:=CAN_DINT(20);
	END_IF;
 
 
END_ORGANIZATION_BLOCK

You may also like...


Warning: count(): Parameter must be an array or an object that implements Countable in /membri/fabioplc/wp-includes/class-wp-comment-query.php on line 399
Menu Title