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):
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:
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 |