loading...

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 e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *