Vai al contenuto
PLC Forum


Implementazione In Scl - pensando per una soluzione diversa


Savino

Messaggi consigliati

FUNCTION_BLOCK FBxx

NAME:xx_xx

..

VAR_TEMP

...

..

STEP_LEVEL : REAL;

...

..

AUX1 : WORD;

AUX2 : WORD;

LENGTH1 : INT;

DB_N : WORD;

INDEX: INT;

OFFSET: INT;

..

.

END_VAR

...

..

BEGIN

..

LENGTH1 :=0;

OFFSET :=0;

INDEX :=0;

..

.

OFFSET:= (LENGTH1 * 4) - 2 ;

..

AUX1:=WORD_TO_BLOCK_DB(DB_N).DW[iNDEX];

INDEX:=INDEX+ 2;

AUX2:=WORD_TO_BLOCK_DB(DB_N).DW[iNDEX];

MW18:= AUX1;

MW20:= AUX2;

STEP_LEVEL :=DWORD_TO_REAL (MD18); ..

.

END_FUNCTION_BLOCK

----------------------------------------------------

DATA_BLOCK "xxxx"

TITLE = TANK13

STRUCT

CALIBRATION : ARRAY [1 .. 2, 1 .. 31 ] OF REAL ;

END_STRUCT ;

BEGIN

CALIBRATION[1, 1] := 0.000000e+000;

CALIBRATION[1, 2] := 4.200000e+000;

CALIBRATION[1, 3] := 7.800000e+000;

CALIBRATION[1, 4] := 1.050000e+001;

CALIBRATION[1, 5] := 1.490000e+001;

..

.

CALIBRATION[2, 29] := 1.100000e+005;

CALIBRATION[2, 30] := 1.200000e+005;

CALIBRATION[2, 31] := 1.260000e+005;

END_DATA_BLOCK

Ciao,

Ieri all'improvisso, mi e' capitato di dover fare una implementazione in SCL alla veloce.. in prattica dovevo leggere dei DB con lunghezza variabile , tipo come sopra , 2 dimensioni REAL data type array, pilotando l'offset a secondo la richiesta imposta dagli algoritmi...

Diciamo che alla fine la soluzione adottata e' stata molto soddisfacente.. il codice implementato dopo essere validato, ha performato bene.

Come potete apprezzare , per leggere una data REAL ho usato la forma :

     AUX1:=WORD_TO_BLOCK_DB(DB_N).DW[INDEX];
     INDEX:=INDEX+ 2;
     AUX2:=WORD_TO_BLOCK_DB(DB_N).DW[INDEX];
     MW18:= AUX1; 
     MW20:= AUX2;
     STEP_LEVEL :=DWORD_TO_REAL (MD18);

appogiandomi sulla data PLC per formatare la variabile di 4 BYTES o 2 WORD per ottenere finalmente la FLOAT (MD).

Mi domandavo si c'era un'altra strada senza dovere usare la data PLC, benche' una struttura SCL propia...

Ringrazio in anticipo per any comment. ;)

Link al commento
Condividi su altri siti


ti costruisci un UDT con la struttura che tu intendi usare,

poi passi questa struttura al FB10 (e' un esempio) come dato In_Out

Type UDT10

Struct

// Struttura Calibration

CALIBRATION : ARRAY [1 .. 2, 1 .. 31 ] OF REAL ;

end_Struct

END_TYPE

Function_Block FB10

Title = 'Read Real'

// SubRoutine for read real value from Structur of Array

//

//

Version : '1.0'

Author : xxxx

Name : yyyy

Family : zzzzz

Var_Input

Index1: INT:

Index2: INT:

End_Var

Var_in_out

Calibration : UDT10; // Struttura Array che gia' avevi definito

End_Var

Var_Output

Step_level : REAL;

End_Var

Begin

Step_Level := Calibration[index1,index2]

end_Function_Block

Link al commento
Condividi su altri siti

Dear Beatrice_Ru,

Grazie mille per la tua risposta..

Dunque, diciamo che in una Process Cell ho 100 Units (tanks), ad ogni tank viene associato una DB quale forma non posso cambiare.

DATA_BLOCK "TANK13" // DB13
TITLE = TANK13
..
STRUCT 
 CALIBRATION : ARRAY [1 .. 2, 1 .. 31 ] OF REAL; 
END_STRUCT; 
BEGIN
  CALIBRATION[1, 1]  := 0.000000e+000; 
  ..
  CALIBRATION[1, 31] := 1.036500e+003;
  CALIBRATION[2, 1]  := 0.000000e+000; 
  ..
  CALIBRATION[2, 31] := 1.260000e+005; 
  END_DATA_BLOCK
 DATA_BLOCK "TANK15" // DB15
  TITLE = TANK15
..
STRUCT  
 CALIBRATION : ARRAY  [1 .. 2, 1 .. 28 ] OF REAL;   
END_STRUCT;
BEGIN
   CALIBRATION[1, 1]  := 0.000000e+000; 
   ..
   CALIBRATION[1, 28] := 1.016400e+003; 
   CALIBRATION[2, 1]  := 0.000000e+000; 
   ..
   CALIBRATION[2, 28] := 1.160000e+005; 
END_DATA_BLOCK
Come tu hai gia' intuito, devo leggere indirettamente delle data REAL a secondo un indice dato, da una determinata DB.. (DB_N = input) Diciamo che mi sarebbe bastato un mnemonic del tipo :
DAUX1 : DWORD;
DAUX1:=DWORD_TO_BLOCK_DB (DB_N). DD[INDEX];
STEP_LEVEL :=DWORD_TO_REAL (DAUX1);
Cioe' leggere la DB nel modo
 DAUX1 := DB[DB_NUM][DWORD];
Ma purtroppo non esiste. Infatti cercavo per una soluzione del genere, senza dovere appoggiarmi sulla data PLC, sia questa del tipo Flag, DB, UDT..cioe', definire un data type come VAR_TEMP (ma non UDT o DB o Flag) da utilizzare temporaneamente dentro l'FB. In C++ avrei dichiarato una union per utilizzare come maschera per formatare 4 bytes in una DWord o float..
 
union reg_32bits
{
    float mw_32;
    char mb_32[4];
};
union reg_32bits m_FloatingValue[1].mw_32
oppure
union reg_32bits
{
    signed long int RegDWord_32;
    char DW_32[4];
};

 m_FloatingValue[0].mw_32;    // indirizzamento DWord
 m_FloatingValue[0].mb_32[3]; // \
 m_FloatingValue[0].mb_32[2]; //  | indirizzamento byte
 m_FloatingValue[0].mb_32[1]; //  |
 m_FloatingValue[0].mb_32[0]; // /

Oppure un'accesso in lettura con una forma che ancora non mi viene in mente.. :unsure:

Comunque la suluzione da te suggerita :

Step_Level := Calibration[index1,index2];
Non e' accettata dal compilatore..invalid variable...Number of array dimensions exceeded (max. 6) <_<

Saluti

Modificato: da Savino
Link al commento
Condividi su altri siti

Scusami Savino, pensavo di eserti stata utile, invece

ho sbagliato qualche sintassi.

Eccomi allora.

Ho capito che hai 100 processi da controllare ognuno con un suo pacchetto di dati.

Io per vacilitarti il compito ho creato una sola DB (DB10).

nel Suo interno questa DB10, ha 100 elementi Cell[1..10]

ogni elemento Cell e diviso in una Struttura CALIBRATION : ARRAY [1 .. 2, 1 .. 31 ]

con questa prima sorgente SCL ti crei due UDT 10, e UDT11 e poi la DB10 appunto:

Type UDT10

Struct

// Struttura Calibration

Calibration : ARRAY [1 .. 2, 1 .. 31 ] OF REAL ;

end_Struct

END_TYPE

Type UDT11

Struct

// Struttura Process Cell

Cell : ARRAY [1 .. 100] OF UDT10;

end_Struct

END_TYPE

// Creazione DB10

DATA_BLOCK DB10 UDT11

BEGIN

END_DATA_BLOCK

Bene ora ecco FB10 Corretta (ho fatto sia il Parametro di Input_Output = Struttura UDT11, che accesso diretto sulla DB10)

Function_Block FB10

Title = 'Read Real'

// SubRoutine for read real value from Structur of Array

//

//

Version : '1.0'

Author : xxxx

Name : yyyy

Family : zzzzz

VAR_INPUT

IndexCell: INT;

Index1: INT;

Index2: INT;

END_VAR

Var_in_out

Process : UDT11; // Struttura Array che gia' avevi definito

End_Var

Var_Output

Step_level : REAL;

Step_lev : REAL;

END_VAR

VAR

PX,PY,PZ: INT; // Puntatori con limite per IndexCell, Index1,Index2

END_VAR

BEGIN

PX:= IndexCell; PY:= Index1; PZ:= Index2;

IF PX <1 THEN PX :=1; END_IF; IF PX >100 THEN PX :=100; END_IF; // Limite 1..10

IF PY <1 THEN PY :=1; END_IF; IF PY >2 THEN PY :=2; END_IF; // Limite 1..2

IF PZ <1 THEN PZ :=1; END_IF; IF PZ >31 THEN PZ :=31; END_IF; // Limite 1..31

Step_Level := Process.Cell[PX].Calibration[PY,PZ]; // puoi puntatare un Struttura a tuo piacimento

Step_Lev := db10.Cell[PX].Calibration[PY,PZ]; // viene puntato il Data Block DB10

end_Function_Block

Spero che cosi vada bene.

Link al commento
Condividi su altri siti

Gentile Beatrice,

Scusami Savino, pensavo di eserti stata utile, invece

ho sbagliato qualche sintassi.

ma figurati.. ti ringazio per il tuo interessamento.

In tanto ti dico che quando compilo il codice mi da errore, forse c'e' un errore di sintassi :

Error in a block DB10
Symbol table entry for instance DB or DB of the type UDT does not match the called FB or UDT
DATA_BLOCK DB10 UDT11     <- qui
BEGIN
END_DATA_BLOCK

Poi, tieni presente che le DB col'array CALIBRATION sono a lunghezza variabile ( 1..31, 2..31) - (1..29, 2..29)- ( 1..15, 2..15);

Infatti l'FB riceve anche come parametro d'ingresso la lunghezza dei DB ricavata in un FC chiamato in precedenza (DBLG), ma questo non sarebbe un problema... ma si per creare il tuo UDT 10 ?? <_<

Comunque, domani studiero' ancora il tuo metodo e vedro' se ne posso ricavare qualcosa d'utile...

Per adesso ti ringrazio , sei stato super disponibile e very smart !! ;)

P.D: devo propio andare al letto che mi sono pescato l'influenza :(

Modificato: da Savino
Link al commento
Condividi su altri siti

Gentile Beatrice,

Nonostante alla fine sia riuscito a compilare l'utimo esempio di codice da te postato, la forma della soluzione non sarebbe quella da me desiderata.. e ti spiego perche...

Innanzitutto, tanto mio cliente come me siamo soddisfatti della performance del codice da me consegnato, questo funziona bene e fa' quello che deve fare. La mia curiosita' era nata dal fatto che per leggere una word doppia da una DB in modo indiretto ho dovuto leggere per due volte una word e dopo creare la doppia word , formatandole sulla base di una MD del PLC, dovuto alla mancanza di una sintassi del genere:

DAUX1 : DWORD;

DB_N : WORD;

INDEX: INT;

DAUX1:=DWORD_TO_BLOCK_DB (DB_N). DD[iNDEX]; <- questa sintassi non esiste in SCL

STEP_LEVEL :=DWORD_TO_REAL (DAUX1);

Piuttosto ho dovuti creare la word doppia facendo cosi:

MW18:=WORD_TO_BLOCK_DB(DB_N).DW[INDEX];   // leggo la prima WORD
INDEX:=INDEX+2;                           // incremento di 2 bytes
MW20:=WORD_TO_BLOCK_DB(DB_N).DW[INDEX];   // leggo la 2nda WORD
NEXT_VOLUME :=DWORD_TO_REAL (MD18);       // creo la DWORD sulla maschera MD

Come vedi, il metodo e' molto semplificato e meno drastico, l'unica cosa e' che mi devo appoggiare ad una MD, e non ad un costruito SCL.

Infatti, Io mi domandavo.. ma come e' possibile che i progettisti cha hanno disegnato l' SCL abbiano previsto una sintassi per un'accesso indiretto impostanto come offset l'indirizzo DB + l'indirizzo WORD e non abbiano previsto fare la stessa cosa invece per indirizzare una WORD doppia. Dove sarebbe questo limite nel sistema, visto che S7300/400 ha una architettura a 32 bit.

Sono stati cosi' pigri o c'e' qualcosa che Io non ho ancora afferrato, o magari la sintassi c'e' ma riesco tovarla( magari c'e' in una release successiva a quella che sto' utilizzando)

Attenzione, mi sto riferendo a una sintassi, mnemonic... e non ad un metodo diverso, come potrebbe essere quello che tu hai elencato.

Comunque, ti ringrazio di cuore per il tuo interessamento. :)

Modificato: da Savino
Link al commento
Condividi su altri siti

DAUX1:=DWORD_TO_BLOCK_DB (DB_N). DD[INDEX]; <- questa sintassi non esiste in SCL

Non funziona perchè è errata la prima parte relativa all'identificazione del DB "DWORD_TO_BLOCK_DB"

Hai provato con questa sintassi?

DAUX1:=WORD_TO_BLOCK_DB (DB_N). DD[iNDEX]

A me funziona.

CIAo

Beppe

Modificato: da beppeconti
Link al commento
Condividi su altri siti

DAUX1:=WORD_TO_BLOCK_DB (DB_N). DD[iNDEX]

A me funziona.

:clap:

Grazie mille beppeconti.. aspettavo un tuo riscontro , infatti non poteva non esistere.! :rolleyes:

Ti ringrazio ancora e anche a Beatrice. :)

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