B&R Automation Basic

Perfection in Automation B&R Automation Basic Opis języka Document version: 1.0 PL 1 B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemy...
30 downloads 1 Views 1MB Size
Perfection in Automation

B&R Automation Basic Opis języka Document version: 1.0 PL

1

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Spis treści: 1. Wstęp ...........................................................................................................3 1.1. Typy, operatory i wyrażenia ....................................................................................... 3 1.1.1. ZMIENNE, NAZWY........................................................................................................................... 4 1.1.2. PROSTE TYPY DANYCH................................................................................................................. 5

1.2. Stałe......................................................................................................................... 10 1.3. Deklaracje ................................................................................................................ 10 1.4. Operatory arytmetyczne........................................................................................... 10 1.5. Operatory warunkowe .............................................................................................. 11 1.6. Operatory binarne i logiczne .................................................................................... 11 1.7. Słowa kluczowe B&R Automation Basic .................................................................. 13 1.8. Konwersje typów ...................................................................................................... 17 1.8.1. KONWERSJA NIEJAWNA.............................................................................................................. 17 1.8.2. KONWERSJA JAWNA.................................................................................................................... 19

1.9. Nadrzędność i kolejność wykonywania działań........................................................ 21

2. Kontrola wykonywania programu ...........................................................23 2.1. Proste wyrażenia, bloki wyrażeń .............................................................................. 23 2.2. Wyrażenie if ............................................................................................................. 24 2.2.1. IF ..................................................................................................................................................... 24 2.2.2. ELSE ............................................................................................................................................... 26 2.2.3. ELSE IF.......................................................................................................................................... 29

2.2. Wyrażenie case........................................................................................................ 32 2.3. Pętle......................................................................................................................... 34 2.3.1. LOOP … TO … DO ….................................................................................................................... 34 2.3.2. LOOP … DOWNTO … DO ............................................................................................................. 36 2.3.3. WARUNKOWE WYJŚCIE Z PĘTLI ................................................................................................ 36

2.3. Praca krokowa select ............................................................................................... 38 2.4. Wyrażenie goto ........................................................................................................ 43

3. Wskaźniki i złożone typy danych ............................................................44 3.1. Tablice ..................................................................................................................... 45 3.2. Łańcuchy znaków..................................................................................................... 47 3.3. Struktury................................................................................................................... 47 3.4. Adresy...................................................................................................................... 51 3.5. Wskaźniki ................................................................................................................. 53

4. Funkcje i struktura programu..................................................................60 4.1. Funkcje .................................................................................................................... 60 4.2. Typy Funkcji ............................................................................................................. 63 4.2.1. FUNKCJE „INLINE” ........................................................................................................................ 63 4.2.2. BLOKI FUNKCYJNE....................................................................................................................... 64 4.2.3. BLOKI FUNKCYJNE D-I-Y ............................................................................................................. 66

4.2. Struktura Programu.................................................................................................. 69

2

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1. Wstęp Aby pomóc Ci przyswoić język B&R Automation Basic (AB), poniżej przedstawiony jest jego opis i charakterystyka. W systemie pomocy B&R Automation Studio zamieszczony jest pełen opis języka wraz z wieloma przykładami, których przepisanie i sprawdzenie może ułatwić zrozumienie zagadnienia. W opisie tym pomięto również opis interfejsu użytkownika B&R Automation Studio. Temat ten opisany jest w oddzielnym dokumencie oraz w systemie pomocy.

1.1. Typy, operatory i wyrażenia Są to podstawowe składniki języka programowania. Zmienne i stałe są najprostszymi modułami danych, które mogą być użyte w programie. Mogą być używane w połączeniu z operatorami. Wyrażenie jest połączeniem modułów danych i operatorów, czego wynikiem są nowe wartości modułów danych. Typ modułu definiuje, co obiekt może w sobie zawierać i jakie operacje mogą być na nim wykonywane. Ten rozdział - wraz z przykładami - opisuje wszystkie podstawowe komponenty dla dobrego zrozumienia ich działania.

Zmienne i nazwy Proste typy danych Stałe Deklaracje Operatory arytmetyczne Operatory warunkowe Operatory binarne i logiczne Słowa kluczowe AB Konwersje typów Nadrzędność i kolejność wykonywania

3

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1.1.1. Zmienne, nazwy Zmienna jest miejscem do przechowywania wartości. Wartość ta może być czymkolwiek, np. pozycją włącznika (włączony, wyłączony) czy licznikiem zdarzeń. Aby odnieść się do zmiennej musi ona mieć nazwę. Jest kilka zasad nazywania zmiennych: •

Wszystkie zmienne muszą zaczynać się literą.



Pozostałe znaki nazwy mogą być literami, cyframi, podkreślnikiem lub znakiem dolara; pozostałych znaków nie można używać.



Maksymalna długość nazwy zmiennej wynosi 32 znaki.



W nazwie ma znaczenie wielkość liter; przykładowo zmienna switch nie jest tym samym co zmienna SWITCH.



Nazwa zmiennej nie może zawierać spacji.



Zmienna nie może nazywać się tak samo jak słowo kluczowe języka B&RAutomation Basic, np. if, else, loop.

Kierując się powyższymi zasadami, takie zmienne jak: lamp_1, F_int$ są prawidłowe natomiast stop!, 33_light są nieprawidłowe (stop! zawiera niedozwolony znak (!), a 33_light zaczyna się od cyfry). Niezależnie od powyższych zasad, jest jeszcze kilka zaleceń jakimi należy się kierować przy nazywaniu zmiennych: •

Nazwa, jaką się nadaje powinna być krótkim opisem tego, czego zmienna dotyczy. Przykładowo nazwa zmiennej s nic nam nie mówi, nazwa switch jest już lepsza, jednakże optymalną i najbardziej domyślną nazwą jest light_switch.



Przy długich nazwach należy używać podkreślników i wielkich liter w celu rozdzielania słów. Nazwa TopLevelSwitch lub top_level_switch jest lepsza niż toplevelswitch.



Jeżeli nazwa nie opisuje zmiennej w sposób wystarczający należy zastosować komentarz.



Wiele zmiennych zdefiniowanych przez system zaczyna się podkreślnikiem. Własnych zmiennych nie można tak zaczynać jednakże można wykorzystywać te już zdefiniowane w systemie.

4

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1.1.2. Proste typy danych Każda zmienna ma ustalony typ; w B&R Automation Basicu jest ich wiele. Typ opisuje właściwości zmiennej, np. zakres wartości, rozdzielczość liczby przechowywanej w zmiennej lub możliwe do wykonania na niej operacje. B&R Automation Basic posiada następujące typy numeryczne danych: BOOL, UINT, UDINT, SINT, INT, DINT, REAL. Tabela poniżej przedstawia przegląd tych typów:

Dodatkowo istnieją specjalne typy zmiennych do przechowywania łańcuchów znaków (STRING), różnic czasów (TIME) i dat (DATE_AND_TIME).

5

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1.1.2.1. Typ BOOL Typ BOOL może zawierać tylko jedną z dwóch wartości: TRUE (1) lub FALSE (0). Stosowany jest głównie do przechowywania zmiennych typu włącz/wyłącz. 1.1.2.2. Typy liczbowe Typy USINT (BYTE), UINT (WORD) i UDINT (LONG) mogą reprezentować tylko liczby dodatnie. Mogą na przykład służyć do przechowywania wartości numerycznych, znaków ASCII, wartości analogowych. Dla tych typów 0 jest dolnym zakresem a górny zakres podaje tabela powyżej. SINT (INT8), INT (INT16) i DINT (INT32) mogą reprezentować zarówno liczby dodatnie jak i ujemne. Każdy z tych typów ma inny zakres (patrz tabela powyżej). Mogą być wykorzystywane do takich samych zastosowań jak typy opisane wyżej z tą jednak przewagą, iż mogą reprezentować wartości zarówno dodatnie jak i ujemne (np. reprezentacja temperatury, zliczanie w górę/dół). Jeśli wybierzesz niewłaściwy typ w trakcie definiowania zmiennej (np. jej zakres będzie za mały) program może zacząć zachowywać się nieprzewidywalnie. Dla przykładu: jeśli licznik osiągnie wartości zakresu swojej zmiennej to ponownie się przeładuje wartością będącą początkiem zakresu tej zmiennej. Zjawisko to nazywa się przepełnieniem. Największa wartość zmiennej typu USINT to 255. Zmienna typu SINT może przechowywać wartości do 127. Pomimo tego można w nią wpisać wartość większą, np. 200. Jednakże, jeśli sprawdzisz po tym jej zawartość zauważysz, że zamiast liczby 200 zmienna zawierza liczbę -56. Dlaczego? Aby lepiej zrozumieć to zjawisko popatrz na ilustrację poniżej:

6

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Binarny odpowiednik liczby 200 i 56 jest identyczny i wynosi (%11001000) ale sposób w jaki jest wyświetlany zależy od typu danej. Gdy liczba jest przypisana do zmiennej, kompilator nie sprawdza czy zmienna jest w stanie przechować tą wartość czy nie. Musisz sprawdzić sam i upewnić się, że żadne nieoczekiwane przepełnienia nie będą miały miejsca. Przepełnienia mogą wystąpić także przy innych typach danych mających taką samą liczbę bitów, np. INT/UINT lub DINT/UDINT.

1.1.2.3. Typ REAL (FLOAT) Jak na razie zajmowaliśmy się danymi typu całkowitego. Wiele razy jednak mamy do czynienia z sytuacjami, gdzie występują nie tylko typy całkowite, lecz także typy rzeczywiste, np. 32.5 st. C, czy 5.03V. Używając notacji naukowej (mantysa i wykładnik) możemy zapisać zarówno bardzo małe jak i bardzo duże liczby. Przykładowo liczba 1700000000 (1.7*10^9) w B&R Automation Basicu zapisana jest jako 1.7E9 (3 bajty mantysy i jeden bajt wykładnika), co jest zgodne z normą IDEE 754 zapisu liczb rzeczywistych. 7

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Zmienna typu rzeczywistego ma zakres ±3.4E+38. Jeśli wartość ta zostanie przekroczona ustawi się bit powiązany ze zmienną pokazujący w statusie +INF. Najmniejsza dodatnia liczba rzeczywista to +1.18E-38 natomiast największa ujemna to -1.18E-38. Liczby z przedziału pomiędzy nimi wynoszą zero.

Zalety stosowania liczb rzeczywistych są niezaprzeczalne, jednakże należy też wspomnieć o ich wadach. Obliczenia wykonywane na liczbach typu rzeczywistego zajmują do kilkudziesięciu razy więcej czasu niż obliczenia na zmiennych typu całkowitego. Powinno się więc używać ich rozważnie, np. zamiast stosować typ REAL do zapisu 1.25 s lepiej użyć 1250 ms.

1.1.2.4. Typ TIME Ten typ przechowuje różnice czasu. Różnica czasu przechowywana jest w milisekundach w liczbie 32-bitowej. W programie i trybie monitora jest wyświetlana jako dni, godziny, minuty, sekundy, milisekundy. Zakres tego typu: od T#−24d20h31m23s648ms do T#24d20h31m23s647ms. Najmniejsza wartość różna od zera to T#1ms.

8

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1.1.2.5. Typ DATE_AND_TIME Ten typ służy do przechowywania informacji o dacie. Informacja ta, podobnie jak w typie TIME, przechowywana jest w liczbie 32-bajtowej. Wyświetlana jest w formacie określonym przez normę IEC61131-3. Zakres tego typu: od DT#1970−01−01−00:00 do DT#2099−12−31−23:59:59 a najmniejsza wartość to 1 s.

1.1.2.6. Typ STRING Typ ten służy do przechowywania znaków, więc może przechowywać nazwy czy teksty. W deklaracji zmiennej tego typu należy podać maksymalną dopuszczoną liczbę znaków. Przykładowo łańcuch 10 znaków należy zadeklarować jako STRING(10). Łańcuchy znaków przechowywane są jako bajty zawierające kody znaków ASCII umieszczone jeden za drugim. Ostatni bajt jest znakiem końca łańcucha i wynosi zero, nie jest jednak wliczany w długość łańcucha.

1.1.2.7. Jaki typ danych użyć? Czy nie można by po prostu używać zawsze największego typu danych? Można, jednak takie rozwiązanie wiąże się z marnowaniem pamięci, która nie jest nieograniczona i może się w pewnym momencie skończyć. Innym aspektem związanym z używaniem dużych typów jest czas wykonywania na nich obliczeń, dłuższy dla typów większych. Wybierając typ danej należy też pamiętać o tym czy dana będzie występowała jako ujemna czy nie. Zawsze należy zwracać uwagę na to, jak duże będą dane przechowywane w zmiennych i jakie duże będą wyniki w nich przechowywane po wykonaniu obliczeń.

1.1.2.8. Przykłady typów danych Przykład 1: licznik jest zdefiniowany jako typ SINT. Program ma następujące linie kodu: licznik = 127 9

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

licznik = licznik + 1 Następnym krokiem programu będzie przyjęcie przez zmienną licznik wartości -128 ponieważ został przekroczony górny zakres zmiennej typu SINT i nastąpiło przepełnienie. Jeśli w programie dzieją się dziwne rzeczy, jedną z przyczyn może być właśnie przekroczenie zakresu.

1.2. Stałe Stała jest liczbą, która nie zmienia swojej wartości. Stałe występują w systemie i w bibliotekach, mogą być także definiowane przez użytkownika.

1.3. Deklaracje Zmienna zadeklarowana jest następująco: nazwa_zmiennej : NAZWA_TYPU Linia powyżej nie jest linią programu! Jest to tylko informacja, że zmienna jest w jakiś sposób zadeklarowana.

1.4. Operatory arytmetyczne =

przypisanie/równość,

+

dodawanie,



odejmowanie/znak ujemny liczby

*

mnożenie,

/

dzielenie

mod

reszta z dzielenia

Przykład: x=3 y=5

10

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

a = 10 b=5 wynik = x*y + a/b

Najpierw wykonywane jest mnożenie, potem dzielenie (patrz Kolejność wykonywania działań). Następnie powstałe dwa składniki są dodawane i w rezultacie otrzymujemy liczbę 17. Dla pewności można użyć nawiasów, aby w sposób jasny widzieć kolejność wykonywania działań.

1.5. Operatory warunkowe =






>=

= max) or (emergencyStop = 1) then pompa = 0 endif Pompa zostanie wyłączona (pompa = 0) jeśli zostanie przekroczony poziom maksymalny (poziom >= max) albo włączony zostanie wyłącznik awaryjny (emergencyStop = 1) Ogólnie rzecz ujmując możemy zapisać tabelę prawdy następująco:

12

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

gdzie Left oznacza wyrażenie po lewej stronie operatora a Right wyrażenie po prawej stronie. Zarówno Left jak i Right muszą być w nawiasach: (Left) operator (Right).

1.7. Słowa kluczowe B&R Automation Basic access

określa dostęp dynamiczny

action

patrz wyrażenie case

BIT

binarny typ danych

BIT_CLR

A=BIT_CLR(IN, POS) A przyjmuje wartość IN z wyzerowanym bitem na pozycji POS. Operator IN pozostaje niezmieniony

BIT_SET

A=BIT_SET(IN, POS) A przyjmuje wartość IN z ustawionym bitem na pozycji POS. Operator IN pozostaje niezmieniony

BIT_TST

A=BIT_TST(IN, POS) A przyjmuje wartość bitu z pozycji POS słowa IN

case

patrz wyrażenie case

do

patrz wyrażenie loop

downto

patrz wyrażenie loop

EDGE

wykrywanie zbocza opadającego lub narastającego

13

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

EDGENEG

wykrywanie zbocza opadającego

EDGEPOS

wykrywanie zbocza narastającego

else

patrz wyrażenie if

elseaction

patrz wyrażenie case

endaction

patrz wyrażenie case

endcase

patrz wyrażenie case

endif

patrz wyrażenie if

endloop

patrz wyrażenie loop

endselect

patrz wyrażenie select

exitif

patrz wyrażenie loop

FLOAT

typ danych 32-bitowych rzeczywistych

FBK

wywołanie bloku funkcyjnego

goto

patrz wyrażenie goto

if

patrz wyrażenie if

INC

inkrementacja

INT16

typ danych 16-bitowych całkowitych dodatnich i ujemnych

INT32

typ danych 32-bitowych całkowitych dodatnich i ujemnych

INT8

typ danych 8-bitowych całkowitych dodatnich i ujemnych

LONG

typ danych 32-bitowych całkowitych dodatnich

loop

patrz wyrażenie loop

next

patrz wyrażenie select

of

patrz wyrażenie case

select

patrz wyrażenie case

14

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

state

patrz wyrażenie select

then

patrz wyrażenie if

to

patrz wyrażenie loop

when

patrz wyrażenie select

ABS

zwraca bezwzględną wartość liczby

ACOS

zwraca arcus cosinus liczby

adr

zwraca adres zmiennej

AND

logiczne AND

ASIN

zwraca arcus sinus liczby

ASR

arytmetyczne przesunięcie w prawo

ATAN

zwraca arcus tangens liczby

COS

zwraca cosinus liczby

EXP

funkcja wykładnicza A=EXP(IN)

EXPT

funkcja potęgowa A=EXPT(IN1, IN2)

LIMIT

ograniczenie A=LIMIT(MIN, IN, MAX) MIN jest dolnym a MAX górnym ograniczeniem wyniku. Jeśli IN jest mniejsze od MIN zwracana jest wartość MIN. Jeśli IN jest większe od MAX zwracana jest wartość MAX. W pozostałych przypadkach zwracana jest wartość IN

LN

zwraca logarytm naturalny z liczby

LOG

zwraca logarytm dziesiętny z liczby

LSL

patrz SHL

LSR

patrz SHR

MAX

zwraca większą wartość z danych dwóch wartości

15

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

MIN

zwraca mniejszą wartość z danych dwóch wartości

MUX

A=MUX(CHOICE, IN1, IN2, …, INn) zwraca jedną z wartości IN w zależności od CHOICE

OR

logiczne OR

ROL

A=ROL(IN, N) przesuwanie pierścieniowe w lewo wartości IN o N pozycji

ROR

A=ROR(IN, N) przesuwanie pierścieniowe w prawo wartości IN o N pozycji

SEL

A=SEL(CHOICE, IN1, IN2) wybór binarny zależny od CHOICE (typ BOOL). CHOICE=1: zwracana jest wartość IN1, w innym przypadku wartość IN2

SHL

przesuwanie w lewą stronę bit po bicie wartości N: A=ASR(IN, N), prawa strona wypełniana jest zerami

SHR

przesuwanie w prawą stronę bit po bicie wartości N: A=ASR(IN, N), lewa strona wypełniana jest zerami

SIN

zwraca sinus liczby

sizeof

zwraca liczbę bajtów jaką zajmuje zmienna

SORT

zwraca kwadrat liczby

TAN

zwraca tangens liczby

TRUNC

zwraca część całkowitą liczby

XOR

logiczne EXOR

16

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

1.8. Konwersje typów Jeśli operacja dokonuje się na dwóch zmiennych różnych typów, muszą one być skonwertowane do jednego typu. Kompilator automatycznie dokonuje konwersji w górę, czyli mniejsze zmienne zamienia na większe. Popatrz uważnie na przykłady poniżej.

Przykład: byte_pv: USINT, word_pv: UINT, end: UDINT end = byte_pv + word_pv

Kolejność wykonywania operacji jest następująca: byte_pv jest automatycznie konwertowany do typu UINT, wykonuje się dodawania dwóch wartości UINT, wynik tego dodawania jest typu UINT, wynik UINT jest konwertowany na typ UDINT i przechowywany jest w zmiennej end.

Konwersja niejawna Konwersja jawna

1.8.1. Konwersja niejawna

17

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Konwersję tą należy stosować bardzo ostrożnie gdyż może spowodować nieprzewidywalne zachowanie programu.

Przykład 1: dzielna: SINT, dzielnik: SINT, iloraz: REAL dzielna = 3 dzielnik = 4 iloraz = dzielna / dzielnik Wynik (iloraz) równa się 0. Dlaczego? Wykonane zostało dzielenie typów całkowitych (zarówno dzielna, jak i dzielnik są liczbami typu SINT), w związku z tym wynikiem dzielenia jest też liczba całkowita, w tym przypadku równa 0. Wynik jest konwertowany do typu rzeczywistego (do ułamka). Dlatego liczba 0 przedstawiana jest jako 0.0.

Przykład 2: dzielna: SINT, dzielnik: REAL, iloraz: REAL dzielna = 3 dzielnik = 4 iloraz = dzielna / dzielnik Wynik (iloraz) równa się 0.75. Dlaczego? Dzielna jest konwertowana w górę do liczby rzeczywistej (3.0). Teraz dzielna i dzielnik są liczbami rzeczywistymi, więc wynik też jest wartością typu rzeczywistego (0.75). Wynik jest przypisywany do też do zmiennej typu rzeczywistego (do ułamka). Nie wykonywana jest żadna konwersja.

18

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Przykład 3: dzielna: SINT, dzielnik: SINT, iloraz: REAL dzielna = 3 dzielnik = 4 iloraz = float(dzielna) / dzielnik Wynik (iloraz) równa się 0.75. Dlaczego? 1. Dzielna została skonwertowana w górę w sposób jawny (przez programistę) do wartości rzeczywistej. 2. Dzielnik został skonwertowany w górę w sposób niejawny do wartości rzeczywistej. 3. Wykonane zostało dzielenie wartości rzeczywistych. Wynikiem dzielenia jest wartość rzeczywista (0.75). 4. Wynik jest przypisywany do też do zmiennej typu rzeczywistego (do ułamka). Nie wykonywana jest żadna konwersja.

1.8.2. Konwersja jawna

19

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Konwersję typów można dokonywać samemu. Można robić ją w dół (od wartości większej do wartości mniejszej) lub w górę (od wartości mniejszej do wartości większej). Konwersja w górę gwarantuje zawsze prawidłowe rezultaty.

Przykład: int8_pv : type SINT. word_pv : type UINT. end : DINT (the same as before) end = int32(int8_pv) + int32(word_pv)

Uwaga! Pomiędzy PL2000 (pierwotna wersja AB) i Automation Basic występuje różnica przy konwertowaniu z wartości większej do mniejszej typu BOOL. W PL2000 tylko najmłodszy bit jest sprawdzany podczas konwersji. Automation Basic sprawdza wszystkie bity danej. W poniższym przykładzie boolvar ma wartość zero w PL2000 (bit 0 nie jest ustawiony). W Automation Basic natomiast boolvar ma wartość jeden, ponieważ usintvar nie jest zerem. usintvar = 2 boolvar = BIT(usintvar)

Problemy z typami danych mogą wyniknąć również przy stosowaniu zmiennych tego samego typu. Może się tak zdarzyć, że dodając do siebie dwie wartości dojdzie do przepełnienia i wynik działania będzie niepoprawny. Przykład: Temperatura w dużym pomieszczeniu mierzona jest w trzech różnych miejscach. Należy wyliczyć średnią temperaturę w pomieszczeniu. Pomiary trzech temperatur przechowywane są w zmiennych o nazwach: temp_1, temp_2, temp_3 a wynik w zmiennej av_temp. Wszystkie zmienne są typu INT. Podstawowa formuła wykonania działania obliczającego średnią temperatura wygląda następująco: av_temp = 1/(liczba pomiarów) * Suma(temperatury) Jest kilka metod zapisania powyższej formuły w Automation Basicu. Wersja 1 20

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

av_temp = 1/3 * (temp_1 + temp_2 + temp_3)

W tej wersji wynik zawsze będzie zerem gdyż 1/3 jest dzieleniem całkowitym i zawsze da wartość zero.

Wersja 2 av_temp = temp_1/3 + temp_2/3 + temp_3/3

Ta wersja w zasadzie da poprawny wynik, choć nie jest dobrze zapisana. Wersja 3 av_temp = (temp_1 + temp_2 + temp_3) / 3

Ta wersja jest optymalna: najpierw dodane są całkowite wartości temperatur a dopiero potem podzielone są przez 3.

1.9. Nadrzędność i kolejność wykonywania działań W każdym wyrażeniu pierwszy wykonywany jest ten operator, który ma najwyższy priorytet, potem wykonywane są operatory o coraz niższym priorytecie. Operatory o tym samym priorytecie wykonywane są od lewej do prawej strony. Nadrzędność w Automation Basic przedstawia się następująco:

21

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Używając operatorów należy mieć na względzie kolejność ich wykonywania. Używając nawiasów (najwyższy priorytet) kolejność może być dokładnie ustalona. Prosty matematyczny przykład: 6 + 7 * 5 – 3 w zależności od kolejności wykonywania działań albo użycia nawiasów może dać różne wyniki.

22

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

2. Kontrola wykonywania programu Program to lista instrukcji, która nie jest jednak zawsze wykonywana jedna po drugiej, czasem występują przeskoki do innych sekcji w zależności od różnych warunków. Istotą kontroli wykonywania jest takie sterowanie programem, by zawsze dokładnie wiadomo było, co i gdzie program robi. Proste wyrażenia, bloki wyrażeń Wyrażenie if Wyrażenie case Pętle loop Praca krokowa select Wyrażenie goto

2.1. Proste wyrażenia, bloki wyrażeń Proste wyrażenie to pojedyncza linia instrukcji: przypisanie wartości, obliczenie albo wywołanie funkcji. Przykład: init = 0 result = (x2 – x1)/(y2 – y1)

status = DIS_str(0, 1, “hello”)

Bloki wyrażeń to wyrażenia lub instrukcje zajmujące kilka linii. Zawsze zaczynają się i kończą słowem kluczowym.

Przykład: if (x1 < 3) then y2 = y2 + 1

23

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

endif

loop (counter = 1 to 20) do ;... statement(s) endloop

2.2. Wyrażenie if Służy ono do wyrażania decyzji. Może występować w trzech odmianach: if, if-else oraz else if. if else else if

2.2.1. if if warunek then wyrażenie endif

Podstawową zasadą jest, że jeśli warunek jest prawdziwy to wykonywane jest wyrażenie (lub kilka wyrażeń), jeśli natomiast warunek nie jest prawdziwy wykonywane jest wyrażenie (wyrażenia) następujące po endif. Warunek może być prosty lub złożony z kilku operatorów, np. z and czy or. Graf dla wyrażenia if pokazany jest poniżej:

24

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Uwagi dotyczące zapisu: if oraz then muszą być w tej samej linii, wyrażenia nie mogą występować w liniach, w których występuje if i then, endif musi występować jako jedyne w linii. Spójrzmy na przykład: Płyn w pojemniku jest podgrzewany przez palnik. Jeżeli temperatura przekroczy pewną wartość (max_temp) powinien włączyć się alarm.

Program będzie wyglądał następująco: if (curr_temp < max_temp) then hot_alarm = 0 endif

25

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

if (curr_temp >= max_temp) then hot_alarm = 1 endif

2.2.2. else Wyrażenie to stosuje się razem z wyrażeniem if. Składnia wygląda następująco: if (warunek) then wyrażenie A (lub kilka wyrażeń A) else wyrażenie B (lub kilka wyrażeń B) endif

Jeśli warunek jest spełniony wyrażenie A (wyrażenia A) jest wykonywane, jeśli warunek nie jest spełniony wyrażenie B (wyrażenia B) jest wykonywane. Else musi występować w linii jako jedyne słowo. Graf dla wyrażenia if-else pokazany jest poniżej:

Uwagi dotyczące zapisu są takie same jak dla if a dodatkowo: else musi występować w linii jako jedyne słowo.

Program z poprzedniego przykładu można teraz zapisać: if (curr_temp < max_temp) then alarm = 0 else alarm = 1

26

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

endif

2.2.2.1. Zagnieżdżanie Jeżeli istnieje potrzeba zastosowania kilku warunków istnieje możliwość zagnieżdżenia wyrażeń if – else. Oznacza to wstawienie wyrażenia if – else w inne wyrażenie if – else. if (warunek A) then wyrażenie (wyrażenia)A else if (warunek B) then wyrażenie (wyrażenia) B1 else wyrażenie (wyrażenia) B2 endif endif

Najpierw sprawdzany jest warunek A. Jeśli jest on spełniony wykonywane są wyrażenia A po czym program przechodzi do ostatniego endif. Jeśli jednak warunek nie jest spełniony, program przechodzi do drugiego wyrażenia if i sprawdza jego warunek (warunek B). Jeśli jest on prawdziwy wykonują się wyrażenia B1 po czym program przechodzi do następnej instrukcji za drugim endif. Jeśli natomiast nie jest prawdziwy wykonają się wyrażenia B2, po czym program przejdzie do następnej instrukcji za drugim endif. Graf dla zagnieżdżonego wyrażenia if – else wygląda następująco:

27

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Zagnieżdżanie jest bardzo przydatne, jeśli chcemy sprawdzać warunki zależne od innych warunków. Trzeba być jednak ostrożnym i zawsze pamiętać, że każdemu if musi odpowiadać endif. Zagnieżdżać można dowolnie głęboko jednak po kilku zagnieżdżeniach program staje się nieczytelny a po kilkudziesięciu kompilator może nie być w stanie przekompilować listingu ze względu na ograniczoną pamięć. Zbyt głębokie zagnieżdżanie jest złym stylem programowania i powinno się w inny sposób rozwiązywać zadania gdzie występują warunki uzależnione od innych warunków. Aby poprawić czytelność listingu programu należy używać wcięć (tabulatorów) tak jak w przykładach powyżej. Przykład: Do poprzedniego przykładu dodaliśmy teraz alarm niskiej temperatury. Jeśli temperatura spadnie poniżej minimalnego poziomu uaktywni się alarm niskiej temperatury, jeśli natomiast podniesie się ponad poziom maksymalny, uaktywni się alarm wysokiej temperatury.

28

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Kod w języku Automation Basic wygląda następująco: if curr_temp < min_temp then too_cold = 1 else too_cold = 0 if curr_temp >= max_temp then too_hot = 1 else too_hot = 0 endif endif

2.2.3. else if To wyrażenie jest specjalną wersją wyrażenia if. Pozwala na wiele warunków bez konieczności ciągłego używania w nowej linii słowa endif co korzystnie wpływa na przejrzystość kodu programu. Konstrukcja wygląda podobnie do zagnieżdżonego if - else jednak znaczenie jej jest nieco inne. if (warunek A) then wyrażenie (wyrażenia) A else if (warunek B) then wyrażenie (wyrażenia) B else if (warunek C) then wyrażenie (wyrażenia) C else wyrażenie (wyrażenia) D endif

29

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Jak tylko spełniony zostanie jeden z warunków wykonywane jest odpowiadające mu wyrażenie po czym program przechodzi za linię endif. W innym przypadku wykonane zostanie wyrażenie D po czym program przejdzie za linię endif. Uwagi dotyczące if – else: •

występuje tylko jedno endif; else if nie początkuje nowego wyrażenia if (jest kontynuacją pierwszego if) i nie potrzebuje „zamknięcia” endif



może występować wiele else if ale tylko jedno else



każda linia z else if musi być zakończona słowem then



po spełnieniu jednego z warunków wykonywane jest odpowiadające mu wyrażenie (wyrażenia) po czym program przechodzi do lini programu następującej po słowie endif

Wróćmy teraz do naszego przykładu pojemnika z płynem. Załóżmy, że chcemy go podgrzewać z różną mocą w zależności od temperatury. Im niższa temperatura płynu tym większa moc grzania. Pokazuje to rysunek poniżej:

Kod w języku Automation Basic wygląda następująco: ; inicjalizacja off = 0 low = 1 medium = 2

30

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

high = 3 ; program cykliczny if curr_temp < (set_temp*5/10) then heat = high else if curr_temp < (set_temp*8/10) then heat = medium else if curr_temp < set_temp then heat = low else heat = off endif

Używając zagnieżdżonej struktury if – else należałoby napisać (część inicjalizacyjna bez zmian): if curr_temp < (set_temp*5/10) then heat = high else if curr_temp < (set_temp*8/10) then heat = medium else if curr_temp < set_temp then heat = low else heat = off endif endif endif

Dwie powyższe wersje programu działają tak samo jednakże wersja zagnieżdżona jest mniej czytelna. Należy mieć na uwadze fakt, że ktoś inny czytający listing programu (albo nawet Ty sam po jakimś czasie) może mieć trudności z rozszyfrowaniem zagnieżdżonego kodu. Czasem warto zastanowić się nad zmianą zapisu programu z bardzo zagnieżdżonego na rzecz prościej wyglądających wyrażeń. Jednym z nich może być case opisane poniżej.

31

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

2.2. Wyrażenie case Podobne jest do powielonego wyrażenia if - else. Zamiast jednak konieczności pisania za każdym razem warunku, specyfikuje się możliwe odpowiedzi. Podstawowa struktura tego wyrażenia wygląda następująco: case dana of action n0..n1: wyrażenie (wyrażenia) A endaction action n2..n3: wyrażenie (wyrażenia) B endaction action constant: wyrażenie (wyrażenia) C endaction elseaction: wyrażenie (wyrażenia) D endaction endcase

Poniższy diagram tłumaczy zasadę działania wyrażenia case

32

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Tylko jedna akcja w trakcie działania wyrażenia case może być wykonana. Jeśli expression nie mieści się w przedziałach n0…n1, n2…n3 ani nie jest równe stałej constant to zostaną wykonane wyrażenia D. Przykład: Napiszmy program, który załącza różne moce grzania w zależności od temperatury podgrzewanego płynu i ustawienia zadanej temperatury. Będziemy dokonywali jednego z poniższych wyborów: jeśli bieżąca temperatura jest z przedziału (0 – 49%) wartości zadanej to włącz grzanie na poziom high jeśli bieżąca temperatura jest z przedziału (50 – 79%) wartości zadanej to włącz grzanie na poziom medium jeśli bieżąca temperatura jest z przedziału (80 – 99%) wartości zadanej to włącz grzanie na poziom low w innym przypadku wyłącz grzanie zakończ

Kod w języku Automation Basic wygląda następująco: ; część inicjalizacyjna ; poziomy grzania off = 0 low = 1 med = 2 high = 3 ; początkowy stan grzalki heat = off ; main program section case (curr_temp*100/set_temp) of action 0..49: heat = high endaction action 50..79: heat = med endaction action 80..99:

33

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

heat = low endaction elseaction: heat = off endaction endcase

Wartości action mogą być tylko stałymi, nie mogą być zmiennymi. To, do którego zakresu należą sprawdzane jest tylko jeden raz przy wejściu do wyrażenia case. Wyrażenie case jest najlepszym wyjściem, gdy mamy do czynienia z wieloma wyborami. Zapis jest bardzo przejrzysty i ułatwia programiście szybkie zorientowanie się, co i gdzie w danej chwili dzieje się w programie.

2.3. Pętle Pętla jest częścią programu, której wykonywanie jest powtarzane. O tym, ile razy ma być powtórzone decyduje licznik pętli lub warunek wyjścia z pętli. loop …to…do… loop…downto…do Warunkowe wyjście z pętli

2.3.1. loop … to … do … Podstawowa struktura pętli wygląda następująco: loop PV = liczba to licznik do wyrażenie (wyrażenia) endloop

Po wejściu do pętli PV przyjmuje wartość liczby a następnie wykonywane są wyrażenia i inkrementowana jest liczba. Czynności te będą powtarzać się tak długo aż liczba nie przekroczy wartości licznik. Wtedy program przejdzie do lini następującej po słowie endloop. Graf pętli loop wygląda następująco:

34

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Przykład: Otrzymujemy pakiety danych, które składają się z 10 liczb typu INT i sumy kontrolnej. Należy obliczać sumę kontrolną dla każdego pakietu (nazwaną check_new) i jeśli nie zgadza się ona z tą do nas przesłaną (check_old) należy zasygnalizować błąd. Sumę kontrolną liczy się przez zwykłe dodanie wszystkich dziesięciu wartości do siebie (może wystąpić przepełnienie, ale to nie jest w tym przykładzie ważne). Schemat programu wygląda następująco: wylicz check_new if check_new różni się od check_old then sygnalizuj błąd endif

Wersja 1:

35

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

check_new = data[0] + data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7] + data[8] + data[9] if check_new check_old then error = 1 endif

Jest ona poprawna jednakże mało czytelna. Gdybyśmy mieli np. 500 danych to dodawanie ich w taki sposób byłoby w ogóle nieczytelne. Wersja 2: check_new = 0 loop index = 0 to 9 do check_new = check_new + data[index] endloop if check_new check_old then error = 1 endif

Ta wersja jest dużo lepsza od poprzedniej. Gdybyśmy chcieli zmienić np. liczbę składników sumy wystarczy zmienić jeden indeks w programie.

2.3.2. loop … downto … do Ta pętla działa niemal identycznie do pętli przedstawionej powyżej, jedyną natomiast różnicą jest to, ze licznik jej nie jest inkrementowany a dekrementowany.

2.3.3. Warunkowe wyjście z pętli Jeżeli pętla nie ma licznika mówiącego ile razy ma się powtórzyć, musi mieć warunek wyjścia. Struktura takiej pętli jest następująca: loop statement(s)A exitif condition statement(s)B endloop

36

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Ta pętla powtarzana jest tak długo aż nie zostanie spełniony warunek wyjścia. Używanie jej niesie z sobą to ryzyko, że jeśli warunek wyjścia nigdy nie zostanie spełniony, pętla będzie wykonywała się nieskończenie i program nigdy z niej nie wyjdzie.

Poniższy przykład powinien wyjaśnić różnice między pętlami z warunkowym wyjściem a wyjściem zależnym od licznika. Prowadzimy kontrolę jakości. Wszystkie sprawdzane artykuły są ważone a ich wagi zapisywane. Następnie lista wag jest sortowana od największej do najmniejszej. Pewna waga artykułu jest minimalną akceptowalną w procesie kontroli jakości. Zadaniem do zrealizowanie jest procentowe obliczenie ile produktów zostało zaakceptowanych. Zapiszmy ten problem w sposób strukturalny: start od początku posortowanej listy start pętli sprawdź wagę artykułu, jeśli za mała to wyjdź z pętli sprawdź, czy wykorzystano wszystkie artykuły, jeśli tak to wyjdź z pętli inkrementuj liczbę dobrych artykułów koniec petli

37

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Aby powyższą strukturę zapisać w języku BR Automation Basic należy wprowadzić kilka zmiennych. Liczba wszystkich artykułów w poddanych kontroli to total, lista wag produktów przechowywana jest w tablicy nazwanej weights. Minimalna akceptowalna waga to min_weight. total : USINT, count : USINT, min_weight : USINT, weights[100] : USINT, quality : UINT total = 99 count = 0 loop exitif (weights[count] < min_weight) exitif (count >= total) count = count + 1 endloop quality = UINT(count) * 100 / total

Wyjście warunkowe zamiast wyjścia zależnego od licznika pętli używamy wtedy, gdy nie jest nam znana dokładnie liczba, przy której program ma opuścić pętlę.

2.3. Praca krokowa select Jest to instrukcja z określoną liczbą stanów. Pozostaje ona w jednym ze stanów tak długo aż nie otrzyma komendy do jego zmiany. Rezultatem takiego działania jest to, że za każdym razem, gdy program wchodzi w ten obszar kodu tylko aktualny stan jest wykonywany. Dodatkowo umieszczone w nim są warunki (lub jeden warunek), które – jeśli zostaną spełnione – spowodują zmianę stanu w następnym cyklu. Budowa tej konstrukcji wymaga wyrażenia select i wygląda następująco: select state stan1 wyrażenie (wyrażenia)1A when warunek1 next stan2 wyrażenie (wyrażenia)1B state stan2 wyrażenie (wyrażenia)2A when warunek2

38

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

wyrażenie (wyrażenia)2B next stan3 state stan3 wyrażenie (wyrażenia)13 when warunek3 next stan1 endselect

Tylko jeden stan (state) jest wykonywany podczas działania konstrukcji select. Przechodzenie między stanami możliwe jest, gdy spełniony jest warunek przejścia aktualnie wykonywanego stanu. W przykładzie powyżej najpierw wykonywany będzie stan1, czyli wyrażenia 1A. Zmiana stanu na stan2 nastąpi, gdy warunek1 zostanie spełniony – zaczną wtedy być wykonywane wyrażenia 2A. Gdy teraz spełniony zostanie warunek2, wykonają się wyrażenia 2B, po czym program przejdzie do stanu3. Najlepiej wytłumaczyć działanie konstrukcji select na przykładzie. Zbudujmy prosty kawomat, który może sprzedawać – dla ułatwienia – tylko czarną lub białą kawę. Kawa kosztuje 25 centów, maszyna przyjmuje tylko sumy będące kombinacją monet pięcio- i dziesięcio- centowych a także wydaje resztę (jeśli przyjęta suma jest większa niż 25 centów). Najpierw musimy zastanowić się, jakie stany maszyny będą nam potrzebne. Na pewno konieczne będzie użycie stanów związanych z „przepływem” pieniędzy, czyli 0, 5, 10, 15, 20 i 25 centów. Zainicjalizowanie działania kawomatu odbywa się przez wrzucenie do niego monet lub wciśnięcie przycisku wyboru kawy. Diagram jego pracy wygląda następująco:

39

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

6 powyższych stanów maszyny określa całkowitą sumę wrzuconych do niej monet, przykładowo T_20 oznacza 20 centów. Przerywane linie oznaczają wrzucone monety, szare linie to wciśnięcie przycisku a czarne strzałki mówią o tym, co maszyna w danej chwili robi (wydaje kawę, wydaje resztę pieniędzy). Maszyna zaczyna i kończy pracę w stanie T_0. Pseudokod jej działania podany jest poniżej: state T_0: when a 5c coin inserted, change to T_5 when a 10c coin inserted, change to T_10 state T_5: when a 5c coin inserted, change to T_10 when a 10c coin inserted, change to T_15 state T_10: when a 5c coin inserted, change to T_15 when a 10c coin inserted, change to T_20

40

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

state T_15: when a 5c coin inserted, change to T_20 when a 10c coin inserted, change to T_25 state T_20: when a 5c coin inserted, change to T_25 when a 10c coin inserted, give back 5c and change to T_25 state T_25: when a 5c coin inserted, give back 5c when a 10c coin inserted, give back 10c when the black key is pressed, dispense black coffee and change to T_0 when the white key is pressed, dispense milk and coffee, and change to T_0

Teraz przetłumaczmy powyższy pseudokod na język BR Automation Basic. Musimy napisać select i endselect oraz stworzyć sensownie nazwane zmienne, aby w sposób jasny i zrozumiały mówiły nam czego dotyczą. Wszystkie zmienne mogą być typu BOOL, ponieważ reprezentują tylko informację TRUE/FALSE (np.: wciśnięty przycisk – tak lub nie, suma pieniędzy w kawomacie równa 25 centów – tak lub nie). Program wygląda następująco: select state T_0 when coin_5 = 1 next T_5 when coin_10 = 1 next T_10 state T_5 when coin_5 = 1 next T_10

41

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

when coin_10 = 1 next T_15 state T_10 when coin_5 = 1 next T_15 when coin_10 = 1 next T_20 state T_15 when coin_5 = 1 next T_20 when coin_10 = 1 next T_25 state T_20 when coin_5 = 1 next T_25 when coin_10 = 1 return_5 = 1 next T_25 state T_25 if coin_5 = 1 then return_5 = 1 else if coin_10 = 1 then return_10 = 1 endif when black_key = 1 coffee = 1 next T_0 when white_key = 1 milk = 1 coffee = 1 next T_0 endselect

Zaawansowana konstrukcja select Konstrukcja select wraz ze wszystkimi “dodatkami” wygląda następująco: select gdzie_jestem wyrażenia 0

42

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

state stan1 wyrażenia 1A when warunek1 next stan2 wyrażenia 1B state stan2 wyrażenia 2A when warunek2 wyrażenia 2B next stan3 state stan3 wyrażenia 3 when warunek3 next stan1 endselect

Wyrażenia 0 wykonywane są przy każdym wejściu do konstrukcji select przed przejściem do właściwego stanu. W wyrażeniach 0 można także użyć warunków przejścia. Jest to bardzo przydatne przy sprawdzaniu np. wystąpieniu globalnego błędu aczkolwiek nie jest polecane do zwykłych zastosowań. Zmienna gdzie_jestem (musi być typu UINT) podaje numer stanu, w którym aktualnie znajduje się program. Zmieniając tą zmienną w programie można przechodzić pomiędzy stanami konstrukcji select, jednakże należy robić to bardzo ostrożnie. Nieoczekiwane wejście do któregoś ze stanów spowodować może bardzo dużo zamieszania, ponieważ zmienne mogą przyjąć równie nieoczekiwane wartości. Operacji na zmiennej gdzie_jestem można dokonywać tylko wtedy gdy naprawdę jest to uzasadnione i przemyślane.

2.4. Wyrażenie goto W języku BR Automation Basic występuje polecenie skoku (goto) do innej części programu (label), ale nie jest zalecane jego stosowanie. Zawsze można zastosować inne rozwiązanie niż właśnie goto. Należy pamiętać, że nie jest dobrym stylem stosowanie skoków do innej części programu.

43

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Przykładem zastosowania goto jest wyjście z mocno zagnieżdżonej struktury w momencie np. wystąpienia jakiegoś błędu. Przykład: loop ... to ... do loop ... to ... do if ... then loop if (problem) then goto recover endif endloop endif endloop endloop ... ... ... recover: rozwiąż problem

3. Wskaźniki i złożone typy danych Dotychczas poznawaliśmy proste typy danych. Często jednak ma się do czynienia z typami złożonymi, które mają tę zaletę, że mogą przyspieszyć wykonywanie programu i podnoszą jego skuteczność. Są nimi: •

tablice



łańcuchy znaków



struktury



adresy



wskaźniki

44

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

3.1. Tablice Zwykłą zmienną można traktować jak pojedyncze pudełko do przechowywania danej. Jeśli mamy kilka zmiennych mamy także kilka pudełek. Aby mieć dostęp do nich wszystkich, musimy mieć dostęp do wszystkich pudełek osobno. W tablicy natomiast wszystkie zmienne są ze sobą powiązane. Oznacza to, że można odnosić się do nich za pomocą jednej nazwy, co jest podstawową zaletą używania tablic. Jeśli chcemy działać na pewnej liczbie zmiennych tego samego typu, np. zapisywać je, odczytywać czy przechowywać, należy się mocno zastanowić nad użyciem właśnie tablicy. Może to uprościć program i sprawić, że będzie on bardziej przejrzysty. Aby użyć zmiennej tablicowej, trzeba podać nie tylko jej nazwę, ale także jej indeks wskazujący, do którego elementu chcemy się odwołać. W pamięci tablica wygląda następująco:

Jak widać struktura tablicy jest dość prosta. Aby dostać się do jej poszczególnych elementów należy posłużyć się nawiasami kwadratowymi, np. aby trzeciemu elementowi zmiennej tablicowej o nazwie value nadać wartość 70 należy napisać value[2] = 70 (value[2] a nie value[3] ponieważ numeracja zaczyna się od zera). Zmiennych tablicowych używa się głównie wtedy, gdy mamy do czynienia z operacjami na seriach danych, np. wyliczenie średniej temperatury ze stu pomiarów. Przykład: Mamy maszynę, która wydaje 8 rodzajów napoi: colę, lemoniadę, sok pomarańczowy, cytrynowy, jabłkowy, wiśniowy, bananowy i wodę. Zadaniem programu jest wydanie napoju w zależności od tego, który został wybrany (kwestię zapłaty w tym zagadnieniu pomijamy). Z każdym napojem powiązany jest jeden przycisk, który ma wartość, 1 gdy jest wciśnięty a 0 gdy nie jest. Pseudokod programu wygląda następująco: 45

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

sprawdź przycisk jeśli przycisk wciśnięty to wydaj napój i wyjdź

Kod w języku B&R Automation Basic wygląda następująco: cola : BOOL, lemonade : BOOL, orange : BOOL, lime : BOOL, mineral : BOOL, cherry : BOOL, banana : BOOL, apple : BOOL if cola = 1 then dispense(1) else if lemonade = 1 then dispense(2) else if orange = 1 then dispense(3) else if lime = 1 then dispense(4) else if mineral = 1 then dispense(5) else if cherry = 1 then dispense(6) else if banana = 1 then dispense(7) else if apple = 1 then dispense(8) endif

Powyższy zapis nie jest najlepszy, ponieważ każda zmienna musiała być przetestowana. Gdybyśmy mieli tych zmiennych 100 czy 200 program byłby bardzo długi, przez co nieczytelny. Możemy jednak zapsiać tak jak poniżej, używając pętli: drinks[8] : BOOL, index : USINT loop index= 0 to 7 do if drinks[index] = 1 then dispense(index+1) endif exitif drinks[index] = 1 endloop

46

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

3.2. Łańcuchy znaków Stanowią specjalny typ tablicy. Jeśli chcemy przechowywać informacje do wyświetlenia lub druku, przechowujemy je w tablicy znaków. Pojedynczy znak może być przechowywany w zmiennej typu USINT. Jeśli więc mamy do czynienia z ciągiem znaków (łańcuchem znaków) potrzebujemy tablicy typu USINT. Jej rozmiar musi odpowiadać długości łańcucha. Znakiem końca ciągu znaku jest wartość 0 umieszczona bezpośrednio za ostatnim elementem łańcucha (wartość zero, nie kod ASCII liczby zero!), która jest informacją, że w danym miejscu kończy się ciąg (dodatkowy znak na końcu). Jak wszystkie zmienne, tak i w łańcuchach znaków należy zainicjalizować wszystkie jego elementy. W przeciwnym wypadku na końcu łańcucha mogą się znajdować „śmieci”. Istnieje szereg funkcji, które operują na łańcuchach znaków, np. strcpy() – kopiuje jeden łańcuch do drugiego, strcat() – dodaje jeden łańcuch na koniec drugiego (konkatenacja), strlen() – oblicza długość łańcucha (do znaku końca), Szczegółowe informacje na temat wszystkich bibliotek, w tym również biblioteki AsString zawierającej funkcje na łańcuchach znaków znajdują się w systemie pomocy B&R Automation Studio.

3.3. Struktury Struktura jest zbiorem zmiennych, nawet różnych typów, zebranych razem. Użycie struktur lepiej organizuje zmienne. Zestawienie zmiennych w logiczne zbiory daje lepszą przejrzystość niż serie nieuporządkowanych danych. Struktury są często stosowane w językach wysokiego poziomu. Struktury w B&R Automation Basic są podobne do struktur używanych w języku C albo rekordów w Pascalu. Przykładem wykorzystania struktur w przemysłowej aplikacji pozycjonowania może być punkt, którego określają współrzędne x, y, z albo wszystkie informacje związane z warunkami przechowywania płynu w kontenerze: wysokość, szerokość, objętość, maks. ciśnienie, poziom cieczy, typ cieczy, data napełnienia itd. Możliwości wykorzystania struktur są nieskończone. Uporządkować można tak wszystkie grupy albo zestawy zmiennych, które należą do jednego zbioru.

47

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Oczywiście elementy struktur mogą być różnych typów w różnej kolejności. Elementami struktur mogą być zmienne prostych typów, tablice, łańcuchy znaków oraz inne struktury. Struktura jest typem danych i ma swoją nazwę (jak BOOL, INT itd.). Definicja typu strukturalnego Struct_name: Struct_name {element1: TYP, element2: TYP…..} Nazwa zmiennej typu strukturalnego Struct_name: var_name: Struct_name

Deklaracja zmiennej

Przykład: Chcemy przechowywać trójwymiarową współrzędną punktu. Wykorzystując proste typy danych potrzebujemy trzech zmiennych: punkt_x: REAL, punkt_y: REAL, punkt_z: REAL.

Albo zdefiniować strukturę i używać tylko jednej zmiennej: WSPOLRZ {x: REAL, y: REAL, z: REAL} punkt: WSPOLRZ

Przykład: Mamy prosty system pozycjonowania z 5 punktami docelowymi. Maszyna musi przejść przez wszystkie 5 punktów w odpowiedniej kolejności. Znana jest prędkość maszyny (w jedn./s) i punkty docelowe. Należy obliczyć całkowitą przebytą drogę maszyny (w jedn.) i czas potrzebny na 48

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

wykonanie całej operacji. Zakładamy dwuwymiarowy układ, więc potrzebujemy tylko współrzędnych x i y. Ruch odbywa się po następującej ścieżce:

Dystans pomiędzy dwoma punktami wynosi:

dyst = ( x2 − x1 ) 2 + ( y 2 − y1 ) 2

SQRT(a) jest funkcją obliczającą pierwiastek - ( a ). Do obliczania potęg liczb służy funkcja EXPT(a,b) - ( a b ). Przy założeniu, że mamy daną prędkość i punkty docelowe nasz pseudokod wyglądałby następująco: ustaw dystans = 0 dla każdej pary punktów oblicz dystans między nimi dodaj do całkowitej drogi oblicz czas jako zadany dystans/prędkość

Mając algorytm można przystąpić do definicji struktur, deklaracji zmiennych i pisania kodu programu. Napiszemy dwie wersje programu: pierwszą prostą i drugą ulepszoną wykorzystującą dotychczas zdobytą wiedzę. Wersja 1: 49

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

WSPOLRZ {x: REAL, y: REAL} p1: WSPOLRZ, p2: WSPOLRZ, p3: WSPOLRZ, p4: WSPOLRZ, p5: WSPOLRZ dyst: REAL, prędkosc: REAL, czas: REAL rozn: REAL, x_rozn: REAL, y_rozn: REAL if (predkosc = 0) then predkosc = 10 endif dyst = 0 x_rozn = p2.x – p1.x y_rozn = p2.y – p1.y rozn = SQRT(EXPT(x_rozn, 2) + EXPT(y_rozn, 2) ) dyst = dyst + rozn x_rozn = p3.x – p2.x y_rozn = p3.y – p2.y rozn = SQRT(EXPT(x_rozn, 2) + EXPT(y_rozn, 2) ) dyst = dyst + rozn x_rozn = p4.x – p3.x y_rozn = p4.y – p3.y rozn = SQRT(EXPT(x_rozn, 2) + EXPT(y_rozn, 2) ) dyst = dyst + rozn x_rozn = p5.x – p4.x y_rozn = p5.y – p4.y rozn = SQRT(EXPT(x_rozn, 2) + EXPT(y_rozn, 2) ) dyst = dyst + rozn czas = dyst / predkosc

Patrząc na strukturę programu, wydaje się ona dość nieczytelna, nawet używając struktur. Byłoby znacznie lepiej gdyby nie powtarzać kawałków programu kilka razy. Co, jeśli mielibyśmy 100 albo 1000 punktów? Stwórzmy więc tablicę punktów, czyli tablicę struktur. To uprości program i skróci program. Wersja 2: WSPOLRZ {x: REAL, y: REAL} punkt[5]: WSPOLRZ dyst: REAL, predkosc: REAL, czas: REAL

50

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

rozn: REAL, x_rozn: REAL, y_rozn: REAL, indeks: USINT if (predkosc = 0) then predkosc = 10 endif dyst = 0 loop indeks = 0 to 3 do x_diff = punkt[indeks+1].x – punkt[indeks].x y_diff = punkt[indeks+1].y – punkt[indeks].y rozn = SQRT(EXPT(x_rozn, 2) + EXPT(y_rozn, 2) ) dyst

= dyst + diff

endloop time = dist / speed

Choć na pierwszy rzut oka program wygląda bardziej skomplikowanie, jest on znacznie ulepszony. Należy zwrócić uwagę na indeksy i ich odwołanie do poszczególnych elementów tablicy. W przypadku większej ilości punktów wystarczy zwiększyć rozmiar tablicy i liczbę końca pętli. Pamiętaj, że 5 elementową tablicę indeksuje się od 0 do 4. Jak widać, można stosować same struktury, tablice struktur, struktury struktur itd. Istnieją jednak pewne ograniczenia: •

Nie można zagnieżdżać struktur (tablic struktur, struktur struktur) głębiej niż do 5 poziomu,



Na każdym poziomie może być maksymalnie 100 elementów,



Struktura nie może mieć więcej niż 32KB pamięci (dodane wszystkie elementy nie zapominając o równaniu bajtów – tzw. byte allignment).

3.4. Adresy Gdy używamy zmiennych, zazwyczaj odnosimy się do nich za pomocą ich nazw. W rzeczywistości zmienna musi być przechowywana gdzieś w pamięci, do której to odwołuje się CPU właśnie przez adresy. Gdy deklarujemy jakąś zmienną, CPU rezerwuje dla niej pewien obszar pamięci. Jeśli zdefiniujemy cztery zmienne, CPU umieści je prawdopodobnie jedną obok drugiej. Nie musi tak

51

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

zrobić; zrobi tak by przestrzeń wykorzystana została jak najbardziej efektywnie. Pamięć jest alokowana w jednobajtowych blokach. Przykład: Output : USINT, Wait_time : UINT, Elapse : UDINT, Notify[4] : USINT

Można tutaj zaobserwować rozmiar zmiennych w pamięci. Adres każdego z bloków pokazany jest poniżej rysunku. Jeśli zapytamy o adres zmiennej Wait_time to odpowiedzią będzie $A002. Czasem potrzeba zmiennej do przechowywania adresu. Adres zawsze przechowuje się w typie UDINT. Stwórzmy zmienną an_address i przechowajmy w niej adres zmiennej Wait_time. Wait_time : UINT, an_address : UDINT an_address = adr(Wait_time)

an_address zawiera teraz wartość $A002. Funkcja adr() znajduje adres zmiennej spomiędzy

nawiasów. Funkcja zawsze zwraca adres pierwszego bajtu zmiennej. Jeśli zapiszemy: an_address = adr(Elapse)

an_address wyniesie $A004. Gdy mamy do czynienia z tablicą i wykorzystamy funkcję adr() to

zwrócony zostanie adres pierwszego jej elementu. Zapis: an_address = adr(notify)

zwróci wartość $A008. Można także otrzymać adres któregoś elementu tablicy zapisując: an_address = adr(notify[2])

52

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Otrzymamy wtedy: $A00A. Tablice mają kilka specyficznych cech. Jej elementy są zawsze ułożone jeden pd drugim. Oznacza to, że jeśli znamy rozmiar każdego elementu i adres pierwszego elementu można obliczyć adres innych elementów. Znajdźmy trzeci element tablicy notify: an_address = adr(notify) an_address = an_address + 2

Rezultat tego działania jest taki sam jak z poprzedniego przykładu. Funkcja zwracająca adresy działa również na strukturach. struct{New : USINT, Effort : UINT, Work[26] : USINT, Origin : USINT} temp_var : struct an_address = adr(temp_var.Work[8])

an_address zawiera teraz adres ósmego elementu komponentu Work zmiennej temp_var.

3.5. Wskaźniki Wskaźnik jest odwołaniem się do zmiennej pod inna nazwą. Rysunek poniżej prezentuje taką sytuację:

Zmienna var_2 ma dynamiczny dostęp do zmiennej var_1. Dynamiczny dostęp oznacza, że podczas działania programu var_2 jest powiązana z var_1. Jakakolwiek zmiana var_1 wiąże się z taką samą zmianą var_2 i na odwrót, jednakże po takim „powiązaniu” korzysta się tylko ze zmiennej dynamicznej wskazującej na zmienną statyczną. Jak przypisać wskaźnik do zmiennej?

Zmienna wskaźnikowa musi mieć dostęp do zmiennej statycznej. Zapis jest następujący: var_1 : USINT, var_2 : USINT (dynamic) var_2 ACCESS adr(var_1)

lub podobnie: var_1 : USINT, var_2 : USINT (dynamic), address : UDINT

53

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

address = adr(var_1) var_2 ACCESS address

Aby pokazać, jakim narzędziem są wskaźniki posłużymy się przykładem bez większego sensu, ale trafnie demonstrującego ten rodzaj zmiennych. x : USINT, y : USINT, z[10] : USINT ptr : USINT (dynamic) x = 2 ;initial assignment y = 6 ;initial assignment z[0] = 8 ;initial assignment ptr access adr(x) ;ptr points to x y = ptr ;y = 2 ptr access adr(y) ;ptr points to y ptr = z[0] ;y = 8 ptr access adr(z) ;ptr points to z[0] ptr = 70 ;z[0] = 70

Wskaźnik może wskazywać na różne zmienne, należy jednak pamiętać, że powinien być tego samego typu co zmienna, którą wskazuje. Do czego jeszcze może być użyty wskaźnik? Zamiast używania tablic struktur, wskaźniki mogą być użyte do powiązania struktur razem. Nazywa się to zwykle dynamicznie łączoną listą. Dynamicznie dlatego, że może zmieniać się jej rozmiar a łączoną dlatego, że elementy muszą być ze sobą powiązane. To wyjaśnienie stanie się zrozumiałe po prześledzeniu poniższych przykładów. Mamy trzy zmienne, które są prostymi strukturami zawierającymi liczbę i wskaźnik do następnego elementu. Są one ułożone w formie listy. Trzeba wyzerować wszystkie liczby znajdujące się na liście. Po pierwsze, należy stworzyć struktury, wypełnić je oraz przyporządkować wskaźniki. struct{nxt : UDINT, number : USINT} var_1 : struct, var_2 : struct, var_3 : struct, current : struct ;fill in the numbers var_1.number = 26 var_2.number = 8 var_3.number = 70 ;assign the pointers var_1.nxt = adr(var_2)

54

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

var_2.nxt = adr(var_3) var_3.nxt = 0 current access adr(var_1)

Oznacza to, iż nasza lista wygląda teraz tak:

Zmienna wskazuje element na liście, który obecnie używamy. Podobnie jest z indeksem tablicy. Aby przejść przez listę należy użyć pętli, która została już opisana. loop current.number = 0 ;clear the current ;element exitif current.nxt = 0 ;exit if the end ;of the list ;reached current access current.nxt ;move to the next ;element in the ;list endloop

Proszę zauważyć, że składnik nxt tej struktury jest adresem kolejnego elementu na liście, w związku z tym nie trzeba znowu używać funkcji adr(). Spójrzmy na każdą iterację pętli, aby dokładnie dowiedzieć się, w które miejsca wskazują wskaźniki i co się dzieje w danym momencie. Koniec pierwszej iteracji pętli

55

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Bieżący wskaźnik zmienił wartość, którą użył aby wskazać 0. Następnie przesunął się, aby wskazać to, co poprzedni element (var_1) wskazywał (var_2). Koniec powtórzenia drugiej pętli

Jest to koniec pętli, ponieważ został napotkany warunek wyjścia (nxtcomponent = 0). Zwróćmy uwagę na to jak wskaźniki podążały za naszym bieżącym wskaźnikiem, aby poruszać się wzdłuż listy. Jest kilka dodatkowych, specjalnych wskaźników dla listy. Są one po to, aby utrzymać ścieżkę początku listy a może też i końca listy. Listy posiadają wskaźniki biegnące w obydwu kierunkach, dlatego też można poruszać się wzdłuż listy do przodu i do tyłu. Dlaczego więc nie użyć tablicy?

Jedną z wielu korzyści używania wskaźników jest to, że wszystkie informacje pozostają dokładnie w tym samym miejscu. Lista może być przestawiona, ale zmienione zostaną tylko wskaźniki. Jeżeli używamy tablicy, kiedy dwa elementy są zamienione, to każdy składnik struktury musi być skopiowany do nowego miejsca. Jeżeli natomiast używamy listy wskaźnikowej, to zostawiamy wszystkie informacje tam gdzie są i przestawiamy tylko wskaźniki. Tak samo postępujemy przy wprowadzaniu elementów do listy. W przypadku tablicy wszystkie elementy po wprowadzeniu

56

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

muszą być przesunięte, wzdłuż, ale zamiast tego kiedy używamy wskaźniki, tylko wskaźniki muszą być przestawione. Można to wyraźnie zaobserwować na diagramie.

Czasami nie wiadomo ile elementów potrzeba użyć w tablicy. Co powinno się wtedy zrobić? Utworzyć tablicę tak dużą jak to możliwe i zmarnować dużo pamięci? Utworzyć ją tak dużą jak potrzeba i mieć nadzieję, że ona tego nie przekroczy? Kiedy używamy struktur dynamicznych danych, dodatkowe elementy mogą być dodawane podczas używania, kiedy jest to potrzebne. Jak duża jest moja zmienna?

Występuje jeszcze jedna funkcja, którą przypisuje się adresom i wskaźnikom. Podczas używania wskaźników nie zawsze wiadomo jak duża jest rzecz, z którą mamy do czynienia. Istnieje funkcja, która ją obliczy. Używa się jej w podobny sposób do funkcji adr(), czyli tak: var_size : UINT, var : ANYTHING var_size = sizeof(var)

Zmienna var_size zawiera liczbę bajtów var zajmowaną w pamięci. Jeśli var jest sześcioelementową tablicą USINT to var_size też będzie wynosił 6. Całkiem przydatne jest posiadanie tabeli z liczbą bajtów dla każdego typu danych.

57

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

*) zwraca liczbę bitów

Tablice

Teraz powinniśmy znać wielkość tablicy w bajtach. Trzeba być ostrożnym, jeżeli zmienna jest typu BOOL, ponieważ w tym przypadku sizeof zwróci liczbę bitów. Struktury

Zwróćmy uwagę na trzecią kolumnę w tablicy. Sizeof zawsze zwraca parzystą liczbę dla wielkości struktury. Dzieje się tak, ponieważ każda struktura i wszystkie elementy struktury muszą rozpoczynać się od parzystego adresu. Także, jeśli w strukturze element powinien jednak zaczynać się od nieparzystego adresu, bajt jest pozostawiony wolny a składnik rozpoczyna się od następnego parzystego adresu. Przykład powinien to wszystko rozjaśnić: Mamy prostą strukturę z dwoma składnikami struct{item_1 : USINT, item_2 : UDINT}

Deklarujemy zmienną tego typu i wykonujemy sizeof() na niej: result : UINT, test : struct result = sizeof(test)

Jaki powinien być rezultat? Patrząc na długość w powyższej tabeli (kolumna 2), typ USINT ma długość 1 a UDINT 4, dlatego też wydaje się, że result powinna wynosić 5. Jednak nie! Wynosi on 6 (użyj kolumny 3 powyższej tabeli). Struktura zawsze zaczyna się od parzystego adresu w pamięci.

58

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Oznacza to, że po przydzieleniu bajtu kolejny adres jest nieparzysty. UDINT musi być ustawiony zaczynając od parzystego bajtu, więc pusty bajt jest pozostawiony pomiędzy. Jeżeli struktura jest zdeklarowana w odwrotny sposób, czyli tak: struct{item_2 : UDINT, item_1 : USINT}

funkcja sizeof nadal będzie zwracała 6. Pusty bajt jest nadal przyłączany do „końca” struktury. Jak formowana jest struktura, przedstawiona jest poniżej.

59

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

4. Funkcje i struktura programu Rozdział ten dotyczy łączenia wszystkich części, które omówiliśmy do tej pory, w pełny obraz. W rozdziale zostały opisane także bardzo wartościowe informacje dotyczące funkcji oraz ich tworzenia. Jest bardzo ważne to, aby być zaznajomionym z poprzednimi rozdziałami, ze szczególnym uwzględnieniem rozdziału „Wskaźniki i złożone typy danych”. Funkcje Typy funkcji Struktura programu

4.1. Funkcje Funkcje są przydatnym narzędziem do pisania programów. Funkcja jest częścią kodu, który został już napisany i który ma odpowiednie zadanie, np. obliczanie nachylenia kąta, umieszczanie tekstu na wyświetlaczu. Funkcja może przypominać czarną skrzynkę. Skrzynka ta ma swoją nazwę, która mówi, co ta funkcja robi. Nie trzeba wiedzieć co jest w jej środku, tylko wiedzieć jakie są jej wejścia a jakie wyjścia.

Występują funkcje do przeróżnych zadań, takich jak: trygonometria, wyświetlanie, operacje na łańcuchach, powiadamianie o błędzie, itd. Co należy zrobić przed użyciem funkcji?

Większość bibliotek funkcji musi być importowana do bieżącego projektu. Jeżeli biblioteka zawierająca funkcję, która jest używana, nie została importowana, to kompilator nie będzie jej widział i zakomunikuje błąd. Funkcje przedstawione w przykładach pochodzą z systemu, bibliotek BURTRAP i IEC 1131. Biblioteka systemu jest wbudowana, natomiast dwie pozostałe powinny być 60

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

importowane przed użyciem przykładów w tym rozdziale. Proszę odnieść się do rozdziału „Library Menager” B&R Automation Software Help. Jak używamy funkcji?

Funkcję wywołuje się jej nazwą oraz parametrami wejściowymi i wyjściowymi (umieszczonymi między nawiasami), np.: DIS_chr(1,0,"O")

To jest funkcja do DISplay (wyświetlenia) ChaRacter (znaku) na ekranie B&R 2010 CPU. Funkcja jest zdefiniowana: DIS_chr(line, column, char)

Pierwszy parametr line (linia) mówi funkcji, w której linii (0 lub 1) ma być wyświetlony znak. Drugi parametr column (kolumna) mówi funkcji, w której kolumnie ma wyświetlić znak. Ostatni, trzeci parametr char jest znakiem, który ma być wyświetlony zgodnie z linią i kolumną. Zamiast używać stałych, parametry mogą być ustalone zmiennymi. Jeżeli zostanie użyty nieodpowiedni typ zmiennej dla parametru funkcji, to kompilator poinformuje, że został użyty zły typ lub występuje zła liczba parametrów. Nazwy funkcji mogą być dłuższe niż 8 znaków, ale tylko pierwszych 8 jest istotnych. Lepiej jest wpisać całą nazwę, ponieważ będzie to bardziej zrozumiałe dla nas, jednak nie ma to żadnego znaczenia dla komputera. Teraz, kiedy znamy już podstawy funkcji, spróbujmy na kilku przykładach jak wyglądają one w rzeczywistości: Przykład: Wyświetl klasyczny „Hello, World!!” na wyświetlaczu. W tym przykładzie nie są wymagane żadne zmienne i używamy tutaj nowej funkcji. Pseudokod wygląda następująco: Wyświetl „Hello” w pierwszej linii Wyświetl „World” w drugiej linii

Kod w języku B&R Automation Basic: DIS_str(0,0,"Hello, ")

61

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

DIS_str(1,0,"World !!")

Funkcja DIS_str wyświetla łańcuch znaków. Jeżeli po zdeklarowaniu i skompilowaniu zmiennych wszystko pójdzie bez błędu na wyświetlaczu B&R 2010 powinno pojawić się:

A teraz coś bardziej złożonego. Mamy część sprzętu posiadającego serię alarmów. Wyświetl odpowiednią informację alarmu. Alarmami są: przegrzewanie, ciśnienie oleju jest zbyt niskie, nie ma wystarczająco paliwa. Po tym jak alarm został wywołany, wiadomość pozostaje na ekranie do momentu pojawienia się następnej. Oto podstawowy pseudokod: Jeśli włączy się alarm o przegrzaniu to utwórz wiadomość o przegrzaniu Jeśli włączy się alarm o ciśnieniu oleju to utwórz wiadomość o ciśnieniu oleju Jeśli włączy się alarm o niskim paliwie to utwórz wiadomość o niskim paliwie Jeśli włączy się jakikolwiek alarm to wyświetl skonfigurowaną wiadomość Lub Wyświetl OK.

Kod B&R Automation Basic wygląda następująco: strcpy(message0,"Alarm:") if too_hot = 1 then strcpy(message1,"Overheat") else if oil_press = 1 then strcpy(message1,"Oil Pres") else if low_fuel = 1 then strcpy(message1,"Low Fuel") endif if (too_hot=1) or (oil_press=1) or (low_fuel=1)then DIS_str(0,0,message0) DIS_str(1,0,message1) else DIS_str(0,0,"No Alarm") DIS_str(1,0," ")

62

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

endif

4.2. Typy Funkcji Jak dotąd określenie „funkcja” było używane do opisania wszystkich typów bloków przed zbudowaniem kodu, który może być wywołany grupą parametrów. B&R Automation Basic oferuje dwa wyraźnie różne rodzaje „funkcji”. Funkcje typu „inline” Bloki funkcyjne Bloki funkcyjne D-I-Y

4.2.1. Funkcje „inline” Funkcja inline jest funkcją, która zwraca dokładnie jeden element danych (może to być tablica lub struktura), który może być używany jako operand w wyrażeniu. Symbolicznie można przedstawić to tak:

Przykład: Masz aplikację, dla której trzeba znaleźć stopień nachylanie kąta dla obliczeń matematycznych. W bibliotekach można znaleźć funkcję COS określoną w ten sposób: result = COS(angle)

gdzie wynik i kąt nachylenia są typu REAL. Jeżeli użyjesz funkcji tak jak tutaj, nic się nie stanie. COS(my_angle)

Wynik funkcji jest obliczony i nie jest do niczego przypisany. Najprostszym sposobem na to, aby użyć funkcji prawidłowo jest przydzielenie wyniku do zmiennej: my_result = COS(my_angle)

63

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Występują lepsze i bardziej wydajne sposoby używania funkcji inlines. Określenie „inline” (kod wbudowany) oznacza, że wynik może być używany natychmiast i może być operandem w wyrażeniu. Przyjrzyjmy się bardziej złożonemu przykładowi.

Przykład: W aplikacji występuje wartość kąta angle_X i kąta angle_Y, trzeba ocenić wartość wyrażenia. SIN(angle_X) x COS(angle_Y) + SIN(angle_Y) x COS(angle_X)

Wiadomo, że wynik inline może być używany natychmiast, więc można to napisać w B&R Automation Basic w taki sam sposób jak normalny matematyczny wzór. z = SIN(angle_X)*COS(angle_Y)+SIN(angle_Y)*COS(angle_X)

Funkcja inline nie zawiera statycznych danych. Za każdym razem jest wywoływana tą samą grupa parametrów, wynik jest ten sam. B&R dostarcza kilka bibliotek na temat funkcji z wbudowanym kodem inline z szerokim opisem ich funkcjonalności. System BURTRAP, AsMath oraz biblioteki IEC 1131 zawierają funkcje inline. Pełna lista wszystkich funkcji w tych bibliotekach jest opisana w systemie pomocy do B&R Automation Studio.

4.2.2. Bloki funkcyjne Blok funkcyjny (dalej zwany FBK) dla języka sterowników PLC określa się jako funkcję, która zwraca jedną lub więcej wartości. Symbolicznie wygląda to tak:

FBK nie mogą być używane w wyrażeniach takich jak funkcje typu inline, ponieważ one zwracają informacje do grupy zmiennych. Wszystkie wartości zmiennych wyjściowych i niezbędne zmienne wewnętrzne są trzymane z dala od jednego wywołania FBK do następnego. Oznacza to, iż 64

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

wywołanie tego samego bloku funkcji z tymi samymi zmiennymi wejściowymi nie zawsze daje takie same zmienne wyjściowe.

Występują dwie różne metody wywołania FBK: normalna i alias. Na początku zajmiemy się wywołaniem normalnym.

„Normalne” wywołanie FBK

Przy normalnym wywołaniu FBK wszystkie parametry są w nim wyszczególnione.. Wygląda to tak jak normalne wywołanie funkcji. Na przykład używając wyższego licznika FBK CTU(input, reset, limit, limit_reached, counter). Gdzie input, reset i limit są parametrami wejściowymi a limit_reached i counter są parametrami wyjściowymi. Nie można napisać: Z = CTU(input, reset, limit,limit_reached, counter)

Jest to bezsensowne – kompilator poinformuje o błędzie. Funkcja ta posiada grupę a nie pojedynczy parametr, dlatego też nie można jej przydzielić do zmiennej lub używać w wyrażeniu. Wywołanie „alias”

Pozwala na nazwanie poszczególnych zmiennych funkcji i na działania na nich. Nazwa alias musi przestrzegać tych samych zasad, co nazwa zmiennej. Przykład wywołania alias: counter_1.CU = input counter_1.R = reset counter_1.PV = limit counter_1 FUB CTU() limit_reached = counter_1.Q counter = counter_1.CV

Różnice pomiędzy wywołaniem alias i normalnym

Normalne wywołanie FBK jest proste do zrozumienia dla kogoś, kto dopiero rozpoczyna lub dla kogoś kto jest przyzwyczajony do używania funkcji w innym języku. Wszystko zawarte jest w linii z wywołaniem. Parametry alias są przydzielane i wczytywane przy użyciu struktury oraz nie są w ogóle widoczne w linii. Wywołania alias są także szybsze, ponieważ posiadają oddzielną przestrzeń 65

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

pamięci, do której dostęp ma blok funkcji. Zmienne struktury alias mogą być przydzielane także bezpośrednio, czyli tak: counter_1.CU = input counter_1.R = reset counter_1.PV = limit counter_1 FUB CTU() counter_1.CV = counter_1.CV + 5 counter_1 FUB CTU() limit_reached = counter_1.Q counter = counter_1.CV

4.2.3. Bloki funkcyjne D-I-Y Jest możliwe stworzenie własnych, przerobionych bloków funkcyjnych (nie funkcji inline). Aby to zrobić trzeba po prostu napisać kod B&R Automation Basic jako normalny i wywołać edytor FBK w celu określenia wejść i wyjść. Przykład: Nasza funkcja nazywa się ADD_OVER. Stwórzmy prostą funkcję dodania USINT, z dodatkiem, który określi nam czy jest nastąpiło przepełnienie. Nasz algorytm wygląda tak: result = in_1 + in_2 if result < in_1 or result < in_2 then set overflow flag

Kod w B&R Automation Basicu: result, in_1, in_2 : USINT, overflow : BOOL result = in_1 + in_2 if (result < in_1) or (result < in_2) then overflow = 1 else overflow = 0 endif

Po napisaniu kodu i zdeklarowaniu zmiennych należy skonstruować blok funkcji, żeby inne programy wiedziały jakie są wejścia i wyjścia. Musimy użyć edytora FBK i powinniśmy stworzyć FBK, który wygląda tak: 66

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Nasz blok funkcji może być teraz używany w ten sam sposób jak FBK dostarczany przez B&R. Lista parametru przemieszcza się z góry na dół, z lewa na prawo, i aby wywołać blok funkcji należy użyć następującego wywołania: ADD_OVER (input_1, input_2, answer, o_flow)

Testowanie naszego FBK

Zanim stworzymy nasz blok funkcji, dobrym pomysłem na początek jest wypróbowanie go jako mini programu. W ten sposób można najpierw sprawdzić czy zostały popełnione jakieś błędy. Jeżeli jesteśmy pewni, że kod działa bez zarzutu, to należy skopiować kod do bloku funkcji i określić wejścia oraz wyjścia za pomocą edytora FBK. Przekazywanie wskaźników do FBK

Potrafimy już napisać FBK używając prostych typów danych, ale co trzeba zrobić jeśli chcemy użyć łańcuchów znaków, tablicy czy struktury jako parametrów wejściowych i wyjściowych? Wtedy właśnie trzeba użyć wskaźników. Jeżeli nie jest Ci znana sekcja „Wskaźniki i złożone typy danych” z tego rozdziału to zalecane jest najpierw ją przeczytać. Nie można przekazywać struktury ani tablicy jako parametru bezpośrednio do bloku funkcji, ale można wysłać adres. Wtedy blok funkcji może założyć wskaźnik do tego adresu i może mieć dostęp do informacji bez żadnych dalszych problemów. Przykład: Mamy string (łańcuch znaków) i musimy odwrócić kolejność liter, tj. podane słowo „loot” FBK zamieni na „tool”. Mamy podany adres zmiennej tekstowej i musimy ją zmienić.

67

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Wersja 1 1. Połącz wejściowy adres danej string z docelowym adresem 2. Znajdź długość wejściowej danej string 3. Przejdź przez wszystkie elementy na tablicy zaczynając od końca 3.1

Skopiuj bieżący element do następnej pozycji w nowej tablicy

3.2

Uaktualnij pozycję w nowej tablicy

Potrzebujemy kilka zmiennych string[40] : USINT (dynamic), string_out[40] : USINT (dynamic), length : UINT, new_index : UINT, index : UINT

Kod w języku B&R Automation Basic wygląda następująco: ; 1 (adr) and 2 length = strlen(adr(string)) ; 3 index = length − 1 loop new_index = 0 to length−1 do ; 3.1 out_string[new_index] = string[index] ; 3.2 index = index − 1 endloop

Zwróćmy uwagę na podwójne użycie wyrażenia loop. Jeden licznik jest tak naprawdę częścią pętli (new_index) a drugim (index) zajmujemy się oddzielnie. Kod B&R Automation Basic podany powyżej jest już skończony, ale trzeba go jeszcze zamienić w FBK. Powinno to wyglądać tak:

68

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

Wszystko jest teraz zrozumiałe i możemy użyć bloku funkcji. Napiszmy mały program, aby go wypróbować. forwards[10] : USINT, backwards[10] :USINT strcpy(adr(forwards),"Hello") reverse((adr(forwards),adr(backwards)) DIS_str(0,0,adr(forwards)) DIS_str(1,0,adr(backwards))

Na ekranie CPU powinno się pojawić:

4.2. Struktura Programu Czym właściwie jest program? Program jest „zadaniem”, które działa na PLC. Słowa takie jak „zadanie” czy „program” są stosowane zamiennie w tym opracowaniu, jednak w innych opracowaniach B&R 2000 SYSTEM używa się raczej słowa „zadania” (ang. task). Program składa się z dwóch głównych części: sekcji głównej oraz z sekcji początkowej. Mają one różne własności, jednak nadal są one tylko częściami kodu. Każde zadanie powinno wykonywać określoną pracę. Jeżeli w projekcie znajduje się więcej części sprzętu to powinno zostać napisane oddzielne zadanie dla każdej części. Sekcja Główna

Ta sekcja kodu wykonuje całą pracę programu. Działa ona cyklicznie, czyli działa stale tak samo, od początku do końca w nieskończonej pętli. Jest to bardzo ważne, aby o tym pamiętać przy pisaniu programu. Program musi być napisany tak by działał wtedy, kiedy w kółko się powtarza. Program nie może być umieszczony w pętli Twojego programu. Oto przykład jak nie powinno być: 69

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.

Perfection in Automation

... loop ... exitif on_switch = 1 endloop

Powstanie problem, jeżeli program będzie obecny w tej pętli i będzie czekał na włączenie (prawdopodobnie manualne) przełącznika. Może to zabrać dużo czasu (kilka minut, godzin, ...). Ten rodzaj czekającej pętli nie może być częścią programu. Właśnie dlatego specjalna konstrukcja select B&R Automation Basic jest bardzo użyteczna w aplikacjach na PLC. Ta sekcja programu powinna być krótka. Jest określona maksymalna ilość czasu, którą program może zużyć na jeden cykl (czas cyklu zadania). Sekcja inicjalizacyjna

Sekcja ta działa tylko raz, na początku programu. Zwykle jest używana do inicjalizacji stałych, ustawienia wartości początkowych zmiennych i do wykonania jakiejś operacji tylko raz. ; czesc inicjalizacyjna programu (wykonywana tylko raz) ... ... ; czesc cykliczna programu ... ... ...

70

B&R Automation Basic  Copyright 2004 by B&R Automatyka Przemysłowa Sp. z o.o. All rights reserved.