A Common Issue With Code
While working with Beckhoff, I’ve come across several instances of poorly structured FB code. What do I mean by poorly structured? I mean that coders often import their bad habits from older IDE’s. In the case of controls this means overuse of global tags. Even more egregious is the use of global tags in FB’s!?
It is important to separate FB’s entirely from global tags and higher-level sequencer logic. This de-coupling creates reusable blocks that are not dependent upon the structure or operation of external logic. You can then plop these isolated blocks into any program and confidently use them. This is the basis for object-oriented programming and reusable code. Plus doing this will bring you closer to the IEC 611131 standard.
Dealing with Arrays
Most improperly placed global tags are (relatively) simple to refactor out of a function. But what about arrays? In FB’s and Functions, arrays must be statically declared; otherwise the code will not even compile. What if you need to pass an array that may vary in size depending upon which system it is in? Like one machine with 3 stations versus another machine with 10 stations. How would you change the array size?
What I commonly see is defining a global constant variable with the size of the array, such as: STATION_NUMBER := 10. This variable is then used in the definition of the array within the function block. Defining an array in top level logic with a constant is fine, but it is terrible to use it in the FB. By defining anything within the FB or Function with a global tag, you must now ensure this global tag is in all programs that need to use this FB. This creates tightly coupled code, dependent upon external definitions, making it rigid and more difficult to reuse. Plus tightly coupled code makes introducing bugs into the system much easier.
Introducing Variable Arrays
A variable array is exactly what it sounds like; an array that is not defined statically during compiling. It is defined statically during runtime. There is a way to declare dynamic arrays within Beckhoff, but currently there appears to be no way to pass dynamic arrays. Variable arrays may only be defined as a VAR_IN_OUT type within FB’s and Functions. You declare thusly: <VariableName>: ARRAY[*] OF <dataType>.
Key Functions
- LOWER_BOUND( <VariableName>, <dimensionNumber>)
- UPPER_BOUND( <VariableName>, <dimensionNumber>)
You pass to the above functions your variable array name and the dimension of the array. Unless you specified the array as multidimensional, chances are you are using a single dimension array. Now you can iterate through the array with those functions without actually knowing what the defined size is! You won’t get compile errors either since the array is only defined during runtime. Congratulations! Your array in your Function or FB is now fully decoupled from higher logic!
Testing it Out
To test out that these functions work, I created a simple function call ArrayInitializer. The only thing is does is iterate through an array and set the index value equal to the current index. You can see the setup in the image below.
Using this simple function I created a very simple main program testing 3 different arrays. MyStartAt1Array and myStartAt0Array are two common array types we see everywhere. The arrays start their index at 1 and 0 respectively. A less common array, myNegativeArray starts at -4 to see if an array with negative indexes can be handled. Seen below is the setup of the main program to test this function.
All that is needed now is to run the program. After loading into the PLC and running, we can see the successful results in the image below. As expected, all four arrays were properly loaded with their index numbers.
Now that you know how to pass variable arrays into functions and FB’s you can start using it in your code. I implore you to brush up on IEC-61131 standards and work on decoupling your code. I hope you enjoyed this little lesson and learned something useful. Have a good day and keep on improving!
Leave a Reply