Vai al contenuto
PLC Forum


Gestione ingressi


Linotix

Messaggi consigliati

Salve.Qual’e secondo voi il metodo migliore per fare questa cosa:

Ho 64 ingessi in un array all’interno di una fc che gestiscono 64 uscite in un altro array con varie funzioni. Devo ora inserire una memoria che una volta settata faccia si che l’ultimo ingresso alzato oltre a settare l’uscita spenga anche le uscite  precedentemente accese.  In pratica un ingressimo alza l’uscita e mette a zero le altre. Qual’è il metodo migliore in awl? Grazie

Link al commento
Condividi su altri siti


1 ora fa, Linotix scrisse:

 In pratica un ingressimo alza l’uscita e mette a zero le altre.

 

ma è un ingresso preciso o l'ultimo in ordine di tempo?

Link al commento
Condividi su altri siti

Come fai a stabilire se è l'ultimo o se ne arriveranno altri?

Devi impostare un tempo massimo. se allo scadere di questo temporizzatore non ci sono state variazioni dello stato degli ingressi, considiri l'ultimo ingrsso variato.

Ogni volta che varia un ingresso lo memorizzi  nella memoria "ultimo ingresso", poi fai partire il temporizzatore, se il temporizzatore si azzera consideri avvenuto lo stato di ultimo ingresso variato ed esegui la funzione

Link al commento
Condividi su altri siti

Non c’entrano niente I temporizzatori. Cerco di spiegarmi meglio. Se io ho 10 ing. alti, e a quel punto alzo la mem “ resetta ing precedenti” il primo ingresso che si setta azzererà tutti gli altri. Da quel punto in poi, ogni ingresso che si alzerà azzererà il precedente ovviamente. 

Link al commento
Condividi su altri siti

12 ore fa, Linotix scrisse:

Se io ho 10 ing. alti, e a quel punto alzo la mem “ resetta ing precedenti” il primo ingresso che si setta azzererà tutti gli altri. Da quel punto in poi, ogni ingresso che si alzerà azzererà il precedente ovviamente. 

 

Qual'è il problema allora? Se non ti spieghi chiaramente non si riesce a comprendere cosa vuoi realmente fare e qauli sono le condizioni.

 

Forse alzare la memoria "resetta ing precedenti" ?

Ma se non conosci-spieghi le condizioni per cui setti, e resetti, questa memoria il problema è senza soluzioni.

 

Poi c'è un'altra cosa che non chiarisci.

Gli ingressi fisici non li puoi "resettare" perchè il loro stato dipende dal segnale esterno.

Anche se sono ingressi che vengono passati alla funzione dall'esterno non li puoi resettare perchè al prossimo richiamo della funzione saranno ripristinati.

Tutto quello che puoi fare è metterli in AND con un consenso che puoi chiamare "resetta ing precedenti".

Però non puoi usare l'ingresso così cope è ma devi memorizzarne la sequenza di arrivo per poter stabilire la sequenza temporale dell'avvenuta variazione.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

Nel primo post dici che "l'ultimo ingresso setta la sua uscita ed azzera le altre".
Nei successivi post dici che "l'ultimo ingresso azzera gli altri ingressi".

Per quanto riguarda la seconda modalità, come dice Livio, non puoi "azzerare gli ingressi".
Consideriamo quindi solo l'azzeramento di tutte le uscite, e l'attivazione della sola uscita relativa all'ultimo ingresso attivato.

In pratica, devi rilevare i fronti di salita degli ingressi e, quando arriva un fronte di salita, resettare tutte le uscite e poi settare solo l'uscita interessata.

Se lavori a bit, diventa una cosa infinita. Meglio quindi appoggiare i 64 bit di ingresso su 2 variabili DWord.

Un esempio di programma potrebbe essere questo:
 

      L     #Input_DW            // DWord ingressi
      L     #InvInput            // DWord con stato invertito ingressi precedente scansione
      UD
      T     #XOS                 // DWord con fronti salita ingressi
      L     DW#0
      ==D
      SPB   M000                 // Se non ci sono stati fronti di salita, saltare a M000
      L     #XOS
      T     #Output_DW           // Scrivi fronti di salita in DWord uscite
M000: L     #Input_DW
      INVD
      T     #InvInput            // Scrivi stato invertito ingressi per controllo prossima scansione

Con questo sistema te la cavi con poche righe di codice (dovresti ripeterlo per gli altri 32 bit), ma ha un inconveniente: se vanno alti contemporaneamente (nella stessa scansione) 2 o più ingressi, verranno attivate 2 o più uscite.
 

Altra possibilità, fai un LOOP, dove controlli uno ad uno tutti gli ingressi, ed esci dal loop al primo fronte di salita rilevato, così eviti l'eventuale attivazione di più di una uscita.
Con un 1500 nel loop potresti usare una sintassi del tipo IN_Array[id] (dove id è l'indice dell'array), ma nel 300 questa sintassi non è accettata, e devi lavorare con i puntatori.
Oppure fai un ciclo FOR in SCL.

Link al commento
Condividi su altri siti

Ok grazie. In effetti avevo pensato anch’io ad una soluzione come questa e mi era appoggiato a delle Ld temporanee del fc. La soluzione del loop mi sembra migliore. Saresti così gentile da farmi un esempio in awl? Grazie

Modificato: da Linotix
Link al commento
Condividi su altri siti

Ho provato il codice che mi hai suggerito, del resto avevo provato già qualcosa di simile , usando direttamente il fronte delle uscite. Però se io attivo un ingresso, e poi attivo un secondo ( e il primo rimane alto) invece di spegnersi la prima uscita e accendersi la seconda , le uscite iniziano a lampeggiare alternativamente. 

Link al commento
Condividi su altri siti

Quote

Ho provato il codice che mi hai suggerito, del resto avevo provato già qualcosa di simile , usando direttamente il fronte delle uscite. Però se io attivo un ingresso, e poi attivo un secondo ( e il primo rimane alto) invece di spegnersi la prima uscita e accendersi la seconda , le uscite iniziano a lampeggiare alternativamente. 

Io l'ho provato col simulatore, e funziona. Sicuro di averlo copiato correttamente? Come hai dichiarato le variabili? In particolare, le variabili #XOS e #InvInput NON devono essere TEMP.

 

Comunque, ho buttato giù qualcosa in AWL. Ecco il sorgente:

FUNCTION_BLOCK "Test"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      In_DW : DWord;
      RstOut : Bool;
   END_VAR

   VAR_OUTPUT 
      NewInDetected : Bool;
   END_VAR

   VAR_IN_OUT 
      Out_DW : DWord;
   END_VAR

   VAR 
      XOS : DWord;
   END_VAR

   VAR_TEMP 
      id : Int;
      adrIn : DInt;
      adrOut : DInt;
      adrXos : DInt;
   END_VAR


BEGIN
NETWORK
TITLE = 
      SET;
      R #NewInDetected     ;// Azzera variabile OUT "rilevato nuovo ingresso"

      L P##In_DW;// Carica indirizzo variabile immagine ingressi
      T #adrIn;
      L P##Out_DW;// Carica indirizzo variabile immagine uscite
      T #adrOut;
      L P##XOS;// Carica indirizzo variabile immagine rilevamento fronti salita
      T #adrXos;
      L 32;// Imposta numero cicli loop
NEXT:      T #id;
      U DIX[ #adrIn];// Leggi stato ingresso
      FP DIX[ #adrXos];// Rileva fronte salita ingresso
      SPBN M000;// Se non è stato rilevato fronte salita, salta a M000
      L DW#0;
      T #Out_DW;// Azzera tutte le uscite
      SET;
      S DIX[ #adrOut];// Setta uscita corrispondente a ingresso del quale è stato rilevato fronte
      S #NewInDetected;// Setta variabile OUT "rilevato nuovo ingresso"
M000:      L #adrIn;
      + 1;
      T #adrIn;// Incrementa di 1 bit indirizzo variabile immagine ingressi
      L #adrOut;
      + 1;
      T #adrOut;// Incrementa di 1 bit indirizzo variabile immagine uscite
      L #adrXos;
      + 1;
      T #adrXos;// Incrementa di 1 bit indirizzo variabile immagine rilevamento fronti

      L #id;// Carica indice loop
      LOOP NEXT               ;// Decrementa indice e, se indice > 0, torna a NEXT

      UN #RstOut;// Comando reset uscite
      SPB M001;
      L DW#0;
      T #Out_DW;
M001:      NOP 0;

END_FUNCTION_BLOCK

Anche questo l'ho provato col simulatore, e funziona.

La funzione è fatta sempre per 32 ingressi.
Nel tuo caso, per fare i 64 ingressi, dovresti richiamarla due volte (con diverso DB di istanza).
In uscita ho messo anche il rilevamento di un fronte di salita. Questo flag lo potresti usare per azzerare le uscite dell'altro blocco.

 

IMPORTANTE!!! Visto che si fa uso dei puntatori, non si può richiamare la FB come multiistanza. Nel caso volessi richiamarla come multiistanza, dovresti passare alla funzione l'offset dell'indirizzo della funzione stessa.

 

Link al commento
Condividi su altri siti

Io continuo però a sostenere che in SCL sarebbe più facile, anche se non hai dimestichezza con questo linguaggio.
Ecco come potrebbe essere:

FUNCTION_BLOCK "Test_scl"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      IN : Array[1..#n] of Bool;
      RstOut : Bool;
   END_VAR

   VAR_OUTPUT 
      NewInDetected : Bool;
   END_VAR

   VAR_IN_OUT 
      OUT : Array[1..#n] of Bool;
   END_VAR

   VAR 
      XOS : Array[1..#n] of Bool;
   END_VAR

   VAR_TEMP 
      fs : Bool;
      i : Int;
      j : Int;
   END_VAR

   VAR CONSTANT 
      n : Int := 64;
   END_VAR


BEGIN
	// Inizializzo flag rilevamento nuovo ingresso FALSE
	#NewInDetected := FALSE;
	
	
	#fs := false;
	FOR #i := 1 TO #n DO
	    // Rilevo fronte salita ingresso
	    #fs := #IN[#i] AND #XOS[#i];
	    #XOS[#i] := NOT #IN[#i];
	    
	    IF #fs THEN
	        // Eseguo ciclo FOR per azzeramento di tutte le uscite
	        FOR #j := 1 TO #n DO
	            #OUT[#j] := FALSE;
	        END_FOR;
	        // Imposto uscita relativa ad ingresso attivato
	        #OUT[#i] := TRUE;
	        // Imposto flag rilevamento attivazione nuovo ingresso
	        #NewInDetected := TRUE;
	    END_IF;
	END_FOR;
	
	// Azzero uscite con comando da ingresso funzione
	IF #RstOut THEN
	    FOR #j := 1 TO #n DO
	        #OUT[#j] := FALSE;
	    END_FOR;
	END_IF;
END_FUNCTION_BLOCK

In questo caso, lavoro direttamente con gli array. La dimensione dell'array la imposti nella costante "n" all'interno del blocco.

Link al commento
Condividi su altri siti

Grazie mille gentilissimo   In effetti avevo usato variabili temporanee. Problema risolto. Per quanto riguarda  SCL, tutto il resto del programma è in awl quindi vorrei lasciarlo così. Dovrei aggiungere quella parte sulla  fc fatta in awl, o aggiungere un altra fc solamente per le istruzioni scl?Poi quando viene compilato diventa normale awl?

Link al commento
Condividi su altri siti

Quote

Per quanto riguarda  SCL, tutto il resto del programma è in awl quindi vorrei lasciarlo così. Dovrei aggiungere quella parte sulla  fc fatta in awl, o aggiungere un altra fc solamente per le istruzioni scl?Poi quando viene compilato diventa normale awl?

Sì, dovresti fare una FB (non FC, perché ha bisogno di variabili STAT), da richiamare dove vuoi.
Se compili il sorgente, ti risulta un FB con parametri IN/OUT. Richiami la FB e colleghi direttamente gli array di 64 bool.
Se preferisci fare una FC, devi dichiarare la variabile XOS come IN_OUT (e non come STAT, come nell'esempio), e collegare un array di 64 bool (variabile NON TEMP).
Non è strano, anche in un programma interamente in awl, inserire una routine in altri linguaggi.
Per quanto riguarda la compilazione, se lavori con il 300 tutto viene sempre convertito in awl. Con le CPU 1200/1500 invece no.

Link al commento
Condividi su altri siti

Solo un ultima cosa non mi è completamente chiara rispetto al tuo primo esempio. Ho fatto una prova con alcune uscite e funziona. Però io all’inizio avevo usato delle memorie temporanee perche mi era comodo, visto che in uscita della funzione una volta richiamata deve esserci un array da 64 bit. In quel modo potevo creare un array temporaneo e usare delle  LD perché avevo a disposizioni gli indirizzi nella dichiarazione delle variabili  del  blocco e le connessione con l’array di uscita della fc era già fatto.  Però se devo appoggiarmi a delle MD dovrò poi trasferire le memorie nell’array delle uscite , e scrivere su tutti i 64 bit la connessione tra i singoli bit M e l’array In uscita, visto che non voglio trovarmi 64 uscite quando richiamo la FC. C’e un metodo più pratico per connettere i bit dell’array alle Md? Spero di essere stato abbastanza chiaro. 

Link al commento
Condividi su altri siti

Poi perché con le temporanee non funziona visto che le connessioni tra ingressi e uscite sono tutte scritte all’interno della  funzione senza richiami all’esterno?  Scusate per le tante domande ma voglio capire fino in fondo quello che sto facendo. 

Link al commento
Condividi su altri siti

Gli esempio che ho fatto sono per la creazione di una FB alla quale passi in ingresso lo stato degli ingressi, e come IN/OUT lo stato delle uscite. Le variabili usate sono variabili STAT all'interno della funzione. Non serve quindi tirare in ballo merker od altro.
È il modo più comodo per gestire la cosa.
Se non vuoi creare una FB, in ogni caso lascia perdere i merker, e usa i DB. Se il codice lo scrivi all'interno di una FB, dichiara le variabili come STAT.
Se sei all'interno di una FC, crea dei DB con le variabili che ti servono.

 

Quote

Poi perché con le temporanee non funziona visto che le connessioni tra ingressi e uscite sono tutte scritte all’interno della  funzione senza richiami all’esterno?  Scusate per le tante domande ma voglio capire fino in fondo quello che sto facendo. 

Per rispondere a questa domanda, dovrei vedere il tuo programma. Da quello che scrivi non capisco quali siano le variabili TEMP

Link al commento
Condividi su altri siti

20 ore fa, batta scrisse:

o l'ho provato col simulatore, e funziona. Sicuro di averlo copiato correttamente? Come hai dichiarato le variabili? In particolare, le variabili #XOS e #InvInput NON devono essere TEMP.

Mi riferivo a queste variabili. Comunque penso di aver capito che che con le temp non funziona perché azzerandosi ad ogni ciclo non memorizzano lo stato per fare il confronto. Grazie del tuo aiuto. 

Link al commento
Condividi su altri siti

Anche se sinceramente per quanto riguarda la variabile xos non mi sembra serva salvare lo stato del ciclo precedente visto che i fronti li rileva ad ogni ciclo. 

Link al commento
Condividi su altri siti

Quote

Anche se sinceramente per quanto riguarda la variabile xos non mi sembra serva salvare lo stato del ciclo precedente visto che i fronti li rileva ad ogni ciclo. 

Il rilevamento del fronte di salita viene fatto confrontando lo stato attuale con lo stato precedente.
Lo stato precedente deve essere memorizzato, quindi non può essere una variabile TEMP.

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...