Deklarując tablice do niedawna konieczne było podawanie od razu dokładnego rozmiaru. Od kiedy wyszła trzecia edycja standardu IEC61131-3 (wykorzystywana m.in. w e!COCKPIT) możliwe jest deklarowanie tablic o zmiennych wymiarach. Dzięki temu można tworzyć bardziej uniwersalne bloki funkcyjne i funkcje.

Oczywiście można wykorzystywać zmienne, aby określić granice tablicy. Muszą być one jednak zadeklarowane jako stałe (CONSTANTS). Nie zmienia to więc podstawowego ograniczenia nałożonego na tablice w poprzednich wersjach standardu.

PROGRAM MAIN
VAR
 aTablica : ARRAY[1..UPPER_LIMIT] OF INT;
END_VAR
VAR CONSTANT
 UPPER_LIMIT : INT := 10; 
END_VAR

Ta właściwość jest szczególnie niewygodna, kiedy tablice przekazywane są jako parametry do bloków funkcyjnych. W artykule „Wskaźniki – najbardziej uniwersalne narzędzie programisty”  opisałem możliwe rozwiązanie takiego problemu. Wykorzystanie wskaźników często bywa jednak kłopotliwe. Tworzony w taki sposób kod nie jest za bardzo czytelny przez co łatwo o błąd, który w tym przypadku może prowadzić do zatrzymania całego programu.

W e!COCKPIT można zadeklarować tablicę w nowy sposób:

aTablica : ARRAY[*] OF INT;

Z tej opcji można jednak korzystać tylko w przypadku deklarowania zmiennych VAR_IN_OUT dla bloków funkcyjnych i funkcji (w e!COCKPIT jest już możliwość korzystania ze zmiennych VAR_IN_OUT w funkcjach). Dalej w momencie kompilacji tablica musi mieć określony rozmiar. W tym przypadku tak zadeklarowana tablica przyjmie zawsze rozmiar tablicy jaką podłączymy do danego bloczka.

FUNCTION FunSumArray :INT
VAR_IN_OUT
aTablica:ARRAY[*]OF INT;
END_VAR
VAR
i:INT;
iSuma:DINT;
END_VAR

(*kod funkcji*)
FOR i:= LOWER_BOUND(aTablica, 1) TO UPPER_BOUND(aTablica, 1) DO


diSuma:=iSum+ aTablica[i];
END_FOR

FunSumArray:=diSuma;

Funkcja LOWER_BOUND zwraca liczbę będącą dolnym zakresem tablicy. Jeśli więc zadeklarowaliśmy tablicę tak jak poniżej, funkcja powinna zwrócić wartość 11. Analogicznie funkcja UPPER_BOUND zwróci wartość 99.

VAR
aTablica1:ARRAY[11..99]OF INT;
END_VAR

(*kod programu*)

iDolnyZakres:= LOWER_BOUND(aTablica1,1);
iGornyZakres:= UPPER_BOUND(aTablica1,1);

Korzystanie z bloków tworzonych w ten sposób jest o wiele wygodniejsze niż w wersji opartej na wskaźnikach.

PROGRAM PLC_PRG
VAR
aTablica1:ARRAY[0..99]OF INT;
aTablica2:ARRAY[8..17]OF INT;
aTablica3:ARRAY[-10..20]OF INT;
aTablica4:ARRAY[300..800]OF INT;

iWynik1:INT;
iWynik2:INT;
iWynik3:INT;
iWynik4:INT;

END_VAR

(*kod programu*)

IWynik1:= FunSumArray(aTablica1);
IWynik2:= FunSumArray(aTablica2);
IWynik3:= FunSumArray(aTablica3);
IWynik4:= FunSumArray(aTablica4);

Co ważniejsze możemy przekazywać tablice z dowolnie zadeklarowanymi granicami dolnymi i górnymi. Zwiększa to możliwości wykorzystania takich bloków. Idealnym przykładem jest bloczek FbMbSimpleServerTcp z biblioteki WagoAppPlcModbus. Trzeba do niego podłączyć tablice, których granice mogą być dowolnie zadeklarowane. Dzięki temu zmienne mogą być udostępniane na dowolnym zakresie adresów modbus.

FUNCTION FunSumArray2D :INT
VAR_IN_OUT
aTablica:ARRAY[*,*]OF INT;
END_VAR
VAR
i:INT;
j:INT;
iSuma:DINT;
END_VAR

(*kod funkcji*)
FOR i:= LOWER_BOUND(aTablica, 1) TO UPPER_BOUND(aTablica, 1) DO
FOR j:= LOWER_BOUND(aTablica, 2) TO UPPER_BOUND(aTablica, 2) DO

diSuma:=iSum+ aTablica[i,j];

END_FOR
END_FOR

FunSumArray2D:=diSuma;

Podsumowanie

Dzięki takim rozwiązaniom możliwe jest tworzenie jeszcze bardziej elastycznych bloków funkcyjnych. W przeciwieństwie do bloków opartych o wskaźniki, kompilator dba o poprawność kodu. Efekt końcowy jest też o wiele bardziej czytelny. Z tak napisanych bloków mogą później bez problemów korzystać nawet niedoświadczeni programiści, bez konieczności zmiany dawnych przyzwyczajeń.

Krzysztof Nosal, WAGO.PL

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Zobacz również

Bliski kuzyn wskaźnika

W poprzednim artykule (Wskaźniki – najbardziej uniwersalne narzędzie