Vai al contenuto
PLC Forum


Tecnica batch


alefrasca

Messaggi consigliati

10 ore fa, Cesare Nicola scrisse:

Se il bit si fosse chiamato, per esempio "merker_passo_1", "merker_passo_15", ecc. sarebbe stato più facile

Io preferisco che i bit di passo abbiano un nome che identifica la funzione del passo.
Di solito organizzo i bit in una struttura. C'è sempre un bit "On", un bit "Init", un bit "End". Poi ci sono i passi.
L'ordine dei passi, molto semplicemente è l'ordine in cui i bit sono ordinati nella struttura.
Se si inseriscono nuovi passi, o se si cambia l'ordine dei passi, non c'è nulla da cambiare.
Invece, se i passi hanno nel nome il numero del passo, se inserisco un passo prima di "Passo_5" devo cambiare tutti i nomi dei passi che vengono dopo.

Qualche volta, dato che ogni tanto bisogna provare nuove strade, ho utilizzato un array (con funzione del passo nel commento).
Poi però sono subito tornato sulla vecchia strada.

Link al commento
Condividi su altri siti


  • Risposte 54
  • Created
  • Ultima risposta

Top Posters In This Topic

  • step-80

    17

  • Cesare Nicola

    13

  • batta

    9

  • leleviola

    9

35 minuti fa, batta scrisse:

Qualche volta, dato che ogni tanto bisogna provare nuove strade, ho utilizzato un array (con funzione del passo nel commento).
Poi però sono subito tornato sulla vecchia strada.

quindi batta sconsigli l'uso degli array perchè legato a un numero di bit nell'array, giusto?

quello che chiedevo io è possibile usare uno shift-register all'interno di un array di bool? Scusate l'ignoranza

Modificato: da leleviola
Link al commento
Condividi su altri siti

No, non lo sconsiglio. Ho detto solo che, personalmente, mi trovo meglio in un altro modo.
Stiamo parlando di metodi più o meno equivalenti, che presentano sia pro che contro. Non esiste quello migliore. La preferenza è puramente soggettiva.

Modificato: da batta
Link al commento
Condividi su altri siti

No, non lo sconsiglio. Ho detto solo che, personalmente, mi trovo meglio in un altro modo.
Stiamo parlando di metodi più o meno equivalenti, che presentano sia pro che contro. Non esiste quello migliore. La preferenza è puramente soggettiva.

 

Quote

quello che chiedevo io è possibile usare uno shift-register all'interno di un array di bool

Sì, certo, è possibile. Non è il mio metodo preferito, perché è un po' rigido. Tutto dipende da cosa devi fare.

Link al commento
Condividi su altri siti

@batta una curiosità: dici di organizzare i bit all’interno di una struttura , la quale suppongo si trovi all’interno di un db. 

I bit saranno quindi identificati come NomeDb.NomeStruttura.NomeBit. Ma qual’è il vantaggio di usare una struttura in questo caso? Puoi usare istruzioni particolari che ti permettono di scorrerla/scriverla/interrogarla meglio?

 

seconda cosa, ma giusto per curiosità: ‘on’ potrebbe essere un bit alto per tutta la durata della sequenza, una sorta di ‘busy’...; ‘init’ sicuramente ha a che fare con l’inizializzazione ma non capisco bene  da chi e come venga scritto...; ‘end’ invece? Per cosa lo usi? 

Link al commento
Condividi su altri siti

Capisco cosa vuoi dire, con una struttura il sistema è più duttile se ho ben capito, mi sembra di capire che se hai da aggiungere un passo tra uno e un altro è più duttile

Link al commento
Condividi su altri siti

2 ore fa, step-80 scrisse:

dici di organizzare i bit all’interno di una struttura , la quale suppongo si trovi all’interno di un db

Generalmente è nelle STAT di una FB. Con le istruzioni SCATTER, GATHER e MOVE puoi agevolmente azzerare tutta la struttura, o verificare se i bit sono tutti a zero, anche lavorando con blocchi ottimizzati.
"On" rimane alto per tutta la sequenza. Anzi, di solito, utilizzo lo stato basso dello stesso ON per azzerare tutta la sequenza. Mi basta abbassare, da qualsiasi parte, il bit ON per resettare tutto.
"Init" è usato per eventuali inizializzazioni allo start della sequenza. Spesso non serve, ma lo dichiaro oramai come prassi.
"End" mi rimane alto per una scansione a fine ciclo. Non serve sempre ma, anche questo, fa parte di una mia prassi oramai consolidata.

 

2 ore fa, leleviola scrisse:

con una struttura il sistema è più duttile se ho ben capito

Come ho già detto, non sto assolutamente sostenendo che questo sistema sia il migliore, ma solo che io mi trovo bene con questo sistema.
Tutti i metodi descritti sono ugualmente validi. Ad ognuno il compito di mettere a punto quello con cui si trova meglio.

Link al commento
Condividi su altri siti

Personalmente uso il metodo dello shift in casi di mini-sequenze tipo homing: sequenze che tipicamente occupano meno di 16 passi e non presentano diramazioni. 

 

Tutti i sistemi hanno i suoi pro e contro..curioso constatare che anch'io,come Batta, nel tempo mi sono creato un sistema che reputo discretamente funzionante e collaudato. Ogni tanto provo ad uscire dal seminato per poi ritornare sui miei passi, anch'io dichiaro delle variabili che spesso so già in partenza che non servono ma per prassi lo faccio ugualmente.

Link al commento
Condividi su altri siti

 

il 30/8/2019 at 19:46 , batta scrisse:

Di solito organizzo i bit in una struttura. C'è sempre un bit "On", un bit "Init", un bit "End". Poi ci sono i passi.
L'ordine dei passi, molto semplicemente è l'ordine in cui i bit sono ordinati nella struttura.

Infatti, gira e rigira si arriva sempre lì: se c'è ordine e coerenza, come fai tu, ogni metodo va bene. Il software che avevo preso in mano io non era così ordinato, i bit erano dei merker senza alcuna organizzazione e quindi il debug era un po' più difficile.

Link al commento
Condividi su altri siti

Quote

Io preferisco che i bit di passo abbiano un nome che identifica la funzione del passo.

Questa è una delle classiche cose che ti fanno pensare 'ma perchè diavolo non c'ho pensato anch'io?'

effettivamente anch'io chiamo i passi 'Passo1', 'Passo2', ecc..ma cosi facendo il rischio è , come diceva @batta, di trovarsi ad aggiungere un passo in mezzo dovendo poi stravolgere tutto. 

Mettiamoci anche che in Mitsubishi le label sono limitate a 32 miseri caratteri , questo porta a doversi ingegnare in altro modo. 

 

Grazie per quest'altra 'perla' :smile:

Modificato: da step-80
Link al commento
Condividi su altri siti

  • 4 weeks later...
Quote

Per come programmo io devi scorrere un FB, non l'intero programma e di solito l'FB non è particolarmente lungo; se lo è, forse ho sbagliato qualcosa e dovevo suddividerlo in più di uno. Ogni FB che contiene una sequenza, ha la sua variabile: le sequenze si "parlano", per me, con un bit di scambio. Cioè, se la sequenza 1 ad un certo punto deve avviare la 2 (che è probabilmente in un differente FB) ed attendere che questa sia conclusa, faccio così:

  • sequenza 1 setta il bit "avvia sequenza 2"
  • sequenza 1 va al passo successivo, dove attende che "avvia sequenza 2 ritorni a zero".
  • Nel frattempo, sequenza 2 parte grazie al bit "avvia sequenza 2" e fa quello che deve fare.
  • Quando sequenza 2 ha finito il suo lavoro, mette a zero "avvia sequenza 2" e sequenza 1 può proseguire

 

Riesumo per un attimo questa discussione per un chiarimento da @Cesare Nicola o @batta o chiunque altro.

 

Nella sequenza descritta si prevede, all'interno di un FB,di resettare un bit proveniente da un altro FB. 

Volevo chiedere, all'atto pratico, come fate ad attuare ciò considerando che , se usate una Fb, non credo che andrete a settare/resettare direttamente gli indirizzi voluti. 

Io ho inteso che (correggetemi se sbaglio):

 

Sequenza 1 e Sequenza 2 sono 2 Fb;

Ad un certo punto di Sequenza 1 devo far partire Sequenza 2;

 

Sequenza 1 pertanto avrà dichiarata:

-come OUT o INOUT  un bit 'avvia sequenza 2';

-come IN o INOUT un bit 'reset start da sequenza 2';

Sequenza 2 invece  avra' dichiarata:

-come IN o INOUT un bit 'Start da Sequenza 1';

-come OUT o INOUT un bit 'reset start a Sequenza 1';

 

Sequenza 1 alza il bit 'avvia sequenza 2' e va al passo successivo dove attende che 'avvia sequenza 2' si abbassi;

Una volta ricevuto lo start, Sequenza 2 fa quello che deve fare  ;

Una volta terminato il suo compito, Sequenza 2 alza (anche per una scansione) il bit 'reset start a Sequenza 1';

Dentro Sequenza 1,il bit 'reset start da sequenza 2' abbassa il bit 'avvia sequenza 2' e il ciclo della Sequenza 1 può continuare.

 

Tralasciando i nomi, i modi ecc , è giusto il ragionamento?è giusto usare quindi questi 4 bit in scambio?

 

Modificato: da step-80
Link al commento
Condividi su altri siti

5 minuti fa, step-80 scrisse:

Sequenza 1 pertanto avrà dichiarata:

-come OUT o INOUT  un bit 'avvia sequenza 2';

-come IN o INOUT un bit 'reset start da sequenza 2';

Sequenza 2 invece  avra' dichiarata:

-come IN o INOUT un bit 'Start da Sequenza 1';

-come OUT o INOUT un bit 'reset start a Sequenza 1';

Non proprio. Io uso variabili INOUT di modo che la stessa che viene settata da un FB può essere resettata dall'altro FB; evito quindi la variabile che tu chiami "reset start da sequenza ...".

Il risultato quindi è:

  1. Sequenza 1 alza il bit 'avvia sequenza 2' e va al passo successivo dove attende che 'avvia sequenza 2' si abbassi;
  2. Una volta ricevuto lo start, Sequenza 2 fa quello che deve fare;
  3. Una volta terminato il suo compito, sequenza 2 resetta il bit "avvia sequenza 2" (è qui la differenza con quanto hai scritto tu)
  4. Dentro Sequenza 1, quando il bit "avvia sequenza 2" è stato abbassato da sequenza 2, il ciclo della Sequenza 1 può continuare.

In questo modo il bit è uno solo. A qualcuno può forse non piacere che un bit settato da un FB venga resettato da un altro; come insisto sempre, però, è questione di usare metodo, ordine, pulizia e commenti. Quel bit deve essere usato solo da quei due FB, solo per quello scopo e deve essere ben commentato (non tipo "str_FB_pomp_princ" o "strt_FB2" che mi fanno venire l'orticaria quando li vedo ma "Start_sequenza_pompa_principale", per esempio); i segmenti in cui quel bit viene messo a zero o uno devono anch'essi avere un commento ben fatto, che faccia capire che si sta "saltando" da un FB a un altro.

Link al commento
Condividi su altri siti

Aggiungo che si potrebbe anche evitare di definire il bit di scambio al di fuori dei due FB; "sequenza 2" può accedere alla DB di istanza di "sequenza 1". Funziona comunque e si risparmia un bit. In questo caso il bit "avvia sequenza 2" non sarà INOUT ma STAT. Questione di gusti e abitudini, se ne è già parlato qui sul forum.

Link al commento
Condividi su altri siti

Chiarissimo @Cesare Nicola

Vero, se dichiaro come INOUT posso settare/resettare da una Fb all'altra (sempre commentando bene come giustamente fatto notare). 

 

Adesso sto sto usando un sistema del genere:

 

Sequenza 1 Comanda -----( )   il bit 'Avvia sequenza 2' e rimane in quella fase che ha come transizione un bit ricevuto dalla sequenza 2 (Ciclo Sequenza 2 terminato).

Quindi 'Avvia sequenza 2' rimane alto finchè non si alza 'Ciclo Sequenza 2 terminato'. 

Quando si Alza 'Ciclo Sequenza 2 terminato' , la sequenza 1 passa alla fase successiva e pertanto 'Avvia sequenza 2' si abbassa.

Dentro Sequenza 2 , il reset di 'Ciclo Sequenza 2 terminato' lo faccio con lo stato basso di 'Avvia sequenza 2'.

 

Alla fine è la stessa cosa, devo ancora trovare un sistema che mi convince al 100% .

Poi credo che vada anche a seconda delle macchine che si realizzano. 

 

Quote

Aggiungo che si potrebbe anche evitare di definire il bit di scambio al di fuori dei due FB; "sequenza 2" può accedere alla DB di istanza di "sequenza 1". Funziona comunque e si risparmia un bit. In questo caso il bit "avvia sequenza 2" non sarà INOUT ma STAT. Questione di gusti e abitudini, se ne è già parlato qui sul forum.

Aspetta, c' è qualcosa che mi sfugge.

Questo è valido nel caso in cui Sequenza 1 e Sequenza 2 siano 2 Fb richiamate una sola volta giusto?

 

Supponiamo che ho un Fb 'Gestione Sequenza Pompe' che si occupa di dare lo start con una determinata sequenza logica a 10 pompe. Questo Fb è richiamato una sola volta.

Avrò quindi anche una Fb 'Gestione Pompa' richiamata 10 volte , ognuna con la sua istanza. Ognuna deve ricevere lo start da 'Gestione Sequenza Pompe'. Come faccio dentro quest'ultima ad indirizzare il  mio start alla pompa voluta? Sono costretto a creare all'interno di essa un qualcosa tipo StartPompa:ARRAY[1..10]of Bool e gestire cosi separatamente lo start alle pompe? Oppure c'è un sistema più elegante?

Modificato: da step-80
Link al commento
Condividi su altri siti

Proprio adesso, step-80 scrisse:

Alla fine è la stessa cosa, devo ancora trovare un sistema che mi convince al 100% .

Come si è detto spesso, ogni sistema ha pro e contro, questione di abitudini.

 

1 minuto fa, step-80 scrisse:

Poi credo che vada anche a seconda delle macchine che si realizzano

Su questo sono meno d'accordo. Se un metodo è efficace su una macchina complessa io lo uso anche su quella semplice. Primo perché così il mio metodo di lavoro è uno solo e vado sempre spedito, indipendentemente dalla macchina. Secondo perché, bello o brutto che sia il mio metodo, se è sempre quello e passo un mio software a un collega, lui sa già cosa aspettarsi, indipendentemente dalla macchina; magari mi tirerà degli accidenti ma almeno sa dove mettere mano! Terzo perché capita che la macchina che oggi è semplice in futuro può subire aggiunte o modifiche che la rendono più complicata e così il software è già predisposto ad modificato o espanso.

Link al commento
Condividi su altri siti

Sono completamente daccodo con @Cesare Nicola , non c'è niente di male a concatenare due cicli di passi e a far attivare l'uno con l'altro dai vari fronti di attivazione e disattivazione dei passi,  daltronde è a questo che servono i fronti di discesa e di salita dei passi attivati, ovviamente per distinguere e far si che i fronti vengano sfruttati nella sequenza dei passi non devono essere interbloccati da condizioni inutili, insomma lo sviluppo di passi deve essere snello e sicuro, daltronde il classico esempio di un traslatore orizzontale e verticale che lavorano insieme, ognuno dei due che per posizionarsi in un dato punto aspetta sempre prima di muoversi l'arrivo dell'altro nella poszione da raggiungere, prima uno e poi l'altro, quindi il fronte di discesa di una movimentazione fa attivare quella successiva dell'altro traslatore.

@step-80 con i fronti di salita e discesa con Mitsubishi non hai di questi problemi anzi è quasi un divertimento

Link al commento
Condividi su altri siti

È un mio limite , e forse non ho usato cosi tanto le fb da conoscerle bene. 

Ma non capisco il senso di usare una fb per puntare ad una variabile di un altro fb. Comodo è comodo, non lo metto in dubbio..ma non ci arrivo fino in fondo. 

 

Con che sintassi accedo poi alla variabile?   <nomedbdiistanza>.<nomevariabile>? 

 

@Cesare Nicola 

 

il mio dubbio riguarda una fb richiamata con piu istanze. 

 

 

Link al commento
Condividi su altri siti

Personalmente, sia che le due (o più) sequenze siano in FB distinte, sia che siano all'interno della stessa FB, io preferisco un "handshake completo": una sequenza dà il comando all'altra sequenza, ed attende la risposta. Quando ricevo la risposta, proseguo. Certo, la risposta si può considerare con il ritorno OFF della richiesta stessa. È una questione puramente personale. Io preferisco tenere separati i bit.

Poi, questi bit, possono essere dichiarati come parametri IN e OUT (o anche INOUT), oppure possono semplicemente essere dichiarati nelle STAT. Generalmente, decido in base alla quantità: se sono pochi uso IN e OUT, se sono molti li dichiaro nelle STAT. Se li dichiaro nelle STAT, li metto all'interno di una struttura dedicata allo scambio di segnali, magari separando anche le variabili in uscita da quelle in entrata.

Link al commento
Condividi su altri siti

@batta

 

Per capire..o meglio per conferma.

Creo una FB e una FC con all'interno lo stesso identico codice, supponiamo un marcia/arresto con autoritenuta..

Dichiaro in entrambi i casi come IN_OUT(per comodità) una struttura contenente le seguenti variabili:

 

Start,

Stop,

BobinaMotore.

 

Quindi nelle mie VAR_IN_OUT avrò 

DatiMotore : StrutturaDatiMotore;

 

Richiamo il blocco FB: mi viene richiesto di assegnare un DB di istanza e procedo.

Il mio DB lo chiamo per esempio Blocco_Autoritenuta_1.

A questo punto non sono obbligato a dichiarare un'altra variabile di tipo 'StrutturaDatiMotore' da assegnare all'ingresso del blocco , giusto? Perchè una caratteristica fondamentale dell'FB è quella di avere un DataBase in pancia già di suo, quindi posso accedere ai dati come 

Blocco_Autoritenuta_1.Start

Blocco_Autoritenuta_1.Stop

Blocco_Autoritenuta_1.BobinaMotore.

 

Cosi come se avessi 'n' blocchi da richiamare potrei creare:

Blocco_Autoritenuta_1;

Blocco_Autoritenuta_2;

Blocco_Autoritenuta_3;

Blocco_Autoritenuta_4;

Blocco_Autoritenuta_5;

...

Blocco_Autoritenuta_100.

 

Diverso il caso nel quale richiamo l'FC. Non mi viene creato nessun DB di istanza e quindi sono costretto a dichiarare 'n' Strutture dati da passare all'ingresso del blocco stesso , se voglio richiamarlo 'n' volte. Cioè , sono sempre costretto ad appoggiarci dei dati e non posso accedere ai suoi dati interni. 

 

E' questa la sostanziale differenza fra FC ed FB? 

 

 

 

 

 

 

Modificato: da step-80
Link al commento
Condividi su altri siti

1 ora fa, step-80 scrisse:

E' questa la sostanziale differenza fra FC ed FB? 

Forse hai fatto un giro un po' lungo, ma direi di sì.
Molto più semplicemente, nelle FB ci sono le variabili STAT, nelle FC no. Tutto il resto è una conseguenza di questa differenza.

Link al commento
Condividi su altri siti

15 ore fa, batta scrisse:

Molto più semplicemente, nelle FB ci sono le variabili STAT, nelle FC no. Tutto il resto è una conseguenza di questa differenza.

Mi correggo:
Nelle FB ci sono le variabili STAT e il DB di istanza, le FC non hanno né STAT, né DB di istanza. Tutto il resto è conseguenza di queste differenze.

Link al commento
Condividi su altri siti

Cesare Nicola
il 28/9/2019 at 14:46 , step-80 scrisse:

Ma non capisco il senso di usare una fb per puntare ad una variabile di un altro fb.

Ero assente, ma Batta ti ha già risposto.

 

Adesso mi concedo un piccolo sfogo. Io sarò pure noioso quando insisto sull'ordine e la pulizia

il 28/9/2019 at 10:27 , Cesare Nicola scrisse:

è questione di usare metodo, ordine, pulizia e commenti

Però poi mi trovo a dover fare teleassistenza a un software e vedo, dopo un bel po' che mi scervello:

 

IF Modo = 1 THEN Variabile := 100; END_IF;
IF Modo = 3 THEN Variabile := 200; END_IF;
IF Modo = 2 THEN Variabile := 300; END_IF;

(codice semplificato, per rendere l'idea)

 

Colpa mia non essermene accorto subito, per carità, però sei lì a guardare un software che non conosci nel quale già ti orienti a fatica e d'istinto, se Modo è = 2 mi aspetto che Variabile sia = 200, invece no.

Non scaglio la prima pietra perché non sono certo senza peccato, ma lo porto come esempio di come si possa a volte perdere tempo per una banalità. 

Link al commento
Condividi su altri siti

Io sono forse ancora peggio, se scrivo in ST sto li a spostare la tabulazione per rendere tutto più leggibile. 

Per far capire, se devo scrivere:

 

Pippo:=Pluto-3; 

IF Consenso THEN Tizio:=Caio/2; FaseCiclo:=50; END_IF; 

 

Già vedere una roba cosi mi da fastidio. Nella mia (poca) logica celebrale, devo vedere una cosa del genere se voglio che il flusso mi sia chiaro:

 

Pippo                          :=(Pluto-3); 

 

IF Consenso THEN

     Tizio                      :=Caio/2;

     FaseCiclo             :=50;

END_IF; 

 

Quote

IF Modo = 1 THEN Variabile := 100; END_IF;
IF Modo = 3 THEN Variabile := 200; END_IF;
IF Modo = 2 THEN Variabile := 300; END_IF;

Anche vedere una cosa cosi mi farebbe venire l'orticaria.

 

Molto meglio:

 

CASE Modo OF

 1: //Vattelapesca

     Variabile := 100; 

 

2: //Vattelapesca

     Variabile := 200; 

 

 

3: //Vattelapesca

     Variabile := 300; 

END_CASE;

Link al commento
Condividi su altri siti

CASE, questo "strano" costrutto! Ho visto programmatori farne un uso smodato, ed altri non usarlo mai.
Nel caso in questione, è sicuramente la scelta migliore.

 

Per le tabulazioni, mi accontento di quelle di default, lasciando però sempre uno spazio tra gli operatori e le variabili.

 

Pippo := (Pluto-3); 

IF Consenso THEN
     Tizio := Caio / 2;
     FaseCiclo := 50;
END_IF;  

 

E non dimentichiamo che, nella 15.1 (non so se anche nella 15), sono possibili, come in C, scritture di questo tipo:

#Pippo := #Pluto := #Paperino := 1234;
#Pippo += 1;
#Pluto -= 10;
Paperino *= 2;

 

Modificato: da batta
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...