Siemens S7 Arrays

Join Date
Sep 2011
Location
Detroit, Michigan
Posts
8
Hello,

Is there a way that I can determine the Upper and Lower Boundaries of an Array in SCL? In VB I would use the UBOUND and LBOUND function. Or in C it would be the SIZEOF command. I am hoping there is a similiar funtion or method that is available in SCL. If not does any one know of a way to determine this value?

Thanks
ExRAGuyFromDetroit
 
Can you explain why you need this information - dynamic code for indexing the array or array bound checking or ....?

Knowing the Upper and and Lower boundaries is not the same as knowing the size of the array - which do you require ?
 
L D[AR2,P#0.0] I need to know the Upper Boundary of the Array. The dimension may change based on the application and I dont want to have to modify my code because of this. I did however find a way to do it.


//******************************************************
// Declare function ***
//******************************************************
FUNCTION FC999 : INT

VAR_INPUT
SingleDimensionPTR : ANY;
TotalArrayPTR : ANY;
END_VAR

VAR_TEMP
pAny : ANY;
pAnyPtr AT pAny : STRUCT
S7Code : BYTE; // Code for S7 = 0x10
DataType : BYTE; // Code for data type = 0x02 = byte
Length : INT; // Repetition factor = Send/receive length
DBNumber : INT; // Data block Number
MemoryArea : BYTE; // Specified memory area = 0x84 = data block
ByteAddressMSB : BYTE; // Byte address most significant bits
ByteAddressLSB : WORD; // Byte address least significant bits
END_STRUCT;

IndividualSize : INT;
TotalSize : INT;

END_VAR

BEGIN

pAny := SingleDimensionPTR;
IndividualSize := pAnyPtr.Length;

pAny := TotalArrayPTR;
TotalSize := pAnyPtr.Length;

FC999 := TotalSize / IndividualSize;
END_FUNCTION

Now I can just call this Function and pass is a pointer to the first position of the Array and a pointer to the entire Array. The function returns the Upper Dimension of the Array.

Regards
ExRAGuyFromDetroit
 
Here's my function and the associated test calls using different array types. What array type did you test with ?
 
Sorry, you are correct. I was using this to determine the Upper Boundary of an array of type STRUCTURE. In this case the Individual Element length is always returned in Bytes as is the Total length of the Entire Array. So the Math works. I have made a change to the Function to work with the following data types.



BYTE, CHAR, WORD, INT, DWORD, DINT, STRUCTURE.

FUNCTION FC799 : INT
TITLE = 'z999_Size_SCL'
VERSION : '1.0'
KNOW_HOW_PROTECT
AUTHOR : 'UTECH'

VAR_INPUT
SingleDimensionPTR : ANY;
TotalArrayPTR : ANY;
END_VAR

VAR_TEMP
pAny : ANY;
pAnyPtr AT pAny : STRUCT
S7Code : BYTE; // Code for S7 = 0x10
DataType : BYTE; // Code for data type = 0x02 = byte
Length : INT; // Repetition factor = Send/receive length
DBNumber : INT; // Data block Number
MemoryArea : BYTE; // Specified memory area = 0x84 = data block
ByteAddressMSB : BYTE; // Byte address most significant bits
ByteAddressLSB : WORD; // Byte address least significant bits
END_STRUCT;

INDEX : INT; //Used in the FOR NEXT LOOP

ibData: ARRAY[0..15] OF BOOL;
iData AT ibData: INT;
dbData: ARRAY[0..31] OF BOOL;
dData AT dbData: DINT;

IndividualSize : DINT; //Returns the Individual Size of the Single Dimension Array
TotalSize : DINT; //Returns the Total Size of the Entire Array
dType : INT;
END_VAR

BEGIN

iData := 0;
dData := 0;

pAny := SingleDimensionPTR;
iData := pAnyPtr.Length;
dType := BYTE_TO_INT(pAnyPtr.DataType);

FOR INDEX := 0 TO 15 BY 1 DO
dbData[INDEX + 16] := ibData[INDEX];
END_FOR;

IF (dType) = (1) THEN //Bool Data Type - Still need to figure out how to detect length
IndividualSize := dData;
ELSIF (dType) = (2) OR (dType) = (3) THEN //BYTE or CHAR. Individ Length is OK
IndividualSize := dData;
ELSIF (dType) = (4) OR (dType) = (5) THEN //INT or WORD. Individ Length * 2
IndividualSize := dData * 2;
ELSIF (dType) = (6) OR (dType) = (7) THEN //DINT or DWORD. Individ Length * 4
IndividualSize := dData * 4;
ELSE //Structure - Length is in Bytes so everything is ok
IndividualSize := dData;
END_IF;

iData := 0;
dData := 0;

pAny := TotalArrayPTR;
iData := pAnyPtr.Length;

FOR INDEX := 0 TO 15 BY 1 DO
dbData[INDEX + 16] := ibData[INDEX];
END_FOR;

TotalSize := dData;

FC799 := DINT_TO_INT(TotalSize / IndividualSize);
END_FUNCTION

Siemens - Size.png
 
Being picky, your routine returns the size of the array, not the upper boundary.

Consider if the arry is declared as follows:

adi1: Array(0..9] of DINT; or
adi2: Array[5..15] of DINT;
 
in your function, you already know the begin point of the array or struct by decoding the any pointer to it.

you also know the length in bytes from the same source as it is an area crossing any pointer.

you have the beginning, and the length, add them inside the function and return the byte offset to get the end.

I have done a similar thing recently so I can use symbolic addressing to keep the reference in place when something is edited above the data, but I also want to know the actual place in the DB.
 

Similar Topics

I have seen many posts relating to indirectly addressing arrays but none seem to fully explain how to do it simply. At the moment I have an...
Replies
5
Views
5,493
Hello I have a s7-1200 and I would like to read the tags present in this controller with my controllogix controller. The two controllers don't use...
Replies
0
Views
11
Hi need help why this “failure 5 emergency stop “ appears at every startup in the morning ? Have to shut off main switch at least 10 times on...
Replies
19
Views
244
i have two plc 1. s7-1212dc/dc/dc ip; 192.168.0.1 2. s7-1500 1513-1pn ip; 192.168.3.2 i need to get data from plc1 to plc2. any idea how to do...
Replies
5
Views
86
Hi everyone hope you'll well. Is it possible for me to download a Crack version of tia portal v13..sorry to say this but the software is very...
Replies
5
Views
183
Back
Top Bottom