Vai al contenuto
PLC Forum


Bit Shift 'Lungo'


step-80

Messaggi consigliati

Buongiorno a tutti

 

probabilmente mi sto perdendo in un bicchiere d'acqua, ma sono 2 giorni che ci sbatto la testa e non trovo una soluzione che mi piace. 

Supponiamo di dover eseguire uno shift register.

Ho una macchina con 38 stazioni di lavoro,ogni stazione lavora 2 pezzi alla volta. Quando i primi 2 pezzi vengono caricati nella prima stazione, inserisco le informazioni nei bit 0 e 1 del registro(in questo caso W0.0 e W0.1).

Quando i pezzi vengono traslati alla stazione successiva eseguo lo shift di 2 posti a sinistra per cui le informazioni caricate prima me le ritrovo nei bit W0.2 e W0.3...e fin qui ok. 

 

Problema: Le stazioni sono 38, quindi abbondantemente sopra una Word e sopra una DWord(per quest'ultima in Mitsubishi fra l'altro non esiste istruzione di shift)

 

Dovendo lavorare con almeno 3 Word consecutive per poter seguire l'informazione sino allo scarico pezzi(quindi stazione Nr 38...W0,W1 e W2) ho fatto delle prove e sono riuscito a traslare il bit alto dalla word 1 alle word 2 e 3 in questo modo: 

BitShift1.thumb.png.e0963da4112c150514ff4a55452bc869.png

Testato in simulazione e funziona, ma volevo chiedere a voi esperti se c'era un modo più semplice per farlo o se sono andato ad incartarmi.

 

Vi ringrazio anticipatamente 

Matteo

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


Le operazioni di shift SHL e SHR operano sia su Word che su DWord, a seconda del tipo definito per la variabile da shiftare. Ovviamente devi lavorare in simbolico (label) e non in assoluto (device). Parlo dello FX5U, quindi del GX3. Purtroppo non hai specificato che tipo di PLC

Il problema per fare una elegante funzione di shift tra più word è che purtroppo il dato dei bit estremi (bit 15 per la SHL e bit 0 per la RHL) non è automaticamente riportato in un flag (contrariamente agli Omron dove tale bit viene masso nel Carry CY e può essere quindi utilizzato, oppure si possono usare istruzioni su multiple word).

Facci sapere su che PLC operi e magari si studia una funzione apposita.

Link al commento
Condividi su altri siti

Buongiorno Ctec e grazie per la risposta. 

 

Scusa non ho specificato di usare GxWorks2 con Una CPU serie Q . Hai ragione esiste l'istruzione SHL o SHR ed operano a 32 bit. 

Quella usata da me (SFL) opera a 16 solamente. 

 

Parli di Carry flag, sull'. ho trovato questa dicitura che non mi sapevo spiegare: 

BitShift2.thumb.png.ddccd1354d11f1f98aec76daaf2318af.png

Può servire al caso mio?

 

Ti ringrazio ancora

 

 

 

Link al commento
Condividi su altri siti

Io ho buttato giù un esempio in linguaggio strutturato di come si potrebbe fare con Siemens. Cambierà leggermente la sintassi, ma il concetto rimane.

IF #Trigger THEN
    #Trigger := FALSE;
    #W2 := SHL_WORD(IN := #W2,
                    N := 1);
    #W2.%X0 := #W1.%X15;
    #W1 := SHL_WORD(IN := #W1,
                    N := 1);
    #W1.%X0 := #W0.%X15;
    #W0 := SHL_WORD(IN := #W0,
                    N := 1);
END_IF;

Ma non hai la possibilità di lavorare direttamente su un array di bit anziché sulle word?

Link al commento
Condividi su altri siti

In ladder diventerebbe così:

image.png.5c39ea8ffb945def0ccebc4b326c87e3.png

Perché funzioni, devi elaborare le istruzioni solo quando c'è il trigger. Potresti quindi metterle all'interno di un blocco, o mettere un salto prima del segmento.

 

Link al commento
Condividi su altri siti

Mi era sfuggito che fai lo shift di due posizioni. Basta che copi il bit 14 nel bit 0 della word successiva, e il bit 15 nel bit 1.

IF #Trigger_2 THEN
    #Trigger_2 := FALSE;
    #W2 := SHL_WORD(IN := #W2, N := 2);
    #W2.%X0 := #W1.%X14;
    #W2.%X1 := #W1.%X15;
    #W1 := SHL_WORD(IN := #W1, N := 2);
    #W1.%X0 := #W0.%X14;
    #W1.%X1 := #W0.%X15;
    #W0 := SHL_WORD(IN := #W0, N := 2);
END_IF;

 

In sostanza, non è molto diverso da quello che già hai fatto tu. Solo che in strutturato mi pare più pratico e più semplice rispetto al ladder.

Modificato: da batta
Link al commento
Condividi su altri siti

Eccomi. Quindi, un Q, e GX2, allora ti suggerirei una soluzione più carina che è la seguente (non perché la tua non lo sia, ma perché qui per esempio si può impostare il numero di bit da shiftare...). Nel GX3 potremmo fare una routine molto più universale, ma qui no.

Eccola qui:

image.png.f519b8c1e3b44a72e2ea8a4749769157.png

Nel ciclo FOR è specificato il numero di bit da shiftare (nel nostro caso 2).

L'ho fatto in ladder per praticità, poiché lo SFC (o FDB per altri...) mi sta profondamente sulle scatole.

Link al commento
Condividi su altri siti

@batta : grazie per il tuo esempio. Indipendentemente dal linguaggio utilizzato, volevo capire se esisteva un modo totalmente diverso per fare la stessa cosa o se ero sulla strada giusta. 

Da quanto capisco, il sistema sta nello shiftare partendo dall'ultima word interessata(nel tuo esempio la nr 2) ; successivamente si copia lo stato del 15mo bit della word precedente nel 1mo bit della word appena shiftata e cosi via in cascata. Dico bene? 

Una cosa che non c'entra nulla: Ho sempre pensato che quando entro in una istruzione che è lanciata da un Trigger(come nel nostro caso) il reset del Trigger fosse sempre l'ultima cosa da fare ...invece vedo che è la prima cosa che fai appena hai la condizione di entrata. Non capisco se è una cosa che si può fare solo in ST , perchè mi sembra di ricordare che qualche tempo fa ho fatto una parte di programma in ladder il quale non funzionava a dovere proprio perchè azzeravo la condizione di entrata NON per ultima cosa. Ha senso quello che dico? Al tempo ho pensato che le istruzioni non venissero eseguite in una sola scansione ma venissero in qualche modo 'appoggiate' in una memoria interna per essere continuate al ciclo successivo; con questo mi sono spiegato il fatto che al ciclo successivo appunto, trovando la condizione di entrata a Zero, le istruzioni venissero saltate. 

 

@ctec: Grazie anche per il tuo esempio: complimenti per l'uso di un ciclo FOR in ladder, non ne avevo mai visto uno😊.

Per quanto riguarda il tuo codice, non ho la minima idea di cosa sia il 'Carry Flag' (SM700) e soprattutto in che condizioni si attivi. Ho capito che è un bit di sistema e che ha a che fare con gli shift ...per caso memorizza l'ultima posizione raggiunta dopo lo shift?

 

Link al commento
Condividi su altri siti

Il Carry (o Riporto in italiano) è usato nei sistemi di calcolo per memorizzare per esempio un overflow di un'operazione matematica quale una somma (CY=1 se la somma eccede il massimo valore memorizzabile nella variabile) o anche dalle operazioni di shift per "salvare" lo stato di un bit fatto shiftare ma che potrebbe essere utile.

Se per esempio fai lo shift  sinistra di una word, il bit 15 viene messo nel carry CY, i bit da 0 a 14 vengono spostati a sinistra, il bit 0 viene messo a 0 (su altri PLC alcune istruzioni permettono di decidere cosa scrivere nel bit 0). Ed è proprio quello che ho fatto dentro il ciclo FOR. Il Carry dello shift della word più bassa viene messo nel bit 0 della word già shiftata della word più alta.

Quindi non memorizza l'ultima posizione raggiunta dallo shift, ma il contenuto prima dello shift del bit più a sinistra (a destra se usi uno scorrimento a destra). Questo proprio per poter fare "cascate" di shift per quante word vuoi senza perdere informazioni. 

Link al commento
Condividi su altri siti

Quote

successivamente si copia lo stato del 15mo bit della word precedente nel 1mo bit della word appena shiftata e cosi via in cascata. Dico bene?  

Sì, esatto. Nel tuo caso poi, che fai uno spostamento di due bit, copi il penultimo e l'ultimo bit di una word nel primo e nel secondo bit di quella successiva.

Oppure, come nell'esempio di "Ctec", esegui lo shift N volte, col vantaggio di avere un codice che non è vincolato al numero di bit da far scorrere.
In Siemens l'interrogazione diretta dei bit di stato (come il CY), purtroppo si può fare solo in AWL.

 

Quote

Ho sempre pensato che quando entro in una istruzione che è lanciata da un Trigger(come nel nostro caso) il reset del Trigger fosse sempre l'ultima cosa da fare ...invece vedo che è la prima cosa che fai appena hai la condizione di entrata.

Nel caso in questione è assolutamente ininfluente resettare il trigger subito o alla fine.

Link al commento
Condividi su altri siti

Propongo una soluzione molto più banale anche se un po' diversa nell'uso degli operandi utilizzati,

Non so sei sei obbligato a usare le Word ma Mitsubishi da anche la possibilità di utilizzare le memorie interne come memorie a bit in numerazione progressiva totalmente decimale,

le cosiddette M, perciò se devi utilizzare 58 bit consecutivi che diventano Veri (ON) basta che ti allochi 58 memorie M consecutive come vuoi e tramite i registri indice fai lo shift dei bit con semplici istruzioni RESET e SET al momento in cui hai l'impulsivo del cambio passo, l'incremento del registro indice ti fa l'incremento del passo. In pratica all'arrivo dell'impulsivo fai il RESET dei bit attualmente attivi, incrementi il registro indice di 2 visto che hai due fasi consecutive attive e in ultimo fai il SET dei bit successivi richiamati direttamente dal registro indice Z0.

Guarda un po' non so se è quello che cerchi e se puoi utilizzare le memorie M:

PS: Non ho aggiunto che il registro indice Z0 andrebbe in qualche maniera tamponato appoggiandolo a un registro D ritenitivo, in modo che in caso di mancanza alimentazione non perdi il punto del passo attivo

 

765764805_shiftbit.thumb.jpg.1b1b6941772331c39cb67cc26872475b.jpg

Link al commento
Condividi su altri siti

@leleviola: Cavolo alla tua soluzione io non ci pensavo nemmeno. L'ho appena testata ed effettivamente è molto valida: Mi permetterebbe di dichiarare un Array di bit della dimensione che voglio (adesso che ci penso mi era stato suggerito anche da Batta) e di gestire il tutto con dei semplici Merker. Unica cosa forse è che sono legato ai registri indice , che se non sbaglio sono limitati. O meglio, potrei usare sempre anche solo Z0 purchè prima dell'istruzione venga inizializzato al valore che aveva alla fine dell'istruzione precedente...e per fare ciò dovrei appoggiarlo a delle memorie retain. Sbaglio?

 

Ho provato a fare un mix tra quanto suggerito da Ctec e quanto da Leleviola e secondo me ne è uscito qualcosa di interessante.

L'istruzione BSFL esegue lo shift di 1 bit a sinistra dell'area M. Purtroppo non è possibile specificare quanti bit ma poco male: con un ciclo FOR si ripete per N volte ed il gioco è fatto.

BitShift3.thumb.png.aa976301e5ec02ffabfffb2269b35c3a.png

Mi fa ancora strano usare un ciclo FOR in Ladder(non che ne usassi molti nemmeno in ST..) ma credo che faccia al caso mio. 

 

Ringrazio tutti per il contributo, siete 1000 volte meglio di qualsiasi Support internazionale😃

 

 

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

Le istruzioni FOR ... NEXT in ladder le ho usate tantissimo soprattutto abbinate ai registri indice, anzi diciamo che sono quasi fatte per quello ed è una delle peculiarità utili dei registri indice con Mitsubishi.

A proposito puoi si usare un solo registro indice nel tuo caso non è necessario che ne usi altri, poi fai tu come ti trovi meglio,

limiti dei registri indice? Non ricordo ma mi sembra di ricordare che sono trattati come semplici INT interi, perciò i limiti sono quelli tipici -32768 a + 32767,

come ti dicevo meglio se il valore che poi carichi nel registro indice se lo appoggi a un registro retain, o meglio l'incremento del valore lo fai sempre sul registro retain poi fai un MOVE sul regsitro indice nel momento opportuno per poterlo utilizzare quando serve

 

Link al commento
Condividi su altri siti

Quote

Perdonami se insisto...ma perchè è ininfluente in questo caso? In quale caso invece sarebbe influente?

Perché lo stato del trigger non è più interrogato all'interno del IF-THEN-ELSE. Non è importante quindi quando viene resettato.
Dopo l'IF viene letta come vera la condizione (Trigger = TRUE), quindi vengono eseguite le istruzioni dopo il THEN, indipendentemente dallo stato che assume successivamente la variabile Trigger.

 

Per quanto riguarda invece l'esempio di "Leleviola", se non interpreto male qualche istruzione, non mi pare che sia un vero e proprio shift-register. Mi pare che imposti OFF il bit puntato da Z0 e quello successivo, poi Z0 viene incrementato di due unità, e viene settato il bit puntato ora da Z0 e il bit successivo.
Ad ogni clock questi due bit avanzano, ma avanzano solo loro, non tutti i bit del registro. Nel registro devo poter avere altri bit alti, e tutti devono avanzare. Anzi, devono avanzare anche i bit a zero. Inoltre devo poter impostare lo stato dei primi due bit del registro.

 

In passato avevo costruito una funzione ottimizzata per fare lo shift di registri molto lunghi (probabilmente, da qualche parte sul forum si trova ancora. Se a qualcuno interessa, la posso pubblicare nuovamente). Si tratta però di una soluzione per Siemens, fatta in AWL. Dovrei convertirla in testo strutturato per renderla adattabile anche ad altri PLC. Non l'ho mai fatto perché, ora, è diventato molto più facile lavorare con gli array, e non ho più avuto bisogno di gestire shift alla "vecchia maniera".

 

Da considerare poi che, molto spesso, al posto di uno SHIFT si può utilizzare un FIFO. Il FIFO è generalmente gestito in due maniere: la prima, concettualmente più semplice, prevede lo scorrimento di tutti gli elementi del FIFO (poco efficiente nel caso di registri FIFO lunghi); la seconda, gestisce invece degli indici per sapere dove andare a scrivere i nuovi dati e da dove estrarre quelli più vecchi. Appena un po' più difficile da costruire, ma molto più efficiente, perché agisce sempre solo sull'elemento direttamente interessato, e due variabili di indice.

 

Per Siemens, esiste un FIFO molto ben fatto in "LGF Library". Si tratta di una libreria gratuita (per scaricarla però bisogna registrarsi sul sito Siemens), aperta e fornita di documentazione, che contiene molte cose utili.

Modificato: da batta
Link al commento
Condividi su altri siti

1 ora fa, batta scrisse:

Per quanto riguarda invece l'esempio di "Leleviola", se non interpreto male qualche istruzione, non mi pare che sia un vero e proprio shift-register. Mi pare che imposti OFF il bit puntato da Z0 e quello successivo, poi Z0 viene incrementato di due unità, e viene settato il bit puntato ora da Z0 e il bit successivo.
Ad ogni clock questi due bit avanzano, ma avanzano solo loro, non tutti i bit del registro. Nel registro devo poter avere altri bit alti, e tutti devono avanzare. Anzi, devono avanzare anche i bit a zero. Inoltre devo poter impostare lo stato dei primi due bit del registro.

Si si è vero il mio esempio serviva solo a far capire banalmente come agire in maniera alternativa, lo scorrimento dei bit attivi lo puoi fare anche con l'uso dei registri indice puntando sempre al medesimo operando iniziale e scorrendo progressivamente l'operando attivo tramite il registro indice che è quello che determina l'unico o gli unici bit attivi nel caso in analisi, poi uno il programma se lo fa come vuole, non è proprio uno shift-register ma perlomeno non sei obbligato a gestire i bit all'interno di una word e doverne adottare le varie contromisure nel passaggio da una word all'altra. Ovviamente il limite non da poco in questo esempio si ha attivi un solo bit o due soli bit per volta e quindi non è uno shift-register di tutti gli altri bit che si vanno a considerare.  Si è vero tramite l'uso degli array l'uso si riesce a fare cose egregie senza troppe difficoltà e l'uso dell'ostico AWL

Modificato: da leleviola
Link al commento
Condividi su altri siti

Quote

Si è vero tramite l'uso degli array l'uso si riesce a fare cose egregie senza troppe difficoltà e l'uso dell'ostico AWL

Per lavorare con gli array il testo strutturato è sicuramente il migliore (considerando i tre linguaggi standard dei PLC: ladder, lista istruzioni, testo strutturato).

In casa Siemens, con il TIA, l'editor del testo strutturato va molto bene (infinitamente meglio di quello del "vecchio" S7) e, rispetto al suo predecessore, anche l'editor del ladder è molto più pratico. Questi miglioramenti degli editor, uniti alla nuova filosofia Siemens che tende ad abbandonare l'AWL, comporta che l'AWL stia cadendo in disuso. Però un po' mi dispiace perché, per certi compiti,  è il migliore. Ostico lo diventa solo quando lo si vuole usare in modo improprio, convertendo pari pari segmenti fatti in ladder, o scrivendo cose illeggibili con parentesi a non finire.

 

Link al commento
Condividi su altri siti

il 10/2/2019 at 11:01 , batta scrisse:

Perché lo stato del trigger non è più interrogato all'interno del IF-THEN-ELSE. Non è importante quindi quando viene resettato.

Questa è una peculiarità del linguaggio strutturato presumo..

perchè se uso in ladder la classica tecnica  batch ( set/reset ) dove ho:

SE stato attivo AND transizione: Set stato successivo , Rst stato attivo....invertendo questi ultimi 2 operandi non funziona più. 

Dico una castroneria? O dipende solo da come viene convertito il codice in linguaggio macchina?

Link al commento
Condividi su altri siti

Roberto Gioachin

Che sia in Ladder, in ST, in FDB o in IL non cambia nulla. Mitsubishi, come molti altri, compila il programma scritto in uno di questi linguaggi in un linguaggio proprietario che è sovrapponibile a IL, quindi dopo che la variabile di trigger viene interrogata, non ha più nessuna importanza il suo stato fino alla scansione successiva. Se invece la variabile di trigger viene interrogata anche per le operazioni successive, allora bisogna fare attenzione a non modificarne lo stato.

Risulta utile verificare il compilato per capire bene cosa succede, certo ci vuole un po' di conoscenza dell' Instruction List  Mitsubishi.

 

Link al commento
Condividi su altri siti

 

Avete perfettamente ragione, ho fatto delle prove ed è proprio come dite voi.

Non so perchè ma ero assolutamente sicuro di aver avuto dei problemi una volta per questa cosa, sicuramente era per altro che il programma si piantava...

 

Comunque sia, questo è come traduce Mitsubishi quello che viene editato:

 

BitShift4.thumb.png.263e21c57d49cd6298d301b754be840f.png

 

Come si può vedere, nel caso di comparazioni il risultato viene appoggiato su un merker (M15358 in questo caso) che è poi usato per eseguire le operazioni successive.

 

Scusate ma preferisco passare per ignorante ora e capire piuttosto che far finta di sapere tutto e poi cadere dal pero..

Grazie ancora a tutti e buona serata!

 

 

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