poniedziałek, 12 września 2016

Protokoły komunikacyjne - ramka Modbus ASCII

Modbus ASCII to szatański wynalazek. Wie o tym każdy, kto go kiedyś implementował, chociaż ta wersja ma swoich zwolenników. Jest podobny do wersji Modbus RTU, ale dane są dodatkowo kodowane.

Każdy bajt jest mianowicie zapisywany za pomocą dwóch znaków w formacie heksadecymalnym. W ramce umieszczane są kody ASCII tych znaków. W efekcie każdy przesyłany bajt zajmuje 2 bajty.

Przykład:
17210 = AB16
A to kod ASCII 65
B to kod ASCII 66

Ta wersja nie wymaga przerwy na łączu, ale w zamian na początku ramki umieszczony jest zawsze znak ":" (dwukropek), a na końcu zawsze znaki CR i LF (carriage return i line feed). Ich kody ASCII to odpowiednio 58 oraz 13 i 10.

ODCZYT

Struktura ramki zapytania dla funkcji 1,2,3 i 4:

: 1 bajt
Adres Modbus 2 bajty
Kod funkcji 2 bajty
Adres w pamięci 4 bajty
Ilość danych 4 bajty
LRC 2 bajty
CR LF 2 bajty

Struktura ramki odpowiedzi dla funkcji 1,2,3 i 4:

: 1 bajt
Adres Modbus 2 bajty
Kod funkcji 2 bajty
Rozmiar danych 2 bajty
Dane N bajtów
LRC 2 bajty
CR LF 2 bajty


ZAPIS

Struktura ramki zapytania i odpowiedzi dla funkcji 5 i 6:

: 1 bajt
Adres Modbus 2 bajty
Kod funkcji 2 bajty
Adres w pamięci 4 bajty
Dane 4 bajty
LRC 2 bajty
CR LF 2 bajty

Struktura ramki zapytania dla funkcji 15 i 16:

: 1 bajt
Adres Modbus 2 bajty
Kod funkcji 2 bajty
Adres w pamięci 4 bajty
Ilość danych 4 bajty
Rozmiar danych 2 bajty
Dane N bajtów
LRC 2 bajty
CR LF 2 bajty

Struktura ramki odpowiedzi dla funkcji 15 i 16:

: 1 bajt
Adres Modbus 2 bajty
Kod funkcji 2 bajty
Adres w pamięci 4 bajty
Ilość danych 4 bajty
LRC 2 bajty
CR LF 2 bajty

niedziela, 14 sierpnia 2016

Protokoły komunikacyjne - ramka Modbus RTU

Modbus RTU wydaje się być najprostszą wersją tego protokołu. Ramki w tej wersji oddziela przerwa w transmisji na łączu. Istotny jest również fakt, że w zapytaniu podaje się zarówno ilość danych do odczytu czy zapisu, jak i rozmiar danych w ramce. Coils i Discrete Inputs zajmują tylko 1 bit, w 1 bajcie zmieści się ich 8. Z kolei każdy rejestr z grupy Input Registers i Holding Registers zajmuje 16 bitów, czyli 2 bajty.

ODCZYT

Struktura ramki zapytania dla funkcji 1,2,3 i 4:

Adres Modbus 1 bajt
Kod funkcji 1 bajt
Adres w pamięci 2 bajty
Ilość danych 2 bajty
CRC 2 bajty

Struktura ramki odpowiedzi dla funkcji 1,2,3 i 4:

Adres Modbus 1 bajt
Kod funkcji 1 bajt
Rozmiar danych 1 bajt
Dane N bajtów
CRC 2 bajty


ZAPIS

Struktura ramki zapytania i odpowiedzi dla funkcji 5 i 6:

Adres Modbus 1 bajt
Kod funkcji 1 bajt
Adres w pamięci 2 bajty
Dane 2 bajty
CRC 2 bajty

Struktura ramki zapytania dla funkcji 15 i 16:

Adres Modbus 1 bajt
Kod funkcji 1 bajt
Adres w pamięci 2 bajty
Ilość danych 2 bajty
Rozmiar danych 1 bajt
Dane N bajtów
CRC 2 bajty

Struktura ramki odpowiedzi dla funkcji 15 i 16:

Adres Modbus 1 bajt
Kod funkcji 1 bajt
Adres w pamięci 2 bajty
Ilość danych 2 bajty
CRC 2 bajty

sobota, 30 lipca 2016

Protokoły komunikacyjne - wstęp do Modbus

Modbus to jeden z najczęściej spotykanych protokołów komunikacyjnych. To prosty i otwarty standard. Powiada wersje zarówno dla portów szeregowych jak i sieci ethernet.

WERSJE MODBUS
  • RTU - podstawowa wersja dla portów szeregowych
  • ASCII - alternatywna wersja dla portów szeregowych, wyróżnia się dodatkowym kodowaniem ASCII
  • TCP - podstawowa wersja dla sieci ethernet
  • OverTCP - alternatywna wersja dla sieci ethernet, gdzie ramka wersji RTU lub ASCII jest wysyłana po TCP

FUNKCJE MODBUS

Wszystkie wersje protokołu Modbus posiadają taki sam zestaw funkcji.

  • 01 - Read Coils
  • 02 - Read Discrete Inputs
  • 03 - Read Holding Registers
  • 04 - Read Input Registers
  • 05 - Write Single Coil
  • 06 - Write Single Register
  • 15 - Write Multiple Coils
  • 16 - Write Multiple Registers

Po przyjrzeniu się zestawowi funkcji nie jest trudno zauważyć 4 obszary pamięci.

Rodzaj zmiennej Odczyt Zapis
Coils 1-bitowy Tak Tak
Discrete Inputs 1-bitowy Tak Nie
Holding Registers 16-bitowy Tak Tak
Input Registers 16-bitowy Tak Nie


ADRES MODBUS

Adres Modbus, inaczej UnitID, to adres konkretnego urządzenia. Na linii musi być unikalny dla każdego slave'a i master'a. Jest szczególnie istotny przy komunikacji za pomocą portów szeregowych.

czwartek, 28 lipca 2016

TwinCAT - dodawanie modułów i podłączanie zmiennych

Sterownik PLC nie miałby sensu, gdyby nie podłączone moduły. Jest ich wiele rodzajów. Za przykład posłużą wejścia i wyjścia, zarówno cyfrowe jak i analogowe. Konfiguracja modułów podłączonych do sterownika odbywa się w trybie CONFIG.

WYKRYCIE MODUŁÓW
  1. gałąź I/O - Configuration
  2. gałąź I/O Devices
  3. opcja Scan Devices (po kliknięciu prawym przyciskiem myszy na gałęzi)
  4. potwierdzenie Scan Boxes
W efekcie powinna się pojawić lista modułów z domyślną nazwą Term i odpowiednim numerem, co najważniejsze w kolejności zgodnej z fizyczną. Ma ona formę drzewa, którego liście to faktyczne wartości. Wartości wejściowe są oznaczone kolorem żółtym, a wartości wyjściowe czerwonym. W zakładce Online można uzyskać podgląd wartości, a także ją wymusić lub wpisać.

DODANIE PROJEKTU
  1. gałąź PLC - Configuration
  2. opcja Append PLC Project(po kliknięciu prawym przyciskiem myszy na gałęzi)
Teraz wystarczy znaleść odpowiedni plik z rozszerzeniem TPY, który otrzymaliśmy po zbudowaniu projektu w PLC Control.

LINKOWANIE

Do zlinkowania zmiennych potrzebne są odpowiednio zadeklarowane zmienne w programie, na przykład:
wejscie_cyfrowe AT%I* : BOOL;
wyjscie_cyfrowe AT%Q* : BOOL;
wejscie_analogowe AT%I* : REAL;
wyjscie_analogowe AT%Q* : REAL;
Teraz wystarczy znaleść odpowiednią wartość w drzewie. Po kliknięciu na nią prawym przyciskiem myszy wybieramy opcję Change Link. Pokazuje się lista zmiennych z programu, które możemy zlinkować z wybraną wartością. Ten sam efekt przyniesie kliknięcie lewym przyciskiem myszy i użycie przycisku Linked to w zakładce Variable. Tutaj widać też jakiego typu zmienną należy zadeklarować w programie. Jeśli nie widać ostatnio dodanych zmiennych, należy w gałęzi PLC - Configuration wybrać projekt i nacisnąć przycisk ReScan.

AKTYWACJA

Ostatni krok to umieszczenie konfiguracji w sterowniku.
  1. przycisk Generate mappings
  2. przycisk Check configuration
  3. przycisk Activate configuration
W tym momencie, po zalogowaniu przy pomocy PLC Control i ewentualnemu uruchomieniu programu, powinno być widać odpowiednie wartości przypisane do zmiennych.

wtorek, 12 kwietnia 2016

TwinCAT - komunikacja pomiędzy instancjami

Komunikacja pomiędzy dwoma instancjami TwinCAT'a możliwa jest wtedy, kiedy obie instancje wiedzą, gdzie szukać drugiej z nich. W tym celu muszą umieć powiązać adres AMS i adres IP. Oczywiście ten drugi musi być osiągalny w sieci. Możliwe jest też korzystanie z nazwy komputera zamiast adresu IP, ale jest to metoda moim zdaniem znacznie mniej pewna.

SPOSÓB AUTOMATYCZNY

Sposób automatyczny pozwala na dodanie tras na obu instancjach jednocześnie. Najpierw jednak należy dodać trasę do naszego komputera:
  1. gałąź "SYSTEM" w drzewie projektu
  2. przycisk "Choose Target"
  3. przycisk "Search ethernet"

Pojawia się okno służące do dodawania tras. Po kliknięciu przycisku "Broadcast search" otrzymujemy listę instancji TwinCAT'a widocznych w lokalnej sieci. Wybieramy z niej odpowiedni sterownik. Warto dodać, że czasami zamiast "Broadcast search" trzeba użyć przycisku "Enter hostname/IP".

Dodanie trasy:
  1. opcja "IP Address" zaznaczona
  2. opcje "Static route" zaznaczone
  3. przycisk "Add route"
  4. przycisk "OK"

W rezultacie na liście pojawia się nazwa i adres AMS, a po rozwinięciu przynajmniej jeden runtime. Po potwierdzeniu wyboru przyciskiem "OK" lub podwójnym kliknięciem można już wykonywać operacje na sterowniku.

Dodanie tras do kolejnych sterowników wygląda podobnie.
  1. gałąź "SYSTEM" w drzewie projektu
  2. podrzędna gałąź "Routes"
  3. zakładka "Static routes"
  4. przycisk "Add"
Pojawia się znajome okno dodawania tras.

SPOSÓB RĘCZNY

Zdarzają się sytuacje, w których wykorzystanie sposobu automatycznego jest niemożliwe. Na liście może na przykład istnieć już wpis o pożądanym adres IP i innym adresie AMS lub odwrotnie. Wpisy można jednak dodać ręcznie na obu urządzeniach.

W przypadku urządzeń z TwinCAT 3 należy otworzyć plik xml:
c:\TwinCAT\3.1\Target\StaticRoutes.xml

i uzupełnić węzeł „TcConfig/RemoteConnections” odpowiednim wpisem:
<Route>
     <Name>nazwa</Name>
     <Address>adres IP</Address>
     <NetId>adres AMS</NetId>
     <Type>TCP_IP</Type>
</Route>

Jeśli chodzi o komputery z TwinCAT 2, korzystamy z ikony w zasobniku systemowym:
  1. menu "Properties"
  2. zakłada "AMS Router"
  3. przycisk "Add"
Na ekranie pojawia się okno, w którym podajemy nazwę, adres AMS i adres IP, a wszystko potwierdzamy przyciskiem OK.

W przypadku Windows CE musimy zdalnie połączyć się ze sterownikiem przy pomocy programu Microsoft Remote Display (CERHost.exe):
  1. menu "File"
  2. opcja "Connect"
  3. menu "Start"
  4. opcja "Run"
  5. polecenie "explorer"
  6. folder "\Hard Disk\System\"
  7. plik "TcAmsRemoteMgr.exe"
  8. przycisk "Add"
Na ekranie pojawia się okno znane z komputerów z TwinCAT 2.

niedziela, 17 stycznia 2016

Podstawy ST - timery

Odliczanie czasu to w programowaniu PLC to rzecz bardzo powszechna, w przeciwieństwie do programów desktopowych czy webowych. Tam czynności najczęściej wykonujemy najszybciej jak to możliwe. Fizyczne urządzenie natomiast nie reaguje natychmiastowo. Może na przykład być uszkodzone, a w nieskończoność czekać nie można.

Wszystkie timery posiadają dwa wejścia i dwa wyjścia:
  • wejście IN : BOOL
  • wejście PT : TIME
  • wyjście Q : BOOL
  • wejście ET : TIME


TON

To chyba najczęściej wykorzystywany bloczek. Kiedy na wejściu IN pojawi się zbocze narastające, wtedy po upłynięciu PT czasu na wyjściu Q pojawi się TRUE. Z kolei FALSE na wejściu IN skutkuje FALSE na wyjściu Q natychmiastowo. Wyjście ET odmierza natomiast czas.

Dla przykładu kawałek kodu, który zgłasza alarm, jeśli pomiar jest wyższy od poziomu alarmowego przez 5 sekund.
VAR_INPUT
    pomiar         : REAL;
    poziomAlarmowy : REAL;
END_VAR
VAR_OUTPUT
    alarm          : BOOL;
END_VAR
VAR
    timerAlarmowy  : TON;
END_VAR
timerAlarmowy(IN := pomiar > poziomAlarmowy, PT := T#5s, Q => alarm);

Drugi często spotykany przykład, grupa instukcji wykonywana co 1 sekundę.
timer(IN := TRUE, PT := T#1s);
IF timer.Q THEN
    timer(IN := FALSE);
    instrukcje wykonywane co 1 sekundę
END_IF



TOF

Bloczek podobny to poprzedniego. Można powiedzieć, że działa odwrotnie. Tym razem TRUE na wyjściu Q pojawia się natychmiastowo po pojawieniu się TRUE na wejściu IN. Zbocze opadające na wejściu IN spowoduje natomiast wystawienie FALSE na wyjściu Q dopiero, kiedy mienie PT czasu.

Analogiczny przykład z alarmem, tym razem napisany z użyciem TOF.
VAR_INPUT
    pomiar         : REAL;
    poziomAlarmowy : REAL;
END_VAR
VAR_OUTPUT
    alarm          : BOOL;
END_VAR
VAR
    timerAlarmowy  : TOF;
END_VAR
timerAlarmowy(IN := pomiar <= poziomAlarmowy, PT := T#5s);
alarm := NOT timerAlarmowy.Q;



TP

Bloczek trochę inny niż dwa pozostałe. Wystawia TRUE na wyjściu Q natychmiastowo po pojawieniu się zbocza narastającego na wejściu IN, ale po upłynięciu czasu PT zmienia stan wyjścia Q na FALSE niezależnie od tego co działo się przez ten czas z wejściem Q. Od tego momentu znowu oczekuje na zbocze narastające.

Przykład, fragment kodu, który uruchamia trwające minutę czyszczenie, kiedy otrzyma sygnał o zabrudzeniu.
VAR_INPUT
    zabrudzenie : BOOL;
END_VAR
VAR_OUTPUT
    czyszczenie : BOOL;
END_VAR
VAR
    timerCzyszczenia  : TP;
END_VAR
timerCzyszczenia(IN := zabrudzenie, PT := T#1m, Q => czyszczenie);

czwartek, 14 stycznia 2016

Podstawy ST - zbocza

Zbocze to moment zmiany sygnału. Jeśli sygnał zmienia się z niskiego na wysoki to jest to zbocza narastające, w przeciwnym przypadku mówimy o zboczu opadającym.


SPOSÓB KLASYCZNY

Oczywistym sposobem na obsługę zmian sygnału jest zapamiętanie poprzedniego stanu.
VAR
    stan          : BOOL;
    stanPoprzedni : BOOL;
END_VAR
IF stan <> stanPoprzedni THEN
    reakcja na zbocze
END_IF

IF stan <> stanPoprzedni AND stan THEN
    reakcja na zbocze narastające
END_IF

IF stan <> stanPoprzedni AND NOT stan THEN
    reakcja na zbocze opadające
END_IF

stanPoprzedni := stan;

Bardzo istotna jest ostatnia linijka przykładu.


SPOSÓB ELEGANCKI

Język ST udostępnia specjalne bloki funkcyjne służące go obsługi zmian sygnału. R_TRIG zwraca na wyjściu stan wysoki przy zboczu narastającym, a F_TRIG przy zboczu opadającym.

Wejścia i wyjścia:
  • wejście CLK : BOOL
  • wyjście Q : BOOL


Przykład:
VAR_INPUT
    stan              : BOOL;
    zboczeNarastajace : R_TRIG;
    zboczeOpadajace   : F_TRIG;
END_VAR
zboczeNarastajace(CLK := stan);
zboczeOpadajace(CLK := stan);

IF zboczeNarastajace.Q OR zboczeOpadajace.Q THEN
    reakcja na zbocze
END_IF

IF zboczeNarastajace.Q THEN
    reakcja na zbocze narastające
END_IF

IF zboczeOpadajace.Q THEN
    reakcja na zbocze opadające
END_IF


Do zapamiętania zmiany można lekko zmodyfikować wywołanie bloku.
IF NOT zboczeNarastajace.Q THEN
    zboczeNarastajace(CLK := stan);
END_IF


W tym przypadku by wyresetować, wystarczy dodatkowo wywołać blok z negatywnym parametrem na wejściu.
zboczeNarastajace(CLK := FALSE);


Dwa powyższe przykłady pozwalają bardzo prosto poczekać na kilka zboczy.
VAR_INPUT
    stanNr1   : BOOL;
    stanNr2   : BOOL;
    zboczeNr1 : R_TRIG;
    zboczeNr2 : R_TRIG;
END_VAR
IF NOT zboczeNr1.Q THEN
    zboczeNr1(CLK := stanNr1);
END_IF

IF NOT zboczeNr2.Q THEN
    zboczeNr2(CLK := stanNr2);
END_IF

IF zboczeNr1.Q AND zboczeNr2.Q THEN
    instrukcje dla obu zboczy narastających
    zboczeNr1(CLK := FALSE);
    zboczeNr2(CLK := FALSE);
END_IF


Dodatkowo możemy określić kolejność, w jakiej sygnały mają się zmienić. W tym celu zmieniamy instrukcję warunkową towarzyszącą wywołaniu drugiego bloku.
IF zboczeNr1.Q AND NOT zboczeNr2.Q THEN
    zboczeNr2(CLK := stanNr2);
END_IF