Vai al contenuto
PLC Forum


Come Scrivere/leggere Dati Di Un Array


autojac

Messaggi consigliati

Salve, sto usando per la prima volta gli array con Step 7, e soprattutto con il linguaggio Assembly.

Ho un semplice vettore di pochi elementi, per fare una prova, diciamo 10. Quindi nel DB2 ho un Array[0..9] di real.

Ora dovrei fare un banalissimo ciclo per riempire in scrittura il vettore (stessa cosa per la lettura). Al di la del ciclo comunque, qual'è la sintassi corretta per leggere/scrivere un dato nell'array??

Se io scrivo in questo modo:

AUF DB 2

L DB1.DBD 0

T DB2.DBD 0

riesco a copiare il valore nel primo elemento dell'array. E cosi via per gli altri elementi..

Però come posso usare indici relativi??

Mi rendo conto che devo stare attento agli indirizzi delle variabili interne all'array. Ovvero di non usare come si farebbe con lo pseudocodice, una cosa del genere array con i che varia da 0 a 9. Ma che in quella i, credo, ci vada l'indirizzo ovvero, da 0 per il primo elemento, 4 per il secondo, 8 per il terzo..etc (essendo real).

Ho provato una cosa del genere:

L #i // num elemento corrente

L 1

-I // num elemento meno 1

L 4 // moltiplico per 4 per avere il giusto indirizzo

*D

T MD 0 // trasferisco il valore calcolato in una md

L 2

T MW0

AUF DB[MW0] // apro il vettore

L "misure".sim_misura

T DBW [MD 0] // trasferisco il valore nel vettore

ma non funziona...

:(

MI chiedo...sto sbagliando qualcosa a livello di sintassi.. o sbaglio proprio concettualmente???

Modificato: da autojac
Link al commento
Condividi su altri siti


Sbagli quasi tutto.

L'impressione è che tu non abbia perso nemmeno un minuto per leggere il manuale e capire come lavorano i puntatori di questo plc.

Ti consiglio di consultare il manuale, e scrivere di nuovo quando avrai un codice che almeno si avvicini a quello corretto.

Modificato: da batta
Link al commento
Condividi su altri siti

Salve,

nel codice da te compilato, si evidenziano alcuni errori di cui uno importante che potrebbe mandarti in STOP la CPU se il valore assunto non rientra negli indirizzi progettati nell'ARRAY di dati, sto parlando della variabile temporanea "#i".

MI chiedo...sto sbagliando qualcosa a livello di sintassi.. o sbaglio proprio concettualmente???

Sia l'una che l'altra........

Ho sistemato alcune parti del codice, inserendo dei commenti nei punti in cui c'erano degli errori o cose che comunque sarebbero da sistemare.

Quindi non ho modificato di molto quello che tu hai scritto, anche se il codice e le istruzioni così come sono usate, hanno un ampio margine di miglioramento mediante l'utilizzo del registro AR1 per indirizzamenti di tipo indiretto.

Altra cosa, forse già lo saprai forse no, ma nel caso in cui tu debba effettuare azzeramenti,inizializzazioni a valori definiti, oppure copiare aree dati da una sorgente ad una destinazione, ci sono nelle librerie di sistema le funzioni SFC21 [FILL] e la SFC20 [bLKMOV].

Lascio a te il compito mediante l'utilizzo dell'aiuto in linea [F1], di leggere la descrizione di queste funzioni.

Inoltre come postato da batta nel suo messaggio, se proprio non hai aperto il manuale o anche il solo aiuto in linea di S7, penso sia doveroso farlo o rileggerlo nuovamente, almeno per le parti relative all'utilizzo dell'indirizzamento di tipo indiretto.

//Attento se la variabile "i" è <0 ed >10 sballa tutto!!!!
//Cioè vai a scrivere su aree di indirizzi inesistenti e la CPU va in STOP.
//Quindi devi fare un minimo di controllo in modo che la variabile di indirizzo 
//rimanga nei campi delle 10 Word in formato REAL definite nell'ARRAY.


      L     #i                          // num elemento corrente 
      L     1
      -I                                // num elemento meno 1
      L     4                           // moltiplico per 4 per avere il giusto indirizzo

//l'istruzione sottostante prima eseguiva una moltiplicazione per numeri a 32 bit 
//quando i calcoli precedenti sono a 16 bit,con Siemens il tutto deve avvenire nell'
//esatto formato di rappresentazione.Inoltre il valore deve essere preparato nel formato puntatore   
//mediante l'uso di SLW3. In relazione ai puntatori esistono comunque altre istruzioni
//tipo P##[..... ed AR1 che si prestano meglio a questo tipo di compiti.
      *I    
      SLW   3                           // prepara il dato in formato puntatore
      T     MD     0                    // trasferisco il valore calcolato in una md 

      L     2
      T     MW     4
      AUF   DB [MW 4]                   // apro il vettore

      L     "misure".sim_misura

//Dal tuo post parli di trasferire dei dati definiti in REAL 
//Nel codice sottostante, il formato precedentemente era scritto con una sintassi  
//equivalente ad una Word [16bit] e non per un REAL o DINT [32bit]
      T     DBD [MD 0]                  // trasferisco il valore nel vettore avente offset indirizzo in MD0

Modificato: da cagliostro
Link al commento
Condividi su altri siti

altra cosa che ho dimenticato, nel codice da te postato la parte:

L 2

T MW0

AUF DB[MW0] // apro il vettore

non è corretta, così facendo vai a scrivere il numero del DB in questo caso DB2, nella MW0 alterando il dato del puntatore definito in MD0.

Quindi ho assegnato per comodità a MW0 un 'altro indirizzo che non vada a sovrapporsi anche se in modo parziale a MD0.

Link al commento
Condividi su altri siti

Grazie Cagliostro per il tuo aiuto, e mi scuso per l'ignoranza. Immagino che per voi queste siano sciocchezze. Per me non lo sono.

ll manuale, su questo argomento, è molto confuso e aiuta poco un principiante, per non dire nulla. :angry:

Tornando all'esepmio. Ho corretto il codice secondo le tue indicazioni. Ora mi trovo di fronte a un problema, credo, di indirizzi inesistenti, (come mi avvertivi tu).

L #i // num elemento corrente

L 1

-I // num elemento meno 1

L 4 // moltiplico per 4 per avere il giusto indirizzo

*I

SLW 3 // prepara il dato in formato puntatore

T MD 0 // trasferisco il valore calcolato in una md

AUF DB2

L "misure".sim_misura

T DBD [MD 0] // trasferisco il valore nel vettore avente offset indirizzo in MD0

Inserisco manualmente e volontariamente i valori di "i" per controllare il processo.

Per i = 1 (primo valore dell'array) va bene. Per i=2 va bene. Per i=3 e superiori la cpu va in blocco.

Ricapitolando e osservando online i calcoli io ho:

per i=1 in MD 0 ci va 0 ((1-1)*4 )*8

per i=2 in MD 0 ci va 32 ((2-1)*4 )*8

per i=3 in MD 0 ci va 64 ((3-1)*4 )*8

e qui la cpu va in blocco. Ma è giusto che io vada a puntare l'array con questa successione di indirizzi ? DBD[0] DBD[32] DBD[64]....

Come si nota non mi è ancora ben chiaro l'utilizzo dei puntatori... :(

L 2

T MW0

AUF DB[MW0] // apro il vettore

si in realtà nel codice aprivo direttamente il db2. Questo era un residuo di copia e incolla da qualche parte..

Modificato: da autojac
Link al commento
Condividi su altri siti

..e mi scuso per l'ignoranza.

Non è necessario scusarsi, siamo tutti ignoranti. :)

Il forum serve proprio per aiutarci a vicenda a diminuire la nostra ignoranza.

Link al commento
Condividi su altri siti

Ma è giusto che io vada a puntare l'array con questa successione di indirizzi ? DBD[0] DBD[32] DBD[64]....

No non lo è.....

Ripartiamo dall'inizio, cioè dal tuo primo post.

Allora hai creato il DB2, che al suo interno contiene un Array di dati REAL (cioè 32 bit in virgola mobile) come da immagine a seguire.

immagineul.png

In questa immagine nel DB2 ho posto l'array come struttura di partenza, per cui il primo indirizzo della doppia word DBD sarà lo 0.

e le sucessive dell'array che contiene altre altre nove variabili avranno indirizzo:

DBD4...DBD8...DBD12...DBD16...DBD20...DBD24...DBD28...DBD32...DBD36...DBD36.

Puoi notare che il salto di indirizzo trà un dato è l'altro è di 4 byte in 4 byte cioè 32bit, per i formati di rappresentazione REAL,DINT,DWORD.

Se vuoi quindi scrivere il valore contenuto di volta in volta in DBD40, su una delle 10 doppie word che compongono l'array,

dovrai calcolarne l'indirizzo che poi viene preparato attraverso l'istruzione SLW3 in formato puntatore.

Quindi se il tuo valore "i" vale:

per "i"=1 ==>(1-1)*4=0 ovvero scrivi sulla DBD0

per "i"=2 ==>(2-1)*4=4 ovvero scrivi sulla DBD4

per "i"=3 ==>(3-1)*4=8 ovvero scrivi sulla DBD8

per "i"=4 ==>(4-1)*4=12 ovvero scrivi sulla DBD12

e così via........

in realtà tu hai interpretato l'istruzione SLW3 come una moltpilicazione per 8, ma in realtà lo scopo è quello di prendere il valore dell'indirizzo del byte (0,4,8,12 etc, etc,) e metterlo nella giusta posizione nella doppia word MD0, in modo che questo venga interpretato correttamente come puntatore all'indirizzo.

Se con il codice che ho postato in precedenza, usi un valore di "i" che va da 1 a 10 non di più e non di meno, andrai a scrivere nel tuo array di dati nel DB2 partendo dalla DBD0 alla DBD36, sempre che il tuo array abbia gli stessi indirizzi che io ho usato come nel DB2 allegato nell'immagine di cui sopra.

Ovviamente ribadisco che partendo dalla base del tuo codice di esempio, il tutto può essere ampiamente rimaneggiato è migliorato utilizzando altri set di istruzioni.

La cosa importante in questo semplice esempio che devi ricordare è quella di far si che il calcolo del puntatore deve contenere un indirizzo tale da far si che i dati vengano scritti dove ti aspetti.

Quindi attenzione alla variabile "i" che deve essere in sintonia con gli indirizzi delle variabili in cui trasferire i dati.

Modificato: da cagliostro
Link al commento
Condividi su altri siti

Grazie ancora per le sempre esaustive risposte. Il discorso dell'indirizzimanto dell'array è chiaro.. Fra l'altro il mio array, come hai fatto nell'esempio, parte da zero..quindi gli indirizzi corrispondono. Mentre in effetti l'espressione "prepara il dato in formato puntatore" non mi era del tutto chiara.

In ogni caso, ora, facendo delle prove, non riesco a capire, l'utilizzo proprio dell'indice "i".

per "i"=1 ==>(1-1)*4=0 ovvero scrivi sulla DBD0

per "i"=2 ==>(2-1)*4=4 ovvero scrivi sulla DBD4

per "i"=3 ==>(3-1)*4=8 ovvero scrivi sulla DBD8

per "i"=4 ==>(4-1)*4=12 ovvero scrivi sulla DBD12

E questo è chiaro. Però, andando in simulazione, e impostando i valori di i manualmente, da i=4 in poi (quindi quando dovrebbe leggere/scrivere all'indirizzo DB12) mi va in blocco la cpu. Sembra quindi che vado a puntare a un indirizzo inesistente. Se però il calcolo precedente dell'indirizzo e del puntatore è giusto... dove sbaglio???

Modificato: da autojac
Link al commento
Condividi su altri siti

niente. devo fare un errata corrige. Il problema sopra era dovuto a un controllo che facevo in modo sbagliato. Aprivo in un punto sbagliato la struttura. Ora riesco a scrivere correttamente il vettore...

Link al commento
Condividi su altri siti

.......nel tuo messaggio #5 scrivi:

Per i=3 e superiori la cpu va in blocco.

mentre nel post di oggi (messaggio #8), scrivi:

da i=4 in poi (quindi quando dovrebbe leggere/scrivere all'indirizzo DB12) mi va in blocco la cpu.

Sembra che da ieri ad oggi se imposti i=3 la CPU non vada più in STOP. Che cosa è cambiato?? Oppure trattasi solo di un errore di scrittura commesso in uno dei due post??

Per chiarezza di informazioni, allego immagine da dove potrai notare che eseguendo il codice in simulazione, impostando un valore superiore a 3 o 4, in questo caso 8 sulla merker word "i" con indirizzo MW10, la CPU non si arresta.

Inoltre nella parte destra dell'immagine, puoi osservare i valori che i vari registri etc. etc. assumono dopo le varie operazioni.

Nel caso di "i"=8 il risultato nella colonna denominata "standard" contiene il valore 28 che è il risultato di (8-1)*4 dopo lo spostamento a sinistra di 3 bit, il dato assume sempre in rappresentazione decimale il valore di 224.

Questo valore viene messo in MD0, che in una rappresentazione binaria a 32 bit avrà il seguente valore:

MSD==> 0000_0000 0000_0000 0000_0000 1110_0000 <==LSD

ora per comprendere bene la cosa dovresti aver visto come è costituita la struttura di un puntatore, comunque sappi che partendo dal bito meno significatico (LSD) i primi tre bit contengono il bit dell'indirizzo, mentre dal quarto bit al 19 bit (quindi per un totale di 16 bit) è contenuto il byte dell'indirizzo.

Ne consegue quindi che essendo a 0 i primi trè bit l'indirizzo del è .0 mentre quello del byte avrà valore 1110_0 corrispondente a 28.

Per cui l'indirizzo contenuto in MD0, nel quale si andrà a scrivere nell'array di DB2 risulterà il 28 byte del DB2 che corrispondente al nome Data[7] dell'Array.

Se ancora non hai capito e non hai risolto sarebbe il caso che tu inserissi il progetto s7 delle sole parti di codice interessate, quindi DB2, la FC in OB1 etc. etc. come allegato in modo da poterlo controllare.

Eventualmente proverei a fare anche questa cosa, potresti avere il contenuto di MD0 che risulta "sporco", quindi o riassegni velocemente un'altra MD mai usata oppure all'inizio del codice esegui un azzeramento di MD0 mediante l'istruzione, che comunque potrai notare sempre nell' immagine allegata.

L0

T MD0

...........

..............

................

immagineqk.png

Link al commento
Condividi su altri siti

....bene.

Come ti dicevo ieri, il codice di partenza da te creato e poi corretto, può essere un valido esempio di partenza per comprendere le basi iniziali sull'indirizzamenti di tipo indiretto.

Generalmente il passo sucessivo e quello poi di far uso di altre istruzioni che definiscono il formato pointer e fanno uso del registro AR1.

Per cui il codice di esempio che attualmente stai testando può prendere anche questa forma.

immagineyb.png

La cosa che salta subito all'occhio è:

il non utilizzo di merker (MD0) e quindi un "risparmio" dei medesimi.

Poi nella colonna AR1 relativa alla schermata online, risulta immediato il valore contenente l'indirizzo del tuo puntatore.

Più altre cose che comunque lascio a te scoprire, facendo la pratica del caso ed avendo la cura di consultare la documentazione di Siemens.

Quest'ultima anche sè a volte può risultare indigesta, con il tempo ti sarà più famigliare.

Modificato: da cagliostro
Link al commento
Condividi su altri siti

Ok. Ora mi sto esercitando e sto provando varie soluzioni.

Ti volevo chiedere un ultima cosa. Nel precedente esempio, io andavo a riempire l'array con dei valori. Quindi a scrivere.

Se dovessi invece leggere i valori dell'array (che sono real), al fine di elaborarli e salvarli in altri punti, il procedimento è sempre lo stesso giusto?

Faccio un loop, leggo il valore corrente, (eventualmente lo salvo da qualche parte), incremento l'indice, e cosi via...

Link al commento
Condividi su altri siti

si.....

basta invertire le seguenti righe di comando:

L DBD [MD 0]

T "misure".sim_misura

In definitiva la sorgente dei dati diventa il tuo Array che "pesca" il dato da leggere con L DBD [MD0] per trasferirlo alla variabile avente destinazione XXX.

Link al commento
Condividi su altri siti

Vorrei spiegare il perché di quell'istruzione "SLW 3" che, se non mi è sfuggito, è rimasta un po' nel limbo.

Bene. Basta tener presente che i puntatori in Step7 non puntano al byte ma puntano al bit.

Con operazioni su byte, word e dword si deve puntare al primo bit della variabile.

Nei casi riportati negli esempi, si potrebbe anche evitare di effettuare due operazioni

L #i

L 1

-I

L 4

*I

SLW 3

e basterebbe scrivere:

L #i

+ -1

SLW 5

E, ad essere pignoli (anche se il risultato non cambia fino a quando l'indirizzo non supera 65535), sarebbe più corretto scrivere SLD 5 al posto di SLW 5.

Link al commento
Condividi su altri siti

  • Alessio Menditto locked this discussione
Ospite
Questa discussione è chiusa alle risposte.
×
×
  • Crea nuovo/a...