Vai al contenuto
PLC Forum


Ottenere indirizzo di una variabile


albertid

Messaggi consigliati

Buongiorno a tutti,

 

mi scuso in anticipo perchè probabilmente è un quesito banale, ma non sono riuscito a trovare nulla a riguardo.

 

Sto cercando di creare una funzione SCL dove in ingresso do un Byte di uscita, nella funzione vorrei recuperare l'indirizzo di questo byte per poter scrivere i byte consecutivi a quello (ho trovato qui sul forum che la funzione POKE potrebbe fare al caso mio per andare a scrivere conoscendo gli indirizzi).

 

Qualcuno potrebbe illuminarmi la via? grazie mille

Link al commento
Condividi su altri siti


4 minuti fa, batta scrisse:

???

Non mi è molto chiaro.

 

Intendo dire che io di quella variabile voglio solo ricavarne l'indirizzo, non voglio scriverla direttamente, nel mio caso è un byte Q, ma potrebbe essere un I, non credo ci siano grosse differenze, sbaglio?

Link al commento
Condividi su altri siti

 

14 ore fa, max.bocca scrisse:

 

Gli ingressi sono 16#81, le uscite 16#82 le db 16#84

I comandi sono peek e poke.

 

 

 

Grazie per la risposta, intendevo dire come recuperare l'indirizzo non come scrivere o leggere il valore.

Piano piano ci sto arrivando leggendo la documentazione, passo l'indirizzo all'FC con una variabile di tipo Any, poi con la funzione FILL vado a scrivere il valore

Link al commento
Condividi su altri siti

Per lavorare con gli indirizzi, meglio se usi AWL.

Però io farei un passo indietro: sei proprio sicuro che ti serva veramente leggere l'indirizzo?

Se spieghi cosa devi fare, forse troviamo un'altra strada.

Link al commento
Condividi su altri siti

50 minuti fa, batta scrisse:

Per lavorare con gli indirizzi, meglio se usi AWL.

Però io farei un passo indietro: sei proprio sicuro che ti serva veramente leggere l'indirizzo?

Se spieghi cosa devi fare, forse troviamo un'altra strada.

 

 

Perchè consigli di utilizzare AWL?

non l'ho mai usato, pensavo fosse SCL il "futuro", forse AWL è più a basso livello?

 

Il mio obiettivo è scrivere una stringa dentro un dispositivo profinet, ho 16 Byte di uscita nei quali voglio scrivere una stringa di 16 char, i char "vuoti" devono essere settati a 0.

Ho scritto questo codice che sembra funzionare, ma sono apertissimo a consigli.

Grazie mille per il supporto

 

FUNCTION "65007_ScriviByteConsecutivi" : Void
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      Stringa : String;
   END_VAR

   VAR_IN_OUT 
      IndirizzoAreaMemoria : Any;
   END_VAR

   VAR_TEMP 
      StrLen : Int;
      i : Int;
      RetVal : Int;
   END_VAR

   VAR CONSTANT 
      ArrayLength : Int := 16;
      Zero : Word := 16#0;
   END_VAR


BEGIN
	
	#StrLen := LEN(#Stringa);
	
	
	FOR #i := 1 TO #ArrayLength
	    
	DO
	    
	    IF #i > #StrLen
	        
	    THEN
	        
	        #Stringa[#i] := #Zero;
	        
	    END_IF;
	   
	    
	END_FOR;
	
	#RetVal := FILL(BVAL := #Stringa, //sorgente
	                BLK => #IndirizzoAreaMemoria);    //destinazione
	
END_FUNCTION

 

 

Questo è ad esempio l'area di memoria che passo alla variabile "IndirizzoAreaMemoria":

 

P#Q1105.0 BYTE 16

Modificato: da albertid
Link al commento
Condividi su altri siti

33 minuti fa, albertid scrisse:

pensavo fosse SCL il "futuro", forse AWL è più a basso livello?

 

AWL può essere paragonato ad un linguaggio tipo assembler, mentre SCL è paragonabile ad un linguaggio come il "C".

Con lo AWL sei più a contatto con la macchina.

Link al commento
Condividi su altri siti

38 minuti fa, Livio Orsini scrisse:

 

AWL può essere paragonato ad un linguaggio tipo assembler, mentre SCL è paragonabile ad un linguaggio come il "C".

Con lo AWL sei più a contatto con la macchina.

 

Io infatti conoscendo un pochino di C, mi trovo più a mio agio con SCL, però capisco il consiglio di Batta

Link al commento
Condividi su altri siti

Il mio consiglio, a dire il vero, non è quello di usare awl, ma di cercare una strada, se possibile, che ti permetta di lavorare senza usare gli indirizzi.

Per esempio, non capisco perché tu voglia passare l'indirizzo della variabile dove andrai a scrivere, e non direttamente la variabile.

Poi dichiari la variabile Stringa come STRING. Ricorda che se nel tipo String non dichiari la lunghezza, viene impostata la lunghezza massima di 254 caratteri.

La funzione FILL è in una cartella chiamata Legacy. Queste istruzioni sono presenti per mantenere la compatibilità con versioni precedenti ma, se possibile, meglio non usarle.
Per lavorare con le stringhe, guarda piuttosto le funzioni dedicate. Per esempio, una funzione che ti potrebbe fare comodo è  Str_TO_Chars.

 

Ribadisco che non ho capito perché vuoi lavorare con l'indirizzo della variabile anziché direttamente con la variabile.
 

Link al commento
Condividi su altri siti

Ciao Batta,

 

ho utilizzato l'indirizzo e non direttamente la variabile perchè le variabili che devo scrivere sono dei Byte di uscita di un dispositivo profinet.

Ho 16 Byte di uscita, non una stringa, quindi per andare a scriverli dovrei andare a metterli nella mia funzione uno ad uno tutti e 16 (correggetemi se sbaglio) per questo ho pensato di puntare solo l'indirizzo del primo Byte e scrivere automaticamente quelli che vengono dopo.

 

Condivido i dubbi sulla variabile di ingresso di tipo stringa, l'ho utilizzata perchè ancora non so bene quanti Byte andrò a scrivere, potrebbero essere anche 32, però hai ragione forse sarebbe meglio usare un array.

 

Link al commento
Condividi su altri siti

1 ora fa, albertid scrisse:

Ho 16 Byte di uscita, non una stringa, quindi per andare a scriverli dovrei andare a metterli nella mia funzione uno ad uno tutti e 16 (correggetemi se sbaglio)

Ti basta dichiarare i 16 byte come un array, e passi alla funzione tutto l'array.
Anche nel caso questi 16 byte siano direttamente nell'area delle uscite, ti basta creare un Tipo di Dati che sia un array di 16 byte, e usarlo sia nella funzione, sia nella tabella delle variabili.

 

1 ora fa, albertid scrisse:

forse sarebbe meglio usare un array

Dipende da come componi la stringa. Se la imposti da un pannello operatore Siemens, dichiararla come String è la soluzione più comoda.

Modificato: da batta
Link al commento
Condividi su altri siti

33 minuti fa, batta scrisse:

Ti basta dichiarare i 16 byte come un array, e passi alla funzione tutto l'array.
Anche nel caso questi 16 byte siano direttamente nell'area delle uscite, ti basta creare un Tipo di Dati che sia un array di 16 byte, e usarlo sia nella funzione, sia nella tabella delle variabili.

 

Grazie per il consiglio, avevo proceduto esattamente in questo modo, ma non so per quale motivo facendo così mi si è allungato il tempo di ciclo di 2ms (!!!) possibile che questo crei qualche noia alla comunicazione, rallentando il ciclo?

io non ho saputo darmi una risposta

Link al commento
Condividi su altri siti

1 ora fa, albertid scrisse:

possibile che questo crei qualche noia alla comunicazione, rallentando il ciclo?

Non credo proprio. Anzi, dato che non utilizzando l'istruzione FILL si possono usare blocchi ottimizzati, dovrebbe essere più veloce.

 

Una domanda: sei sicuro che sia corretto scrivere 00Hex nei byte corrispondenti ai caratteri vuoti della stringa?
Te lo chiedo perché, di solito, se si lavora con caratteri e stringhe, il carattere vuoto non è 00Hex.
00Hex, tradotto in carattere, viene visualizzato come '$00'.
Mi pare strano che il dispositivo dove vai a scrivere riceva dei caratteri, e voglia 00Hex per i caratteri vuoti.
 

Qui sotto, solo per fare un esempio, ho implementato una funzione usando il tipo "Variant". In questo modo, la variabile INOUT potrebbe essere un array di char di dimensioni diverse.
In realtà, nel caso specifico, dove la lunghezza è definita (16 caratteri) non ha senso complicarsi la vita con il formato Variant. È da prendere solo come esempio, buttato lì anche per far vedere l'uso di istruzioni di controllo come "IS_ARRAY", "CountOfElements", "TypeOfElements", ecc.

 

FUNCTION_BLOCK "TestStringToArray"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      Stringa : String[32];
   END_VAR

   VAR_IN_OUT 
      ArrayOut : Variant;
   END_VAR

   VAR_TEMP 
      Buffer : Array[1..#BufferElements] of Char;
      ArrayOutSize : UDInt;
      StrLen : Int;
      i : Int;
      RetVal : Int;
   END_VAR

   VAR CONSTANT 
      BufferElements : Int := 254;
   END_VAR


BEGIN
	// Esegui solo se la variabile passata come parametro è un array di Char
	IF IS_ARRAY(#ArrayOut) THEN
	    IF TypeOfElements(#ArrayOut) = Char THEN
	        // Leggi dimensione array variabile passata come parametro
	        #ArrayOutSize := CountOfElements(#ArrayOut);
	        // Leggi lunghezza effettiva stringa
	        #StrLen := LEN(#Stringa);
	        
	        // Copia caratteri della stringa in "Buffer" (per caratteri vuoti, scrivere 00Hex)
	        FOR #i := 1 TO UDINT_TO_INT((#ArrayOutSize)) DO
	            IF #i <= #StrLen THEN
	                #Buffer[#i] := #Stringa[#i];
	            ELSE
	                #Buffer[#i] := b#16#00;
	            END_IF;
	        END_FOR;
	        
	        // Copia un numero di byte pari alla lunghezza della variabile da "Buffer" alla variabile 
	        #RetVal := MOVE_BLK_VARIANT(SRC := #Buffer,
	                                    COUNT := #ArrayOutSize,
	                                    SRC_INDEX := 0,
	                                    DEST_INDEX := 0,
	                                    DEST => #ArrayOut);
	        
	    END_IF;
	END_IF;
	
	
	
END_FUNCTION_BLOCK


 

Link al commento
Condividi su altri siti

I byte del dispositivo (è una camera Cognex) di default contengono 0x0, se metto ad esempio uno spazio questo viene interpretato come tale (giustamente), ho pensato quindi di reimpostarli al valore che avevano per default in modo da non avere problemi.

 

Grazie mille per l'esempio, mi sarà molto utile, ad un primo sguardo mi sembra proprio fare al caso mio.

Link al commento
Condividi su altri siti

5 ore fa, albertid scrisse:

ad un primo sguardo mi sembra proprio fare al caso mio

Ma se la dimensione dell'array da scrivere è fissa, ti conviene fare qualcosa di più semplice.

Esempio:

FUNCTION_BLOCK "Test"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      MyString : String[#ArrayDim] := 'abcdefghijklmnop';
   END_VAR

   VAR_OUTPUT 
      MyArray : Array[1..#ArrayDim] of Char;
   END_VAR

   VAR_TEMP 
      StringLen : Int;
      i : Int;
   END_VAR

   VAR CONSTANT 
      ArrayDim : Int := 16;
   END_VAR


BEGIN
	#StringLen := LEN(#MyString);
	
	FOR #i := 1 TO #ArrayDim DO
	    IF #i <= #StringLen THEN
	        #MyArray[#i] := #MyString[#i];
	    ELSE
	        #MyArray[#i] := '$00';
	    END_IF;
	END_FOR;
	
	
END_FUNCTION_BLOCK

 

Link al commento
Condividi su altri siti

1 ora fa, albertid scrisse:

non sapevo come si potessero dimensionare gli array con delle costanti in TIA Portal

In SCL si faceva già anche con il Simatic Manager.

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