Vai al contenuto
PLC Forum

Partecipa anche tu alla Live su Youtube martedì 28/01/2025 per festeggiare i 24 anni di PLC Forum

Per ulteriori informazioni leggi questa discussione: https://www.plcforum.it/f/topic/326513-28012025




Array Parametrizzato


Messaggi consigliati

Inserito:

Scusate la mia probabile ignoranza :blink: sull'argomento se pongo questo quesito: non è possibile indicizzare un array di dati ( o di strutture di dati), contenuto in una DB strutturata ad hoc, con indici che possano essere richiamati con parametro (per esempio struttura di informazioni su una serie di oggetti, e richiamo in modo parametrico della struttura associata all'i-esimo oggetto)?

Grazie per la disponibilità di tutti :rolleyes::rolleyes::rolleyes:


Inserita:

..spero di aver interpretato correttamente quallo che intendi. Tu vorresti avere un vettore dal quale richiamare le variabili interne alla struttura tramite un indice (anch'esso una variabile)? del tipo #C?

dim array[1..10]

L array[n]

non mi risulta sia possibile un accesso alla struttura di questo tipo

Inserita:

Se ho capitop bene dovresti indicizzare un parametro any , questo è possibile.

Chiaramente la lunghezza del parametro any deve coincidere con il tuo array.

Inserita:

MI RENDO CONTO DI NON ESSERE STATO PER NULLA CHIARO (POCHE IDEE MA CONFUSE..), E QUINDI MI SPIEGO CON UN ESEMPIO. DATA LA SEGUENTE DB (DI ESEMPIO), SE HO UN INDICE I VARIABILE (PARAMETRICO) POSSO ACCEDERE AL DATO par0 (OPPURE par1 ECC.) DELL'I-ESIMO CAMPO DELLA STRUCT?? (NB: SONO BOOL)

DATA_BLOCK DB 230

TITLE =

VERSION : 0.1

STRUCT

OrdineIndice : ARRAY [1 .. 100 ] OF //Variabile jolly provvisoria

STRUCT

par0 : BOOL ;

par1 : BOOL ;

par2 : BOOL ;

par3 : BOOL ;

par4 : BOOL ;

par5 : BOOL ;

par6 : BOOL ;

par7 : BOOL ;

par8 : BOOL ;

par9 : BOOL ;

par10 : BOOL ;

par11 : BOOL ;

par12 : BOOL ;

par13 : BOOL ;

par14 : BOOL ;

par15 : BOOL ;

END_STRUCT ;

END_STRUCT ;

BEGIN

END_DATA_BLOCK

Inserita:

dalle prove che ho potuto fare (anche perchè avevo la tua stessa esigenza), ho scoperto che non è possibile mettere una variabile (d tipo INT) come ndice dell'array (es: array[var], dove var è il tuo indice), ma puoi solo usare costanti (array[1], array[2]....) per accedere al valore dell'emento dell'array.

Se però usi una DB, puoi generarti una funzione e utilizzare i puntatori, sapendo la distanza da un elemento e l'altro

opn db10

dbw [ar1,p#0.0]

dove in ar1 ha prima caricato l'indirizzo (in bit) dell'elemnto da puntare.

es: per puntare a DB20.dbw10

L 10

L 8 (dimensione in byte)

*I

LAR1 (caricamento in registro AR1)

opn db10

L dbw [ar1,p#0.0] (AR1=80 e punterai a db10.dbw10)

Ciao

Inserita:

Ciao, visto che avevo la stessa necessità, ho preso al volo il tuo consiglio ma mi da errore su

L DBW[AR1,p#0.0]

Le righe prima sono ok ma su questa ho errore.

devo fare qualche dichiarazione a parte?

Ciao

Inserita:

Prova così:

L DBD [AR1,p#0.0]

Infatti credo sia necessario appoggiarsi ad una DWORD

Ciao

Matteo Montanari
Inserita: (modificato)
Prova così:

L DBD [AR1,p#0.0]

Infatti credo sia necessario appoggiarsi ad una DWORD

non è corretto, utilizzando un puntatore di tipo AR1 (o AR2) puoi fare le varie combinazioni:

U DBX [AR1,P#0.0]

L DBB [AR1,P#0.0]

L DBW [AR1,P#0.0]

L DBD [AR1,P#0.0]

se devi eseguire un caricamento oppure

= (S,R) DBX [AR1,P#0.0]

T DBB [AR1,P#0.0]

T DBW [AR1,P#0.0]

T DBD [AR1,P#0.0]

se devi eseguire un trasferimento

Ciao, visto che avevo la stessa necessità, ho preso al volo il tuo consiglio ma mi da errore su

L DBW[AR1,p#0.0]

Le righe prima sono ok ma su questa ho errore.

molto probabilmente ti segnava errore perchè scrivevi L DBW[AR1,p#0.0] e non L DBW [AR1,P#0.0]

(le nuove versioni correggono automaticamente l'errore di sintassi).

devo fare qualche dichiarazione a parte?

la dichiarazione devi farla se utilizzi un area di memoria e non il puntatore. supponendo di utilizzare lo stesso esempio di prima:

      L     10
      L     8                           // (dimensione in byte)
      *I    
      T     MD   250                    // (caricamento in registro MD250)
      AUF   DB    10
      L     DBW [MD   250]              // (MD250=80 e punterai a db10.dbw10)
è comodo utilizzare anche gli "offset" (P#0.0) ad esempio
      U     DIX [AR1,P#0.0]             // Legge stato Ingresso
      UN    DIX [AR1,P#4.0]             // Legge stato Appoggio Impulsivo
      X     DIX [AR1,P#2.0]             // Legge stato Uscita
      =     DIX [AR1,P#2.0]             // Scrive stato Uscita

Modificato: da keosmm
Inserita:

Nel problema iniziale non hai detto con quale linguaggio hai intenzione di programmare il blocco.

Esiste la possibilità di utilizzare il linguaggio di programmazione SCL (ma non è compreso nella licenza base di STEP 7) che consente di accedere alle DB dichiarate con strutture complesse semplicemente usando gli indici degli array.

Nel caso tu abbia tale possibilità ti consiglio comunque di non abusare di tale linguaggio di programmazione perchè nella compilazione l'AWL che ne risulta è tipicamente abbastanza pesante.

Se invece devi lavorare direttamente con AWL, l'unica strada è quella dei puntatori. In questo caso di consiglio di appoggiare l'intera struttura su una struttura locale gemella dell'originale e poi testare i bit che ti interessano. La soluzione è un po' più pesante ma ne guadagni in leggibilità

Ciao e buon lavoro.

  • 2 weeks later...
Inserita:

Ho seguito i vostri consigli anch'io e non da errore in AWL, ma devo ancora provarlo sul campo. Ho fatto però una variante, cioè una DB con tutti array come elementi. Secondo voi funziona lo stesso o mi devo aspettare che... :cussing: ... e devo rifare il pezzo di codice?

Grazie mille dell'aiuto

Matteo Montanari
Inserita:
Ho fatto però una variante, cioè una DB con tutti array come elementi. Secondo voi funziona lo stesso o mi devo aspettare che...

dai pochi dati che dai non possiamo certo sapere il risultato.

prova ad essere un pò più chiaro.

se mai se ci dovesse essere qualche problema nel codice non penso che dovresti risciverlo tutto di sana pianta.

utilizza delle variabili intermedie (mw o md) per sapere quale indirizzo stai puntando, controlla ed eventualmente modifica.

sbagliando si impara (a non sbagliare più nello stesso punto).

Inserita:

Ho creato una DB con trentuno elementi

UNO Array[1..3] of Time

DUE Array[1..3] of Time

..

..

TRENTA Array[1..3] of Time

PUNTATORE Int

L'ultimo elemento mi serve per tener memoria dell'ultima posizione scritta visto che voglio fare una coda circolare. Per l'indirizzamento ho scritto

CALL "TIME_TCK"

RET_VAL:=#Tempo

L "DB".PUNTATORE

L 1

+I

T "DB".PUNTATORE

..

..

L "DB".PUNTATORE

L 96

*I

LAR1

AUF "DB"

L #Tempo

T DBW [AR1,P#0.0]

Ovviamente se devo andare a scrivere nel secondo elemento o aggiungo 32 a AR1 o prendo P#4.0 visto che TIME prende 4 B, e 64 per il terzo elemento

A questo punto spero che funzioni. Se qualcuno ha già qualche dritta, sono ben accette, altrimenti tra un paio di giorni lo scarico in macchina e vedo se funge e poi vedo il da farsi.

Matteo Montanari
Inserita:

nel blocco dati tu hai una struttura di questo tipo:

00.0 uno[1]    TIME    T#0MS  
04.0 uno[2]    TIME    T#0MS  
08.0 uno[3]    TIME    T#0MS  
12.0 due[1]    TIME    T#0MS  
16.0 due[2]    TIME    T#0MS  
20.0 due[3]    TIME    T#0MS  

o è diverso ancora.

non riesco a capire la struttura dal tuo messaggio precedente, e non conoscendo la struttura del blocco dati, non posso verificare se il codice è corretto o meno.

Inserita:

Ciao, il tuo metodo il AWL mi sembra il più efficace, comunque se volessi semplificare il codice, questo sarebbe possibile utilizzando SCL, e strutturando il tuo DB in modo che sia un array[1..31] di STRUCT contenenti i 3 dati di tipo TIME. In questo modo potresti indicizzare direttamente l'array con una variabile di tipo INT e scorrerlo tramite un semplice ciclo FOR.

Inserita:

Ho creato una db così fatta

Indirizzo Nome tipo

0.0 UNO ARRAY [1..3]

*4.0 TIME

12.0 DUE ARRAY [1..3]

*4.0 TIME

...

...

...

...

348.0 TRENTA ARRAY[1..3]

*4.0 TIME

360.0 PUNTATORE INT

Scusa ma non sono riuscito ad inserire un print screen altrimenti sarei stato più esaustivo.

Poi ho usato il tratto di codice già scritto nell'FB

Quindi diciamo che è una DB con 31 elementi, trenta dei quali sono degli Array i cui elementi sono di tipo time, el'ultimo elemento del DB è un intero.

Matteo Montanari
Inserita:
Ciao, il tuo metodo il AWL mi sembra il più efficace, comunque se volessi semplificare il codice, questo sarebbe possibile utilizzando SCL, e strutturando il tuo DB in modo che sia un array[1..31] di STRUCT contenenti i 3 dati di tipo TIME. In questo modo potresti indicizzare direttamente l'array con una variabile di tipo INT e scorrerlo tramite un semplice ciclo FOR.

SCL non è un linguaggio "standard" siemens, non fà parte del pacchetto base di programmazione.

per questo motivo, oltre che quello economico, non viene molto usato e gli esempi o il codice sono scritti in KOP o AWL.

di certo semplificherebbe di molto le cose.

Inserita:

Inoltre non devo fare uno scan di tutto il DB in una volta con un FOR sola, ma solo a fronte di alcune condizioni andare a scrivere sul DB. Potrebbe essere utile in quel caso, ma comunque preferirei fare lo stesso un loop in AWL condizionato dal puntatore

Matteo Montanari
Inserita:

carissimo tode72 non ho ancora ben capito cosa vuoi realizzare.

con il codice che hai impostato scrivi il valore di tempo (letto con la funzione SFC64) nell'area di dati puntata dal puntatore con un offset di "96".

nel primo caso ottieni:

1 * 96 = 96 -> in questo caso specifico andersti a scivere la tua doppia word nell'indirizzo 12.0 ... 15.7 (associato a DUE tempo 1 della tua tabella)

incrementi il puntatore 1 + 1 = 2

e nel secondo caso ottieni:

2 * 96 = 192 -> in questo caso specifico andersti a scivere la tua doppia word nell'indirizzo 24.0 ... 27.7 (associato a TRE tempo 1 della tua tabella)

incrementi il puntatore 2 + 1 = 3

e nel terzo caso ottieni:

3 * 96 = 288 -> in questo caso specifico andersti a scivere la tua doppia word nell'indirizzo 36.0 ... 39.7 (associato a QUATTRO tempo 1 della tua tabella)

seguendo questo ragionamento andresti a "riempire" tutti i tuoi "tempo 1" della tabella, con vaalori di tempo che praticamente si scostano l'uno dall'altro solamente di un ciclo di scansione.

inoltre non scriveresti nulla nella primo (UNO) valore della tua tabella.

consiglio, anziche mettere

L "DB".PUNTATORE

L 96

*I

LAR1

puoi mettere

L "DB".PUNTATORE

L 96

*I

L 96

- I

LAR1

ma diventa brutto da vedere, in alternativa puoi spostare l'inizio della tua tabella , anzichè dall'indirizzo 0 all'indirizzo 10.

Inserita:

Ciao Keosmm

la funzione deve andare a salvare il tempo di inizio, di fine e la sua differenza (la calcolo io e la scrivo nel terzo elemento dell'array) degli ultimi 30 eventi della macchina. Non avevo postato tutto il tratto di codice con le varie condizioni, ma il senso è questo

Ciclo iniziale

Inizio puntatore =0

Arriva l'evento (se non c'è tale evento salta alla fine)

Salvo il tempo di inizio in DB / Array indicato dal puntatore

Attivo un flag

Ciclo successivo

Se l'evento è ancora attivo ma ho il flag salto alla fine (attendo che l'evento smetta)

Appena l'evento sparisce, salvo il tempo in DB/Array indicato dal puntatore +32 per ottenere la seconda posizione dell'array (so che devo scrivere lì perché c'è ancora il flag attivo)

Calcolo la differenza e la salvo su DB/Array indicato dal puntatore +64 per ottenere la terza posizione dell'array

resetto il flag e incremento il puntatore

Con le condizioni adatte spero che tutto fili liscio. Mettendo a 0 il puntatore iniziale dovrei scrivere in sequenza negli indirizzi

0.0

12.0

24.0

....

e quando il contatore arriva a 31 lo riazzero.

la mia domanda comunque rimane quella di sapere se in linea di principio, a parte qualche piccole sbavature, il concetto è esatto o devo trovare un'altra soluzione. :unsure:

TNX

Matteo Montanari
Inserita:

il concetto è esatto, potrebbe essere semplificato il codice, come ti ho suggerito nel messaggio precedente, dovresti partire da un indirizzo diverso da "0", utilizzare questo come indirizzo iniziale provoca sempre de problemi (vedi scrittura di più codice). se parti invece da un indirizzamento diverso, hai più possibilità di scrivere parti di codice uguali e lavorare solamente cambiando l'offset.

stessa cosa utilizzando a "0" il puntatore, sarebbe più comodo, dal punto di vista di debug che il puntatore con "1" punti al primo dato, non al secondo.

attenzione, che utilizzando il punatatore da "0" come fai tu, non devi azzerarlo a 31 (punterebbe l'area del 32mo dato) ma maggiore di 30 (non riesce a puntare l'area del 31mo dato).

Inserita:

Il limite del puntatore lo devo abbassare di sicuro, sorry, errore mio. Proverò a modificarlo secondo tuoi consigli.

Grazie mille dell'aiuto

Inserita:

Forse non ho capito bene il problema

ma non e' piu' semplice questo??

OPN DB 10

L DBB [MD 100]

dove MD 100 = numero del byte spostato a sinistra di 3

md100 ti fa' da puntatore incrementando di 1

prima lo moltiplichi in base al passo della tua struttura poi

sposti di 3 ( ultimi 3 bit servono per il numero del bit )

ovviamente funzia anche a word

Luca

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