Vai al contenuto
PLC Forum


Azzeramento dati


Ghisla

Messaggi consigliati

Buonasera a tutti,

Ho realizzato un blocco FC (TIA Portal V16), al quale come parametro di ingresso gli passo un "Array[*] of POSAGGI". Dove "POSAGGI" sta per una struttura UDT creata da me.

Quello che vorrei fare all'interno di questo FC è azzerare tutti i dati all'interno dell'array passato in ingresso senza dover fare modifiche all'FC in caso di cambio struttura di dati. Il tipo di dati POSAGGI contiene dati misti di cui word,byte,bool ecc.

Questo perchè il tipo di dati che ho creato ora deve essere azzerato, ma nel proseguimento del tempo questa struttura può essere modificata.

 

Ringrazio

 

Link al commento
Condividi su altri siti


io dichiarerei in area temp un dato di tipo "posaggi", siccome nel 1500 le variabili temp vengono inizializzate sempre a 0 si fa abbastanza presto, fai un ciclo for dove ad ogni elemento dell'array gli assegni la tua variabile temp, 3 righe di codice e hai finito.

ricordati di usare le funzioni upperbound e lowerbound per ricavare l'indice minimo e massimo del ciclo.

 

PS devi dichiarare l'array in area in/out, se lo lasci in area in, all'uscita del blocco non viene modificato

Modificato: da il toby
aggiunto PS
Link al commento
Condividi su altri siti

19 ore fa, il toby ha scritto:

siccome nel 1500 le variabili temp vengono inizializzate sempre a 0

vale per tutte le variabili? Anche booleane? Non sapevo di questa caratteristica le temp le ho sempre inizializzate prima di usarle (retaggio s7 300- 400)

Link al commento
Condividi su altri siti

19 ore fa, il toby ha scritto:

siccome nel 1500 le variabili temp vengono inizializzate sempre a 0 si fa abbastanza presto

non vengono inizializzate, se ci sono dei valori sporchi da altre fc restano, è sempre meglio reinizializzarle.

Link al commento
Condividi su altri siti

2 ore fa, acquaman ha scritto:

non vengono inizializzate, se ci sono dei valori sporchi da altre fc restano, è sempre meglio reinizializzarle.

A me piace inizializzarle in modo esplicito, nel programma ma, nel 1500, a differenza del 300, le variabili TEMP vengono azzerate dal sistema.

Link al commento
Condividi su altri siti

Le variabili temp vengono inizializzate a patto che il blocco sia ottimizzato ed il firmware sia V4 o successivo.

 

P.S.: non lo sapevo, sono andato a vedere le linee guida (trovate solo inglese):

Temporary tags are undefined when called in non-optimized blocks. In optimized blocks, the values are always preset with the default value (S7-1500 and S7-1200 firmware V4 and higher). Thus, the resulting behavior is not accidental but reproducible behavior.

 

 

Link al commento
Condividi su altri siti

Non so se ti risolve, ma potresti aggiungere alla tua FC una variabile di ingresso (o in/out) di tipo "POSAGGI" (es. inPosaggiVuota).

Nella FC l'inizializzazione del'array diventerebbe la copia della variabile inPosaggiVuota nell'array tramite ciclo for.

All'esterno della FC avrai bisogno di una variabile sempre di tipo POSAGGI (all'interno di una db_inizializzazione) che lascerai sempre vuota e userai coma input alla tua FC.

 

Se cambi la struttura POSAGGI ti basta ricompilare il programma e il tutto dovrebbe funzionare senza modificare la FC o la db_inizializzazione.

 


 

 

 

Link al commento
Condividi su altri siti

  • 2 weeks later...

Se vuoi farlo in modo "brutale" puoi:
   1) Mettere l'array delle struct in un DB dedicato

   2) Il DB deve essere NON ottimizzato
   3) Scrivere un FC con due righe in di codice per:

      a) Definire di quanty byte è composto il DB

      b) Scrivere un loop da 0 a "numero byte" e scrivere zero in ognuno.

In questo modo, quando dai un DB in pasto all'FC, viene scritto zero in tutti i byte indipendentemente da come è strutturato

Link al commento
Condividi su altri siti

Il 11/11/2020 alle 18:10 , Ghisla ha scritto:

Come posso fare a scrivere un codice che rimanga sempre lo stesso, e che azzeri una struttura che può variare?

Se la struttura cambia, devi usare il formato "Variant".

 

L'utilizzo di variabili "Variant" non è semplicissimo, ma ti permette di fare funzioni che si adattano a tipi di dati diversi.
Un ottimo esempio dell'utilizzo del formato Variant lo trovi nelle funzioni FIFO e LIFO della libreria "LGF_Library".
È una libreria di Siemens, gratuita, secondo me con funzioni fatte molto bene, con blocchi non protetti e codice commentato in modo chiaro.
Volendo, potresti anche usare direttamente la funzione FIFO, sfruttando solo il comando "Clear".

Oppure potresti partire da questa funzione ed eliminare tutto ciò che non ti serve.

O, meglio ancora, studiare bene la funzione per capire come si usano i dati "Variant" e creare una tua funzione.

 

I dati Variant non si usano spesso, e anch'io, onestamente, non li gestisco in modo disinvolto. Ogni volta che mi viene qualche dubbio, consulto la funzione FIFO di questa libreria.

 

Link al commento
Condividi su altri siti

Buongiorno a tutti, ho provato a dare un'occhiata ai dati variant per sistemare il mio FC in modo da passare un qualsiasi tipo di dato in ingresso.

La mia funzione non deve fare altro che prendere un array di tipo di dati in ingresso e eseguire uno shift, al termine dello shift nella prima posizione dell'array deve azzerare tutti i dati.

Ho provato a "smanettare" un poco ma non ci sono riuscito.

 

Nell'immagine allegata si possono vedere i dati nella DB che devo shiftare. 

image.png.e1263bbe41df454fccd4ebee1c9c71bb.png

 

Nell'immagine sottostante potete vedere come ho impostato i dati di in/out del mio FC

image.png.bfd5a49d028be333eddcd10499c02c81.png

 

In questo modo però, sono obbligato a dovermi creare un FC diverso per ogni struttura. Vorrei creare un blocco che con qualsiasi struttura io gli passo esegua lo shift da me desiderato

e come detto prima, nella prima posizione dell'array vada a azzerare tutti i dati.

 

Se riusciste ad aiutarmi con esempi pratici in quanto guardando l'esempio di FIFO e LIFO della siemens non sono riuscito a risolvere il problema, ve ne sarei molto grato.

 

Ringrazio tutti

Link al commento
Condividi su altri siti

5 ore fa, Ghisla ha scritto:

La mia funzione non deve fare altro che prendere un array di tipo di dati in ingresso e eseguire uno shift, al termine dello shift nella prima posizione dell'array deve azzerare tutti i dati.

Allora è ben diverso da quanto avevi chiesto all'inizio. Cito:

Quello che vorrei fare all'interno di questo FC è azzerare tutti i dati all'interno dell'array passato in ingresso senza dover fare modifiche all'FC in caso di cambio struttura di dati. Il tipo di dati POSAGGI contiene dati misti di cui word,byte,bool ecc.

 

Quello che chiedo ora mi sembra più un registro, non un azzeramento di un array.

Nel caso si tratti di un registro (FIFO o LIFO non ha importanza) la soluzione che quasi sempre viene in mente per prima, è proprio quella di far scorrere tutti gli elementi del registro.
Questa soluzione ha il vantaggio di individuare facilmente quale sia il dato più vecchio, e di andare ad inserire il nuovo dato sempre nello stesso elemento. Se si lavora con array di notevoli dimensioni, diventa però un lavoro pesante per la cpu. Immagina un registro con qualche migliaio di elementi.
L'altro metodo è quello di gestire gli indici, anziché far scorrere i dati. In questo modo, per quanto lungo sia l'array, le operazioni saranno sempre le stesse, e ridotte al minimo indispensabile.
Ed è proprio ciò che fa la funzione FIFO che ti ho indicato.

Se il tuo array è di pochi elementi, e se per te è importante mantenere fisso l'ordine degli elementi, allora puoi usare il sistema con scorrimento degli elementi dell'array.


In ogni caso, per creare un'unica funzione che si adatti a strutture dati diversi, la soluzione è nelle variabili di tipo "Variant", non c'è altro modo.

 

 

Link al commento
Condividi su altri siti

L'azzeramento che intendevo era per resettare dopo lo shift i valori nella prima posizione dell'array. La soluzione si è usare per forza i dati variant. Ma per eseguire la funzione da me descritta come posso fare? Non riesco a trovare praticamente la soluzione a livello di codice. Ringrazio

Link al commento
Condividi su altri siti

Quindi mi confermi che vuoi fare uno scorrimento degli elementi dell'array, e poi azzerare solo il primo elemento?

Vedi esempio:

FUNCTION "FC_SHIFT_Variant" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      execute : Bool;
   END_VAR

   VAR_OUTPUT 
      done : Bool;
   END_VAR

   VAR_IN_OUT 
      init : Variant;
      buffer : Variant;
   END_VAR

   VAR_TEMP 
      bufferSize : UDInt;
      BlkMove_Error : Int;
      i : Int;
   END_VAR


BEGIN
	// Inizializzo "done"
	#done := false;
	
	// Eseguire le istruzioni solo con comando "execute" attivo.
	// N.B.: per far avanzare il registro di un solo passo, si deve attivare "execute" per una sola scansione.
	IF NOT #execute THEN
	    RETURN;
	END_IF;
	
	// Controllo che "buffer" sia un array.
	// Se è un array leggo la dimensione dell'array,
	// altrimenti, esco dalla funzione.
	IF IS_ARRAY(#buffer) THEN
	    #bufferSize := CountOfElements(#buffer);
	ELSE
	    RETURN;
	END_IF;
	
	// Se il tipo di dati di "init" è diverso dal tipo di dati
	// degli elementi di "buffer" esco dalla funzione.
	IF TypeOf(#init) <> TypeOfElements(#buffer) THEN
	    RETURN;
	END_IF;
	
	// Le seguenti istruzioni vengono eseguite solo se i controlli precedenti
	// hanno dato esito positivo
	// 
	
	// Scorrimento degli elementi dell'array: il penultimo elemento
	// viene copiato nell'ultimo, il terzultimo nel penultimo, e così via,
	// fino al primo elemento copiato nel secondo.
	// L'indice dell'array parte da zero, quindi l'ultimo elemento avrà indice
	// pari al numero di elementi dell'array - 1.
	// L'indice del penultimo elemento sarà quindi pari al numero di elementi dell'array - 2.
	FOR #i := (UDINT_TO_INT(#bufferSize) - 2) TO 0 BY -1 DO
	    #BlkMove_Error := MOVE_BLK_VARIANT(SRC := #buffer,
	                                       COUNT := 1,
	                                       SRC_INDEX := #i,
	                                       DEST_INDEX := #i + 1,
	                                       DEST => #buffer);
	    IF #BlkMove_Error <> 0 THEN
	        RETURN;
	    END_IF;
	END_FOR;
	
	// al termine dello scorrimento, copio "init" nel primo elemento dell'array.
	#BlkMove_Error := MOVE_BLK_VARIANT(SRC := #init,
	                                   COUNT := 1,
	                                   SRC_INDEX := 0,
	                                   DEST_INDEX := 0,
	                                   DEST => #buffer);
	
	IF #BlkMove_Error <> 0 THEN
	    RETURN;
	END_IF;
	
	// ogni eventuale errore nell'esecuzione della funzione causa l'uscita dalla funzione stessa.
	// Se sono arrivato alla fine della funzione, significa che l'esecuzione è avvenuta
	// in modo corretto.
	// Attivo l'uscita "done".
	#done := TRUE;
	
	
END_FUNCTION

Copia tutto il testo in un file con estensione .scl, importa il file nella cartella "Sorgenti esterne" del progetto TIA Portal, poi click con tasto destro --> "Genera blocchi dalla sorgente".

 

Note:

- l'azzeramento del primo elemento dell'array in realtà non è un azzeramento, ma vengono copiati i dati passati ad "init".
Dovrai quindi creare una struttura con lo stesso tipo di dati degli elementi dell'array, con tutte le variabili a zero.

- all'interno della funzione non ho rilevato il fronte di salita del comando "execute" (sarebbe servita una variabile statica, ma allora si doveva passare ad una FB, o passare la memoria del fronte come IN/OUT), quindi "execute" dovrà essere gestito con un fronte esterno alla funzione.

 

Come già detto in precedenza, questo sistema, con lo scorrimento di tutti gli elementi dell'array, è da usare con una certa cautela, perché la sua esecuzione diventa pesante in caso di array molto lunghi.

 

Mi pare che non ci sia nulla di complesso. Unico accorgimento, per fare le cose con un minimo di criterio, è inserire i controlli per verificare che i dati passati come Variant siano coerenti. Nel mio esempio, in caso di errore esco dalla funzione, ma senza riportare codici di errore. Se guardi come è fatta la funzione FIFO della libreria, vedi che aggiungere dei codici di errore è facilissimo.

Per il resto, tutto si basa sulla lettura della dimensione dell'array, e sulla funzione MOVE_BLK_VARIANT, che è ben descritta nella guida in linea.

Modificato: da batta
Link al commento
Condividi su altri siti

Grazie mille batta, ora ho capito come poter gestire la cosa, non ne avevo la minima idea di come fare.

Per quanto riguarda le dimensioni attualmente ora a me servono pochi dati quindi non dovrebbero esserci problemi. Ti chiedo soltanto una cosa per scopo didattico: come si potrebbe fare ad azzerare i dati nella prima posizione dell'Array all'interno della funzione? E soprattutto, è possibile farlo? 

Per quanto riguarda gli errori ho dato un'occhiata alla libreria da te citata e credo di fare una cosa simile.

 

Batta sempre molto utile ed esaustivo

Link al commento
Condividi su altri siti

12 ore fa, Ghisla ha scritto:

come si potrebbe fare ad azzerare i dati nella prima posizione dell'Array all'interno della funzione? E soprattutto, è possibile farlo? 

secondo me basta che nella dichiarazione aggiungi una variabile che per default è azzerata e al termine la muovi sulla prima posizione dell'array, utilizzando sempre il MOVE_BLK_VARIANT, ma aspettiamo il responso dell'autore del blocco.

Link al commento
Condividi su altri siti

1 ora fa, pigroplc ha scritto:

secondo me basta che nella dichiarazione aggiungi una variabile che per default è azzerata e al termine la muovi sulla prima posizione dell'array, utilizzando sempre il MOVE_BLK_VARIANT, ma aspettiamo il responso dell'autore del blocco.

No, non si può fare.
MOVE_BLK_VARIANT, per poter lavorare, ha bisogno che le strutture dati sorgente e destinazione siano identiche.
Per poter lavorare con variabili interne alla funzione, dovresti dichiararle dello stesso formato degli elementi dell'array.

Ma, allora, se all'interno della funzione devi impostare un tipo di dati definito, non ha più senso lavorare con le variabili Variant.

Comunque, dover passare alla funzione una variabie (init, nell'esempio) per inizializzare il primo elemento dell'array, non mi pare tanto grave.

In alternativa, si potrebbe usare il primo elemento dell'array per l'azzeramento, e lavorare con i dati dal secondo elemento in poi.

Basterebbe modificare il ciclo FOR facendolo terminare ad 1 anziché a 0, e riscrivere la parte per l'azzeramento come segue:

// al termine dello scorrimento, copio il primo elemento dell'array (usato per l'azzeramento) nel secondo elemento.
	#BlkMove_Error := MOVE_BLK_VARIANT(SRC := #buffer,
	                                   COUNT := 1,
	                                   SRC_INDEX := 0,
	                                   DEST_INDEX := 1,
	                                   DEST => #buffer);

In questo modo, la variabile "init" non serve più. Basta ricordarsi di non usare il primo elemento dell'array.

Link al commento
Condividi su altri siti

1 ora fa, batta ha scritto:

MOVE_BLK_VARIANT, per poter lavorare, ha bisogno che le strutture dati sorgente e destinazione siano identiche.

Batta,
dopo la tua spiegazione mi è chiaro........grazie

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...