Przejdź do głównej zawartości

Dokumentacja programowania logiki operacyjnej

Po uruchomieniu Overvis MC252 rozpoczyna wykonywanie programu logiki operacyjnej, jeśli został on wcześniej umieszczony w pamięci wewnętrznej.

Jeśli w pamięci wewnętrznej nie ma programu, a karta pamięci jest obecna (sformatowana jako FAT lub FAT32), MC252 może automatycznie załadować pliki zadań. Takie odczytywanie następuje jeden raz po uruchomieniu lub po zainstalowaniu nowej karty pamięci, ale tylko wtedy, gdy pamięć wewnętrzna nie zawiera programu. MC252 wyszukuje i sprawdza pliki zadań umieszczone w folderze TASKS na karcie pamięci. Znalezione poprawne pliki są odczytywane do pamięci wewnętrznej i tworzą program logiki operacyjnej.

Wewnętrzna pamięć logiki może zostać wyczyszczona wraz z resetem ustawień do wartości fabrycznych. Aby zachować ustawienia i wyczyścić tylko wewnętrzną pamięć logiki, należy użyć polecenia przez Modbus lub interfejs WWW.

  1. Korzystając z interfejsu WWW

1.1 uzyskaj dostęp do urządzenia przez przeglądarkę (zobacz Interfejs WWW); 1.2 otwórz zakładkę Tasks; 1.3 naciśnij przycisk Reload Tasks i potwierdź czyszczenie pamięci.

  1. Przez MODBUS

2.1 połącz się z urządzeniem przez MODBUS i przejdź do trybu konfiguracji (zobacz Mapa rejestrów Modbus); 2.2 aby wyczyścić wewnętrzną pamięć logiki, zapisz wartość 40959 do rejestru poleceń sterujących 120.

Zakładka Tasks pokazuje wynik odczytu folderu TASKS, w tym liczbę wykrytych plików. Pomyślnie odczytane pliki są wyświetlane poniżej w tabeli zadań logiki. Jeśli podczas odczytywania i weryfikacji programu wykryto błędy, wskazywany jest typ błędu, plik i numer linii błędu w pliku. Jeśli program składał się z kilku plików w folderze TASKS, to pamięć wewnętrzna odczyta wszystkie pliki z wyjątkiem tych, w których wykryto błędy. Dlatego podczas poprawiania błędów należy ponownie załadować zadania, aby jeszcze raz wyczyścić pamięć wewnętrzną.

Rejestry Modbus (zobacz Mapa rejestrów Modbus, rejestry 2020-2023) wskazują wynik odczytu folderu TASKS, w tym liczbę odczytanych plików i ilość użytej pamięci. Jeśli podczas odczytywania i weryfikowania programu wykryto błędy, wskazywany jest typ błędu i numer linii. Jeśli program składał się z kilku plików w folderze “TASKS”, pamięć wewnętrzna odczyta wszystkie pliki z wyjątkiem tych, w których wykryto błędy. Dlatego podczas korygowania błędów należy sprawdzić liczbę odczytanych plików. Po wprowadzeniu poprawek należy wyczyścić pamięć wewnętrzną, aby program został ponownie odczytany. Pliki mogą mieć dowolne nazwy i rozszerzenia (z wyjątkiem .OBJ, .MAP, .CNF) oraz być umieszczone w podfolderach folderu “TASKS”.

Plik zadania opisuje zestaw działań powtarzanych w określonych odstępach czasu. Działania mogą obejmować zbieranie danych, przetwarzanie i porównywanie wartości oraz specjalne akcje po spełnieniu predefiniowanych warunków (zgodnie z wynikami przetwarzania).

Plik składa się z linii. Każda linia może być jedną z następujących:

  • pusta;
  • opcja;
  • definicja;
  • akcja.

Linie mogą zawierać komentarze poprzedzone ; lub #. Tekst po tych symbolach jest ignorowany. Linie mogą zaczynać się od etykiet, po których następuje :. Etykiety są używane do odwoływania się do akcji (np. CALL function1function1: RETURN). Części linii są oddzielone symbolami lub TAB.

Opcje konfigurują kompilację lub wykonywanie pliku zadania.

Opcje zaczynają się od @, po którym następuje rodzaj opcji. Następnie pojawia się wartość opcji.

Sprawdzana w czasie kompilacji. Jeśli wersja wykracza poza zakres wersji obsługiwanych przez kompilator, następuje błąd kompilacji pliku zadania.

Przykłady:

Okno terminala
@PROTOCOLVERSION 11

Ustawia rozmiar typu zmiennej. Większe wartości pozwalają na więcej dostępnych typów rzutowania parametrów i prawidłowo obsługują większe wartości, ale zajmują więcej pamięci.

  • 32 - użyj 32-bitowych (4 bajty) zmiennych całkowitych ze znakiem.
  • 64 - użyj 64-bitowych (8 bajtów) zmiennych całkowitych ze znakiem.

Przykłady:

Okno terminala
@VARBITS 64

Ta opcja to ustawiony odstęp czasu między dwoma kolejnymi uruchomieniami zadania. Rzeczywisty odstęp zależy od obciążenia kontrolera i ogólnej złożoności plików zadań (niektóre akcje, takie jak odczyt/zapis parametrów lub wysyłanie SMS, mogą wydłużyć czas wykonywania). Jeśli następny czas uruchomienia nadejdzie przed zakończeniem innego uruchomienia, nowe zostanie opóźnione i wykona się tak szybko, jak to możliwe.

Wartość opcji to liczba całkowita sekund w zakresie 0..2000000.

0 - brak odstępu, natychmiastowe ponowne uruchomienia.

Domyślnie 60.

Przykłady:

Okno terminala
@UPDATE 10 ; ponownie uruchom zadanie co 10 sekund

Ta opcja to modyfikator dla ustawionego odstępu między dwoma kolejnymi uruchomieniami zadania. Jeśli jest ustawiona na wartość różną od zera, ustawiony odstęp jest zarządzany z precyzją podsekundową i wynosi ‘UPDATE’ / ‘UPDATEDIVISOR’.

Wartość opcji to liczba całkowita herców w zakresie 0..500.

0 - precyzja obliczania odstępów w sekundach.

Domyślnie 0.

Przykłady:

Okno terminala
@UPDATE 2
@UPDATEDIVISOR 3 ; odstęp między uruchomieniami będzie wynosił 2/3 lub około 667 ms

Ta opcja definiuje wymuszone opóźnienia oczekiwania między operacjami odczytu/zapisu parametrów urządzenia (nie dotyczy to parametrów pamięci, patrz Definicja parametru poniżej). Pozwala to na więcej czasu na przetwarzanie żądań innych klientów. Opóźnienie jest proporcjonalne do czasu potrzebnego na poprzednią operację parametru.

Wartość opcji to liczba całkowita procentów w zakresie 0..100.

  • 100 - brak wymuszonych opóźnień.
  • 50 - czas opóźnienia równa się czasowi poprzedniej operacji.
  • 25 - czas opóźnienia jest 3 razy dłuższy niż czas operacji.

Domyślnie 25.

Przykłady:

Okno terminala
@PARAMLOADRATIO 50 ; operacje parametrów rozdzielone opóźnieniami o równej długości

Limit oczekiwania na operacje odczytu/zapisu parametrów urządzenia (nie dotyczy to parametrów pamięci, patrz Definicja parametru poniżej). Po upływie limitu czasu operacja kończy się błędem.

Wartość opcji to liczba całkowita milisekund w zakresie 0..5000.

Domyślnie 5000.

Przykłady:

Okno terminala
@PARAMTIMEOUT 1000 ; czekaj nie dłużej niż 1 sekundę na zakończenie operacji parametru

Określa, czy elementy przechowywane przez zadanie (zmienne i warunki) są resetowane przed każdym uruchomieniem.

0 - zmienne i warunki zachowują swoje wartości w pamięci RAM i są resetowane przy wyłączeniach zasilania lub resetach kontrolera. 1 - zmienne i warunki są resetowane przed każdym uruchomieniem.

Domyślnie 0.

Przykłady:

Okno terminala
@RESETDATA 1 ; wartości elementów przechowywanych pozostawione po uruchomieniu nie używane w kolejnych uruchomieniach

Definicje deklarują powiązania logiczne, ciągi znaków i mapowanie rejestrów Modbus lub typy elementów przechowywanych.

Linie definicji zaczynają się od DEF, po którym następuje nowa zdefiniowana nazwa. Następnie pojawia się typ definicji, który może być jedną z następujących grup:

  • ciąg znaków;
  • urządzenie Modbus;
  • parametr;
  • zmienna(e);
  • warunek(i).

Definicja ciągu znaków jest oznaczona parą ", z ciągiem wewnątrz. Ciąg może zawierać specjalne odwołania, ujęte w * (znak ucieczki * powinien być podwojony, aby zostać uwzględniony w samym ciągu).

Specjalne odwołania obejmują:

  • VAR(variable) - dla wartości numerycznej ze zmiennej. Zmienna lasterror może być również tutaj użyta;
  • ERR(variable) - dla literalnej reprezentacji nazwy kodu błędu ze zmiennej. Zmienna lasterror może być również tutaj użyta;
  • PHONE(index) - dla numeru z listy abonentów GSM w ustawieniach urządzenia. Indeks to liczba w zakresie 0 do 4.

Przykłady:

Okno terminala
DEF my_string1 "2 * 2 = *VAR(var_mul_result)*" ; ten szablon ciągu może wygenerować ciąg "2 * 2 = 4"
DEF e_msg "Handled error #*VAR(lasterror)*: *ERR(lasterror)*" ; ten szablon ciągu może wygenerować ciąg "Handled error #1: FUNCTION_ILLEGAL"

Urządzenie Modbus może być używane jako źródło lub magazyn parametrów.

Urządzenie Modbus jest definiowane przez jeden z następujących typów:

  • MBWRDENIED - mogą być używane tylko funkcje odczytu;
  • MBWRSINGLE - mogą być używane funkcje zapisu pojedynczego rejestru/cewki;
  • MBWRMULTI - mogą być używane funkcje zapisu wielu rejestrów/cewek;
  • MBWRANY - mogą być używane zarówno pojedyncze, jak i wielokrotne funkcje zapisu rejestrów/cewek.

Po typie następują 2 lub 3 argumenty:

  1. Adres jednostki Modbus - jeden z następujących: stały ID w zakresie 1..255, własny ID wirtualnego urządzenia kontrolera jako *, lub pośredni ID jako zmienna plus wartość całkowita (np. some_variable+10);
  2. limit rejestrów/cewek odczytu na jedno żądanie Modbus, w zakresie 1..125;
  3. argument jest obecny tylko dla typów MBWRMULTI, MBWRANY - limit rejestrów/cewek zapisu na jedno żądanie Modbus, w zakresie 1..125.

Przykłady:

Okno terminala
DEF mc_252 WRHANY * 125 125 ; własne wirtualne urządzenie kontrolera

Parametry są używane do dostępu do danych zewnętrznych: pobierania danych do lub ze zmiennych.

Parametr jest definiowany przez jeden z typów danych.

Tabela 1 - Typy parametrów dostępne dla dowolnego rozmiaru typu zmiennej

NrTypOpis
0UINT1616-bitowa (2 bajty) liczba całkowita bez znaku (nieujemna), serializowana jako Big Endian (najbardziej znaczący bajt pierwszy, np. 258 jest przechowywane jako 0x01, 0x02);
1INT1616-bitowa (2 bajty) liczba całkowita ze znakiem, serializowana jako Big Endian;
2INT16BLE16-bitowa (2 bajty) liczba całkowita ze znakiem, serializowana jako Little Endian (najmniej znaczący bajt pierwszy, np. 258 jest przechowywane jako 0x02, 0x01);
3INT3232-bitowa (4 bajty) liczba całkowita ze znakiem, serializowana jako Big Endian (najbardziej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x00, 0x01, 0x02, 0x03);
4INT32BLE32-bitowa (4 bajty) liczba całkowita ze znakiem, z bajtami serializowanymi jako Little Endian (najmniej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x03, 0x02, 0x01, 0x00);
5INT32WLE32-bitowa (4 bajty) liczba całkowita ze znakiem, ze słowami serializowanymi jako Little Endian (najmniej znaczące słowo pierwsze, np. 66051 jest przechowywane jako 0x02, 0x03, 0x00, 0x01);
6BIT1-bitowa liczba całkowita (używana na przykład do dostępu do cewek Modbus i wejść dyskretnych);
7INT32BEtak samo jak INT32
8F32EP0RIEEE 754 pojedyncza precyzja (4 bajty) zmiennoprzecinkowa, serializowana jako Big Endian;
9F32BLEEP0RIEEE 754 pojedyncza precyzja (4 bajty) zmiennoprzecinkowa, z bajtami serializowanymi jako Little Endian;
10F32WLEEP0RIEEE 754 pojedyncza precyzja (4 bajty) zmiennoprzecinkowa, ze słowami serializowanymi jako Little Endian;
11F32EP1Rpojedyncza precyzja (4 bajty) zmiennoprzecinkowa, serializowana jako podzielona przez 10 Big Endian;
12F32BLEEP1Rtak samo jak F32BLEEP0R, ale podzielona przez 10 przed serializacją;
13F32WLEEP1Rtak samo jak F32WLEEP0R, ale podzielona przez 10 przed serializacją;
14F32EP2Rpojedyncza precyzja (4 bajty) zmiennoprzecinkowa, serializowana jako podzielona przez 100 Big Endian;
15F32BLEEP2Rtak samo jak F32BLEEP0R, ale podzielona przez 100 przed serializacją;
16F32WLEEP2Rtak samo jak F32WLEEP0R, ale podzielona przez 100 przed serializacją;
17F32EP3Rpojedyncza precyzja (4 bajty) zmiennoprzecinkowa, serializowana jako podzielona przez 1000 Big Endian;
18F32BLEEP3Rtak samo jak F32BLEEP0R, ale podzielona przez 1000 przed serializacją;
19F32WLEEP3Rtak samo jak F32WLEEP0R, ale podzielona przez 1000 przed serializacją;
20UINT16BLE16-bitowa (2 bajty) liczba całkowita bez znaku (nieujemna), serializowana jako Little Endian;
21UINT88-bitowa (1 bajt) liczba całkowita bez znaku (nieujemna);
22INT88-bitowa (1 bajt) liczba całkowita ze znakiem;

Tabela 2 - Typy parametrów dostępne dla 64-bitowego typu zmiennej

NrTypOpis
23UINT3232-bitowa (4 bajty) liczba całkowita bez znaku (nieujemna), serializowana jako Big Endian (najbardziej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03);
24UINT32BLE32-bitowa (4 bajty) liczba całkowita bez znaku (nieujemna), z bajtami serializowanymi jako Little Endian (najmniej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);
25UINT32WLE32-bitowa (4 bajty) liczba całkowita bez znaku (nieujemna), ze słowami serializowanymi jako Little Endian (najmniej znaczące słowo pierwsze, np. 66051 jest przechowywane jako 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
26INT6464-bitowa (8 bajtów) liczba całkowita ze znakiem, serializowana jako Big Endian (najbardziej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03);
27INT64BLE64-bitowa (8 bajtów) liczba całkowita ze znakiem, z bajtami serializowanymi jako Little Endian (najmniej znaczący bajt pierwszy, np. 66051 jest przechowywane jako 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);
28INT64WLE64-bitowa (8 bajtów) liczba całkowita ze znakiem, ze słowami serializowanymi jako Little Endian (najmniej znaczące słowo pierwsze, np. 66051 jest przechowywane jako 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00);
29F64EP0RIEEE 754 podwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako Big Endian;
30F64BLEEP0RIEEE 754 podwójna precyzja (8 bajtów) zmiennoprzecinkowa, z bajtami serializowanymi jako Little Endian;
31F64WLEEP0RIEEE 754 podwójna precyzja (8 bajtów) zmiennoprzecinkowa, ze słowami serializowanymi jako Little Endian;
32F64EP1Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 10 Big Endian;
33F64BLEEP1Rtak samo jak F64BLEEP0R, ale podzielona przez 10 przed serializacją;
34F64WLEEP1Rtak samo jak F64WLEEP0R, ale podzielona przez 10 przed serializacją;
35F64EP2Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 100 Big Endian;
36F64BLEEP2Rtak samo jak F64BLEEP0R, ale podzielona przez 100 przed serializacją;
37F64WLEEP2Rtak samo jak F64WLEEP0R, ale podzielona przez 100 przed serializacją;
38F64EP3Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 1000 Big Endian;
39F64BLEEP3Rtak samo jak F64BLEEP0R, ale podzielona przez 1000 przed serializacją;
40F64WLEEP3Rtak samo jak F64WLEEP0R, ale podzielona przez 1000 przed serializacją;
41F64EP4Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 10000 Big Endian;
42F64BLEEP4Rtak samo jak F64BLEEP0R, ale podzielona przez 10000 przed serializacją;
43F64WLEEP4Rtak samo jak F64WLEEP0R, ale podzielona przez 10000 przed serializacją;
44F64EP5Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 100000 Big Endian;
45F64BLEEP5Rtak samo jak F64BLEEP0R, ale podzielona przez 100000 przed serializacją;
46F64WLEEP5Rtak samo jak F64WLEEP0R, ale podzielona przez 100000 przed serializacją;
47F64EP6Rpodwójna precyzja (8 bajtów) zmiennoprzecinkowa, serializowana jako podzielona przez 1000000 Big Endian;
48F64BLEEP6Rtak samo jak F64BLEEP0R, ale podzielona przez 1000000 przed serializacją;
49F64WLEEP6Rtak samo jak F64WLEEP0R, ale podzielona przez 1000000 przed serializacją;

Po typie następują 1 lub 3 argumenty:

  1. źródło - jedno z następujących: MEMTEMP, MEMBAT, MEMFILE, MEMFLASH lub urządzenie Modbus zdefiniowane wcześniej.
  2. Dla źródła urządzenia Modbus jest to tabela danych Modbus: jedno z następujących C, D, H, I odpowiednio dla cewek, wejść dyskretnych, rejestrów przechowywanych lub rejestrów wejściowych. Dla źródeł pamięci jest opcjonalne - jeśli określone, mapuje parametr pamięci na adresy własnego wirtualnego urządzenia kontrolera.
  3. Dla źródła urządzenia Modbus jest to adres startowy w zakresie 0..65535 (parametr może zajmować kilka adresów w zależności od jego typu i rozmiaru). Dla źródeł pamięci jest opcjonalne - jeśli określone, mapuje parametr pamięci na adresy własnego wirtualnego urządzenia kontrolera.

Źródła pamięci dla parametrów pozwalają na odczytywanie ustawień wstępnych lub przechowywanie ustawień i wartości tymczasowych do przetwarzania w kolejnych uruchomieniach.

  • MEMTEMP - przestrzeń RAM, dane są tracone przy wyłączeniu zasilania lub resecie kontrolera, mały rozmiar obszaru, ale doskonała szybkość zapisu;
  • MEMBAT - obszar pamięci zasilany przez wewnętrzną baterię zegara, bardzo ograniczony rozmiar, ale dobra szybkość zapisu;
  • MEMFLASH - obszar ustawień kontrolera, dane zachowują się przy resecie, mały rozmiar i zwykle tylko do odczytu;
  • MEMFILE - rozszerzalny obszar plików, wymaga obecności karty pamięci z plikami zadań, średnia szybkość, ale doskonały rozmiar obszaru.

Przykłady:

Okno terminala
DEF local_time UINT32 mc_252 H 170 ; własne rejestry kontrolera 170..171
DEF alg_mode UINT32 MEMTEMP H 5000 ; wartość RAM, mapowana na własny rejestr przechowywany 5000

Zmienne są używane do operowania wartościami całkowitymi. Wszystkie zmienne mają ten sam typ, który jest ustawiony w opcjach pliku zadania.

Zmienne mogą być w większości definiowane automatycznie przy pierwszym wzmiankowaniu. Niektóre operacje jednak (takie jak ‘ISKNOWN’, kopiowanie lub przypisywanie elementów tablicy) wymagają, aby zmienna była zdefiniowana wcześniej.

Zmienne są definiowane typem VAR. Tablice zmiennych są definiowane typem VARS, po którym następuje rozmiar tablicy w zakresie 1..65535 (tablica z pojedynczą zmienną jest skutecznie taka sama jak prosta zmienna).

Istnieje jedna wstępnie zdefiniowana zmienna: lasterror. Wystąpienia błędów zapisują kod błędu do niej. Nie można jej zapisać jak innych zmiennych, ale polecenie RAISE skutecznie do niej zapisuje. Ta zmienna może być użyta w obsłudze błędów dla akcji specyficznych dla błędu.

Przykłady:

Okno terminala
DEF variable_1 VAR
DEF array_with_5_items VARS 5

Warunki są używane do operowania wartościami logicznymi.

Warunki mogą być w większości definiowane automatycznie przy pierwszym wzmiankowaniu. Niektóre operacje jednak (takie jak ‘ISKNOWN’, kopiowanie lub przypisywanie elementów tablicy) wymagają, aby warunek był zdefiniowany wcześniej.

Warunki są definiowane typem COND. Tablice warunków są definiowane typem CONDS, po którym następuje rozmiar tablicy w zakresie 1..65535 (tablica z pojedynczym warunkiem jest skutecznie taka sama jak prosty warunek).

Przykłady:

Okno terminala
DEF is_temperature_high COND

Akcje tworzą iteracyjny algorytm logiczny. Akcje mogą być jedną z następujących:

  • asercja;
  • sprawdzenie;
  • polecenie.

Akcje są wykonywane kolejno z następującymi wyjątkami:

  • akcje sprawdzania pomijają pojedynczą akcję, jeśli ich warunek nie jest TRUE;
  • akcje polecenia takie jak GO, CALL, RETURN przeskakują do etykiety lub wracają z wywołania funkcji;
  • akcja polecenia RAISE lub jakiekolwiek wystąpienie błędu albo przeskoczy do obsługi błędów, albo zatrzyma to wykonanie z powodu nieobsłużonego błędu;
  • akcja polecenia EXIT zatrzymuje to wykonanie.

Istnieją 2 etykiety używane jako główna definicja funkcji pliku zadania:

  • run - każdorazowo gdy wykonywane jest uruchomienie pliku zadania, akcja oznaczona etykietą run jest wykonywana pierwsza (jeśli nie ma takiej etykiety, pierwsza akcja w pliku zadania jest pierwszą do wykonania);
  • onerror - jeśli wystąpi błąd bez innych określonych obsługi, używana jest obsługa oznaczona etykietą onerror (jeśli nie ma takiej etykiety, błąd będzie nieobsłużony, patrz Obsługa błędów poniżej).

Akcja może w niektórych przypadkach odwoływać się do innych elementów, które nie zostały zdefiniowane wcześniej w pliku zadania:

  • tablice zmiennych i tablice warunków powinny być zdefiniowane przed odwołaniem do nich;
  • ewaluacje, które mogą przyjmować argumenty różnych typów (takie jak bezpośrednie kopiowanie), wymagają, aby argumenty były zdefiniowane wcześniej;
  • inne zmienne i warunki mogą być odwoływane bez wstępnej definicji;
  • etykiety mogą być odwoływane przez CALL, TRYCALL lub GO przed ich zdefiniowaniem;
  • ciągi znaków mogą być odwoływane przez SENDSMS, SMSRCVD, NOSMSRCVD, SYSLOG lub PARAMLOG przed ich zdefiniowaniem;
  • we wszystkich innych przypadkach odwoływany element powinien być zdefiniowany wcześniej w pliku zadania.

Asercje to akcje produkujące jakieś dane wynikowe, które przechowują w jednym z elementów przechowywanych (zmienna lub warunek).

Asercje zaczynają się od PUT, po którym następuje nazwa elementu docelowego wyniku. Następnie pojawia się funkcja z odpowiednim typem wyniku dla tego celu (patrz Ewaluacja zmiennej, Ewaluacja warunku poniżej). Jeśli nie określono funkcji, argument jest bezpośrednio kopiowany do celu (może to być również używane do pobierania elementów z tablicy indeksowanej przez zmienną lub ich odkładania z powrotem).

Przykłady:

Okno terminala
DEF numbers VARS 3
PUT numbers[0] 0
PUT numbers[1] 1
PUT numbers[2] 2 ; numbers zawiera [0, 1, 2]
PUT index 2
PUT x numbers[index] ; x zawiera 2
PUT var_mul_result MUL x 2 ; var_mul_result zawiera 4

Sprawdzenia to akcje używane do rozgałęziania. Pomijają następną akcję, jeśli ich funkcja (z wynikiem warunku, czyli wartością logiczną) produkuje FALSE lub wartość nieznaną.

Sprawdzenia zaczynają się od IF, po którym następuje funkcja z typem wyniku warunku (patrz Ewaluacja warunku poniżej). Jeśli nie określono funkcji, argument powinien być nazwą warunku.

Przykłady:

Okno terminala
PUT lesser 5
PUT greater 3
IF LE lesser greater ; LE 5 3 produkuje FALSE, bo 5 <= 3 nie jest prawdą
GO then_section ; to polecenie nie zostanie wykonane
; else section
PUT tmp lesser ; wymiana wartości zmiennych lesser i greater
PUT lesser greater
PUT greater tmp
GO endif_section
then_section:
; dwie zmienne już posortowane, nic do roboty
endif_section:
; dwie zmienne teraz posortowane, lesser <= greater

Polecenia to akcje nietworzące danych wynikowych lub je odrzucające.

Polecenia to jedno z następujących:

  • EXIT - zatrzymuje wykonywanie pliku zadania. Ma 1 argument: nazwę błędu, OK (jeśli brak błędu) lub lasterror.
  • RAISE - wymusza wystąpienie błędu. Ma 1 argument: nazwę błędu lub lasterror (dla podniesienia tego samego błędu wyżej).
  • GO - następna akcja nie zostanie wykonana, wykonywanie będzie kontynuowane od określonej etykiety. Ma 1 argument: nazwę etykiety.
  • CALL - rozpoczyna wykonywanie jakiejś funkcji użytkownika. Wykonanie następnej akcji jest odłożone, wykonywanie będzie teraz kontynuowane od określonej etykiety. Ma 1 argument - nazwę etykiety wejścia funkcji.
  • TRYCALL - rozpoczyna jakąś funkcję użytkownika z własną obsługą błędów. Wykonanie następnej akcji jest odłożone, wykonywanie będzie teraz kontynuowane od określonej etykiety. Ma 2 argumenty - nazwę etykiety wejścia funkcji i nazwę etykiety obsługi błędów.
  • RETURN - kończy wykonywanie funkcji użytkownika. Następna akcja nie zostanie wykonana, wykonywanie będzie kontynuowane od poprzednio odłożonej akcji (przez poprzednio napotkane ‘CALL’).
  • WRITE - wyprowadza dane do parametru. Ma 2 argumenty: nazwę parametru, następnie nazwę zmiennej lub wartość całkowitą.
  • PARAMLOG - zapisuje parametr do dziennika danych z komentarzem. Ma 2 argumenty: nazwę parametru, następnie nazwę ciągu. Parametr musi być w rejestrach Modbus lub w inny sposób zmapowany na Modbus, ponieważ jego adres jest używany w dziennikach.
  • PARAMLOGNOCOMMENT - zapisuje parametr do dziennika danych bez komentarza. Ma 1 argument: nazwę parametru. Parametr musi być w rejestrach Modbus lub w inny sposób zmapowany na Modbus, ponieważ jego adres jest używany w dziennikach.
  • SYSLOG - zapisuje ciąg do dziennika systemowego. Ma 1 argument: nazwę ciągu.
  • SENDSMS - wysyła ciąg jako SMS. Ma 2 argumenty: ciąg adresata, następnie nazwę ciągu tekstu SMS. Jeśli ciąg adresata nie zawiera innych znaków niż 0, SMS nie zostanie wysłany.

Przykłady:

Okno terminala
WRITE param_hysteresis 5
EXIT OK

Funkcje ewaluacji zmiennej są używane w akcji asercji (PUT) do obliczania nowej wartości zmiennej.

Mogą produkować wartość numeryczną lub wynik nieznany (patrz Wartości nieznane poniżej).

Większość z następujących funkcji przyjmuje 2 argumenty (np. a i b) i wykonuje operację.

  • ADD - dodawanie (a + b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • SUB - odejmowanie (a - b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • MUL - mnożenie (a * b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • DIV - dzielenie (a / b, wynik całkowity). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • MOD - reszta z dzielenia (a - (a / b * b)). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • SQRT - pierwiastek kwadratowy (całkowity). Przyjmuje pojedynczy argument: zmienną lub wartość całkowitą.

  • VAL - bezpośrednie kopiowanie. Przyjmuje pojedynczy argument: zmienną lub wartość całkowitą. Jak w przypadku innych ewaluacji bezpośredniego kopiowania, nazwa funkcji VAL może być pominięta.

Większość z następujących funkcji przyjmuje 2 argumenty (np. a i b) i wykonuje operację.

  • BITSAND - logiczne AND każdego bitu a z odpowiednim bitem b. Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • BITSOR - logiczne OR każdego bitu a z odpowiednim bitem b. Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • SHR - arytmetyczne przesunięcie w prawo bitów a, b razy w prawo. Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • SHL - przesunięcie w lewo bitów a, b razy w lewo. Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • BITSBIT - kopiowanie bitu b z bitów a. Jest równoważne SHR a b, po którym następuje BITSAND a 1. Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.

  • BITSNOT - inwersja bitów. Przyjmuje pojedynczy argument: zmienną lub wartość całkowitą.

  • READ - przyjmuje parametr jako argument i odczytuje, a następnie rzutuje jego wartość na domyślny typ zmiennej.
  • MAX - maksymalny element tablicy. Przyjmuje pojedynczy argument: tablicę zmiennych.
  • MAXIDX - indeks maksymalnego elementu tablicy w zakresie od 0 do rozmiaru tablicy minus 1. Przyjmuje pojedynczy argument: tablicę zmiennych.
  • MIN - minimalny element tablicy. Przyjmuje pojedynczy argument: tablicę zmiennych.
  • MINIDX - indeks minimalnego elementu tablicy w zakresie od 0 do rozmiaru tablicy minus 1. Przyjmuje pojedynczy argument: tablicę zmiennych.
  • SUM - suma elementów tablicy. Przyjmuje pojedynczy argument: tablicę zmiennych.
  • SELECTBY - przyjmuje 2 argumenty: tablicę zmiennych i tablicę warunków tego samego rozmiaru, i wybiera zmienną odpowiadającą pierwszemu warunkowi, który jest TRUE.
  • GETUPDPERIODSEC - okres aktualizacji zadania w sekundach. Bez argumentów.
  • GETUPDPERIODMS - okres aktualizacji zadania w milisekundach. Bez argumentów.
  • GETUPDNAMEIDX - pierwsza liczba całkowita w nazwie pliku zadania. Może być używana jako baza lub współczynnik przy mapowaniu parametrów, aby tworzyć kilka podobnych zadań o tej samej zawartości. Bez argumentów.
  • GETRTC - zegar czasu rzeczywistego w sekundach (od roku bazowego, zwykle 2000). Czas lokalny, z DST. Bez argumentów.
  • GETYEAR - rok zegara. Bez argumentów.
  • GETMONTH - miesiąc zegara, od 1 do 12. Bez argumentów.
  • GETDAY - dzień miesiąca zegara, od 1 do 31. Bez argumentów.
  • GETHOURS - godziny zegara. Bez argumentów.
  • GETMINUTES - minuty zegara, od 0 do 59. Bez argumentów.
  • GETSECONDS - sekundy zegara, od 0 do 59. Bez argumentów.
  • GETDOW - dzień tygodnia zegara, od 0 do 6, gdzie 0 oznacza poniedziałek, a 6 niedzielę. Bez argumentów.
  • GETDAYTIME - sekundy dnia, od 0 do 86399. Bez argumentów.
  • GETSUNRISE - sekunda wschodu słońca w danym dniu, od -1 do 86400, gdzie -1 oznacza dzień polarny, a 86400 noc polarną. Bez argumentów.
  • GETSUNSET - sekunda zachodu słońca w danym dniu, od -1 do 86400, gdzie -1 oznacza dzień polarny, a 86400 noc polarną. Bez argumentów.
  • GETVOLTAGE - napięcie zasilania w miliwoltach. Bez argumentów.
  • GETTEMPERATURE - temperatura w stopniach. Bez argumentów.

Przykłady:

Okno terminala
PUT square MUL x x

Funkcje ewaluacji warunku są używane albo w asercjach (akcje PUT), albo w sprawdzeniach (akcje IF) do określania wartości warunku.

Mogą produkować TRUE, FALSE lub wynik nieznany (jeśli odwołują się do innych nieznanych wartości elementów, patrz Wartości nieznane poniżej).

Wszystkie funkcje występują w formie bezpośredniej lub odwróconej, które różnią się tylko tym, czy wynik jest odwracany, czy nie przed użyciem. Funkcje są wymienione w obu formach, np. ‘EQ’ / ‘NE’ dla sprawdzeń równości i nierówności (odwrócone EQ).

  • EQ / NE - równy / nierówny (a = b / a != b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.
  • GE / LS - większy-lub-równy / mniejszy (a >= b / a < b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.
  • GR / LE - większy / mniejszy-lub-równy (a > b / a <= b). Pierwszy argument to zmienna, drugi może być zmienną lub wartością całkowitą.
  • AND / NAND - logiczne AND / odwrócone logiczne AND (a && b / !(a && b)). Przyjmuje 2 argumenty warunku.
  • OR / NOR - logiczne OR / odwrócone logiczne OR (a || b / !(a || b)). Przyjmuje 2 argumenty warunku.
  • VAL / NOT - bezpośrednie kopiowanie / odwrócone kopiowanie (a / !a). Przyjmuje pojedynczy argument: warunek lub wartość logiczną (TRUE lub FALSE). Jak w przypadku innych ewaluacji bezpośredniego kopiowania, nazwa funkcji VAL może być pominięta.
  • SMSRCVD / NOSMSRCVD - sprawdza, czy nowy SMS zaczynający się określonym tekstem przyszedł z numeru zaczynającego się określonymi cyframi. Pierwszy argument to początek numeru telefonu, drugi to początek tekstu SMS. Jeśli numer telefonu jest pustym ciągiem, sprawdzane są SMS-y od dowolnych abonentów.
  • ISKNOWN / ISNOTKNOWN - sprawdza, czy wartość elementu przechowywanego jest znana. Przyjmuje pojedynczy argument: zmienną lub warunek (wartości są nieznane, jeśli są odczytane z niezainicjalizowanych parametrów lub ewaluowane z innych nieznanych elementów, patrz Wartości nieznane poniżej).

Przykłady:

Okno terminala
PUT c_equal EQ x 5
IF c_equal
EXIT OK
; ta sama funkcja może być użyta w sprawdzeniu bezpośrednio
IF EQ x 5
EXIT OK

Przetwarzanie danych jest wykonywane przez ewaluacje zmiennych, które przechowują wartości typu całkowitego.

Jednak odczyt i zapis parametrów mogą rzutować typy danych z i na wartości ułamkowe pojedynczej i podwójnej precyzji, jak zdefiniowano w standardzie IEEE 754. To rzutowanie może być wykonane z mnożnikiem (w zależności od używanego typu parametru), aby zachować określoną liczbę cyfr dziesiętnych części ułamkowej wartości. Niektóre podłączone urządzenia mogą również mieć parametry całkowite reprezentujące wartość ułamkową (wstępnie pomnożoną w podobny sposób jak powyżej).

To pozwala na operowanie wartościami ułamkowymi jako całkowitymi.

Należy zachować ostrożność przy używaniu operacji takich jak mnożenie, dzielenie lub pierwiastek kwadratowy.

Na przykład MUL 2 2 = 4, ale jeśli pierwszy argument reprezentuje wartość 0.2 pomnożoną przez 10, a drugi - wartość 0.02 pomnożoną przez 100 (wartości stałoprzecinkowe odpowiednio z precyzją 1 i 2 cyfr), wynik reprezentuje 0.004 pomnożone przez 1000 (10*100, ponieważ mnożniki również zostały pomnożone).

Pierwiastek kwadratowy z poprzedniej wartości (4 oznaczające wartość 0.004 pomnożoną przez 1000), SQRT 4 produkuje 2, co jest nieprawidłowym wynikiem z powodu mnożnika 1000. Ponieważ SQRT 1000 nie jest liczbą całkowitą. Aby uzyskać prawidłowy wynik, mnożnik tej wartości powinien być dostosowany do najbliższego mnożnika z parzystą liczbą zer, czyli 10000. Więc 4 powinno być wstępnie pomnożone przez 10 (produkując 40 dla 0.004 pomnożonego przez 10000). Wtedy SQRT 40 produkuje 6, co jest prawidłowym wynikiem (oznaczającym 0.06 pomnożone przez 100).

Elementy przechowywane mogą być organizowane w tablicach o stałym rozmiarze. Tablice powinny być zdefiniowane przed odwołaniem do nich w ewaluacjach (np. DEF some_array VARS 5 lub DEF the_other_array CONDS 2).

Istnieją 3 sposoby używania tablic:

  • elementy tablicy z indeksem będącym wartością całkowitą mogą być używane w większości funkcji i asercji zamiast pojedynczej nazwy elementu jako argument (lub wynik asercji, np. PUT some_array[3] MUL some_array[2] some_array[1]).
  • elementy tablicy ze zmiennym indeksem mogą być używane: a) albo w asercjach jako wynik dla bezpośredniego kopiowania lub funkcji jednoargumentowych (np. PUT some_array[ar_idx] SQRT distance), b) albo jako argument dla bezpośredniego kopiowania (włączając funkcję NOT, która jest po prostu odwróconym kopiowaniem warunku, np. IF NOT c_array[counter]).
  • niektóre funkcje ewaluacji tablic przyjmują tablice jako argumenty, wykonując wyszukiwanie lub przetwarzanie i produkując pojedynczy wynik zmiennej.

Błędy mogą wystąpić podczas wykonywania akcji.

Niektóre polecenia jak CALL lub RETURN powodują błąd z powodu niewłaściwego użycia, co wymaga korekty programu. Inne polecenia lub funkcje powodują błąd z powodu albo błędnych wartości argumentów (pierwiastek kwadratowy ze zmiennej ujemnej), albo przyczyn zewnętrznych (np. parametr nie mógł być odczytany lub zapisany).

Wystąpienie błędu w funkcji powoduje przerwanie wykonywania i przeskok do obsługi błędu funkcji. Może to się zdarzyć raz na wywołanie funkcji: jeśli nie podano obsługi lub inny błąd wystąpi w samej obsłudze błędu, wykonywanie kontynuuje w obsłudze funkcji wywołującej. Dla głównej funkcji pliku zadania etykieta onerror jest używana jako domyślna obsługa błędu pliku zadania.

Wstępnie zdefiniowana zmienna lasterror może być użyta do odczytu kodu błędu i wykonywania akcji specyficznych dla błędu.

Jeśli nie jest dostępna obsługa wywołująca, błąd jest uważany za nieobsłużony - wykonywana jest domyślna obsługa podobna do tej:

Okno terminala
SYSLOG default_err_msg
EXIT lasterror
;
DEF default_err_msg "Unhandled error #*VAR(lasterror)*: *ERR(lasterror)*"

Błąd podczas asercji zwykle powoduje, że cel wyniku ma wartość nieznaną. Wartości nieznane mogą również pojawić się bez rzeczywistego błędu, np. podczas odczytu niezainicjalizowanego parametru lub używania zmiennej, która nie została zaasercjonowana.

Wartości nieznane mają tendencję do rozprzestrzeniania się, ponieważ większość funkcji odwołujących się do nieznanej wartości zmiennej lub warunku będzie również powodować wartość nieznaną. Niektóre funkcje mogą nadal określić wynik, niezależnie od elementów nieznanych w ich argumentach. Funkcja tablicy SELECTBY może uzyskać wynik wcześnie (przed osiągnięciem jakichkolwiek elementów nieznanych później). Sprawdzenie logiczne AND może skutkować FALSE, jeśli którykolwiek z jego argumentów jest FALSE (podczas gdy drugi może mieć dowolną wartość), OR może podobnie skutkować TRUE, itp.

Krytyczne polecenia mogą wymagać dodatkowych sprawdzeń (ISKNOWN / ISNOTKNOWN) i bezpośrednich asercji zmiennych lub inicjalizacji parametrów, aby zabezpieczyć się przed stanami nieznanymi.

Akcja sprawdzenia IF traktuje nieznany wynik funkcji jako FALSE i pominie następne polecenie. Pozwala to wybrać między bezpośrednią i odwróconą funkcją sprawdzania, aby zabezpieczyć gałąź przed wykonaniem w stanach nieznanych.

Poniżej znajdują się przykłady gotowych programów, z których każdy składa się z pojedynczego pliku zadania. Aby uruchomić przykład na MC252, konieczne jest:

  1. Utworzenie pliku tekstowego (np. z rozszerzeniem .txt) z tekstem programu.
  2. Umieszczenie pliku w folderze TASKS.
  3. Umieszczenie przygotowanego folderu na karcie pamięci microSD, sformatowanej jako FAT lub FAT32.
  4. Włożenie karty pamięci do MC252.

Ten przykład opisuje program, który w przypadku awarii urządzenia wyśle SMS z ostrzeżeniem.

W tekście pliku zadania:

  • 3 to ID Modbus urządzenia OM-310;
  • 240 to adres rejestru, który jest monitorowany pod kątem awarii.
Okno terminala
# Wysyłanie SMS, gdy bit 0 rejestru 240 urządzenia 3 jest ustawiony
#11ta wersja protokołu
@PROTOCOLVERSION 11
#odstęp ponownego uruchomienia zadania będzie co 3 sekundy
@UPDATE 3
#limit oczekiwania na odpowiedź dla zapytania Modbus to 1000 msek = 1 sek
@PARAMTIMEOUT 1000
#po każdym zapytaniu dodawane jest opóźnienie równe czasowi oczekiwania na odpowiedź,
#więc inni klienci mogą wykonywać swoje zapytania
@PARAMLOADRATIO 50
#MC252 może odczytać i zapisać nie mniej niż 120 rejestrów na jedno zapytanie
#zauważ znak * - to ID Modbus własnego wirtualnego urządzenia Modbus MC252
DEF mc252 MBWRANY * 120 120
#ОМ-310 ma ID Modbus równe 3 i pozwala na odczyt 4 rejestrów na jedno zapytanie,
#ale zapis tylko jednego rejestru na jedno zapytanie
DEF om310 MBWRSINGLE 3 4
#podczas każdej aktualizacji wymagane jest odczytanie
#rejestru przechowywanego o adresie 240 z OM-310
#UINT16 – oznacza, że wartość 16-bitowa jest bez znaku (nie może być mniejsza niż 0)
DEF alarms UINT16 om310 H 240
#każde uruchomienie zaczyna się tutaj
PUT alarm READ alarms
#kopiowanie zerowego bitu rejestru 240
PUT alarm BITSBIT alarm 0
#teraz zmienna zawiera wartość parametru 240.0 0 lub 1
#zmienna jest porównywana z 1, warunek produkuje `TRUE`, jeśli alarm = 1
PUT is_alarm EQ alarm 1
#warunek jest spełniony, jeśli poprzedni warunek nie jest spełniony, i odwrotnie
PUT no_alarm NOT is_alarm
#jeśli warunek is_alarm jest spełniony (jeśli 240.0 = 1), to wyślij jeden SMS
IF is_alarm
SENDSMS technician_number alarm_msg
#koniec programu
EXIT OK
#tekst SMS
DEF alarm_msg "OM-310 (3) – avaria"
#telefon do odbioru SMS może być określony poniżej
DEF technician_number "01234567"

W tym przykładzie program kontroluje wartość histerezy na drugim kanale urządzenia TR-101, w zależności od temperatury czujnika na pierwszym kanale.

Program używa pamięci zasilanej baterią zegara jako magazynu limitów temperatury i odpowiadających parametrów histerezy. Te parametry są mapowane na własne rejestry MC252, aby uprościć konfigurację programu.

W tekście pliku zadania:

  • 16 to ID Modbus urządzenia TR-101;
  • 4 to adres rejestru temperatury kanału 1;
  • 47 to adres rejestru histerezy kanału 2;
  • 5500 to adres dla dolnego limitu temperatury;
  • 5501 to adres dla górnego limitu temperatury;
  • 5502 to adres dla histerezy przy przekroczeniu dolnego limitu temperatury;
  • 5503 to adres dla histerezy przy przekroczeniu górnego limitu temperatury.
Okno terminala
@PROTOCOLVERSION 11
@UPDATE 20 #program będzie działał co 20 sekund
@PARAMLOADRATIO 50
DEF mc252 MBWRANY * 120 120
#TR-101 ma ID Modbus 16 i może odczytać nie mniej niż 100 rejestrów na zapytanie,
#ale zapisać jeden rejestr na jedno zapytanie
DEF tr101 MBWRSINGLE 16 100
#INT16 – rejestry z liczbami całkowitymi ze znakiem, ponieważ temperatura może być mniejsza niż 0
DEF t_lower INT16 MEMBAT H 5500
DEF t_upper INT16 MEMBAT H 5501
DEF t_chan1 INT16 tr101 H 4
#UINT16 – ponieważ histereza nie jest mniejsza niż 0
DEF h_at_lower UINT16 MEMBAT H 5502
DEF h_at_upper UINT16 MEMBAT H 5503
DEF h_chan2 UINT16 tr101 H 47
DEF temperatures VARS 3
DEF hysteresi VARS 3
DEF checks CONDS 3
#początek programu
run:
#dolne i górne limity temperatury, a także jej bieżąca wartość
PUT temperatures[0] READ t_lower
PUT temperatures[1] READ t_upper
PUT temperatures[2] READ t_chan1
# histereza dla temperatur, które są poniżej (lub powyżej) limitów
PUT hysteresi[0] READ h_at_lower
PUT hysteresi[1] READ h_at_upper
# bieżąca wartość histerezy
PUT hysteresi[2] READ h_chan2
# czy temperatura wyszła poza limity?
PUT checks[0] LE temperatures[2] temperatures[0]
PUT checks[1] GE temperatures[2] temperatures[1]
# w innych przypadkach - nie zmieniaj histerezy (bieżąca wartość)
PUT checks[2] TRUE
# pożądana histereza jest wybierana z tablicy hysteresi
# zgodnie z warunkami tablicy checks
PUT hysteresis SELECTBY hysteresi checks
# czy histereza nie jest jeszcze ustawiona na pożądaną wartość?
IF NE hysteresis hysteresi[2]
# zapisz nową histerezę do TR-101
WRITE h_chan2 hysteresis
EXIT OK

W tym przykładzie opisany jest program monitorujący temperaturę mierzoną przez OB-215. Gdy temperatura przekracza -15 stopni przez ponad 10 minut, wysyła SMS i rozpoczyna logowanie wartości temperatury.

W tekście pliku zadania:

  • 11 to ID Modbus urządzenia OB-215;
  • 6 to adres rejestru, z którego odczytywana jest temperatura.
Okno terminala
@PROTOCOLVERSION 11
# program będzie działał co 15 sekund
@UPDATE 15
DEF controller MBWRANY * 120 120
DEF ob215 MBWRSINGLE 11 4
DEF temperature INT16 ob215 H 6
# flaga alarmu - wzrost temperatury przez ponad 10 minut
DEF alarm_temp_high UINT16 MEMTEMP H 5000
# licznik dla opóźnienia 10 minut (600 sekund)
DEF counter UINT16 MEMTEMP H 5001
run:
PUT v_temp READ temperature
PUT v_alarm READ alarm_temp_high
# v_alarm jest automatycznie definiowana powyżej jako zmienna
# (przez konstrukcję PUT v_alarm READ)
IF ISNOTKNOWN v_alarm
PUT v_alarm 0
PUT v_counter READ counter
IF ISNOTKNOWN v_counter
PUT v_counter 0
PUT temp_limit -150
IF GR v_temp temp_limit
GO noticed_temp_high
WRITE alarm_temp_high 0
WRITE counter 0
EXIT OK
noticed_temp_high:
PUT counter_limit 10
PUT counter_limit MUL counter_limit 10
IF GE v_counter counter_limit
GO temp_high_too_long
PUT v_period GETUPDPERIODSEC
PUT v_counter ADD v_counter v_period
WRITE counter v_counter
EXIT OK
temp_high_too_long:
# SMS powinien być wysłany tylko raz -
# (flaga v_alarm stanie się 1 przy następnym uruchomieniu)
IF EQ v_alarm 0
SENDSMS phone1 txt
WRITE alarm_temp_high 1
PARAMLOG temperature txt
EXIT OK
DEF txt "OB-215 (11) – avaria, tmp *VAR(v_temp)* > *VAR(temp_limit)*"
DEF phone1 "01234567" ; numer telefonu dla SMS może być określony tutaj

P: Gdzie powinienem umieścić moje pliki zadań na karcie SD?

O: Umieść pliki zadań w folderze TASKS w katalogu głównym karty SD. Karta SD musi być sformatowana jako FAT lub FAT32. Pliki mogą mieć dowolną nazwę i rozszerzenie z wyjątkiem .OBJ, .MAP, .CNF (np. task.txt) i mogą być również zorganizowane w podfolderach.

P: Jak sprawdzić, czy mój plik zadania ma błędy składniowe?

O: Gdy MC252 ładuje pliki zadań, sprawdza je pod kątem błędów. Jeśli wykryto błędy, plik nie zostanie załadowany. Możesz sprawdzić status ładowania za pomocą rejestrów Modbus (zobacz Mapa rejestrów Modbus, rejestry 2020-2023). System wskaże typ błędu i numer linii, w której znaleziono błąd.

P: Czy mój program przetrwa cykl zasilania lub aktualizację oprogramowania?

O: Program przechowywany w pamięci wewnętrznej jest zachowywany przy wyłączeniach zasilania lub ponownych uruchomieniach. Może zostać usunięty podczas aktualizacji oprogramowania z powodu aktualizacji formatów danych silnika wykonywania logiki. Jednak jeśli karta SD z plikami zadań pozostanie zainstalowana, program zostanie automatycznie ponownie załadowany po aktualizacji.

P: Jak wyczyścić program z pamięci wewnętrznej bez resetowania wszystkich ustawień?

O: Wejdź w tryb konfiguracji przez Modbus i zapisz polecenie 40959 do rejestru 120. To wyczyści tylko wewnętrzną pamięć logiki, zachowując konfigurację urządzenia. Jeśli karta SD z plikami zadań jest zainstalowana, program zostanie automatycznie ponownie załadowany.

P: Co się stanie, jeśli wykonanie mojego zadania potrwa dłużej niż interwał UPDATE?

O: Jeśli następne uruchomienie jest zaplanowane przed zakończeniem bieżącego, zostanie opóźnione i wykonane jak najszybciej. Jeśli wiele uruchomień jest opóźnionych, zostaną pominięte, co może wpłynąć na obliczenia (takie jak liczniki). W tym przypadku rozważ optymalizację długich operacji, podzielenie zadania na dwa lub zwiększenie interwału UPDATE.

P: Czy mogę udostępniać dane między wieloma plikami zadań?

O: Tak. Użyj parametrów z pamięcią źródłową (takich jak MEMTEMP lub MEMBAT) zmapowanych na ten sam adres Modbus w różnych plikach zadań. Tylko jeden plik zadania powinien zapisywać do współdzielonego parametru (“zapisujący”), podczas gdy inne mogą z niego czytać.

P: Jak obsługiwać wartości dziesiętne/ułamkowe, jeśli zmienne są liczbami całkowitymi?

O: Użyj arytmetyki stałoprzecinkowej, mnożąc wartości ułamkowe przez potęgę 10. Na przykład, aby pracować z 2 miejscami po przecinku, pomnóż wartości przez 100. Typy parametrów takie jak F32EP2R automatycznie obsługują tę konwersję podczas odczytu/zapisu. Jednak uważaj na operacje mnożenia, dzielenia i pierwiastka, ponieważ wpływają na pozycję przecinka.

P: Jaka jest różnica między MEMTEMP, MEMBAT, MEMFLASH i MEMFILE?

O:

  • MEMTEMP - przestrzeń RAM, dane są tracone przy wyłączeniu zasilania lub resecie kontrolera, mały rozmiar obszaru, ale doskonała szybkość zapisu;
  • MEMBAT - obszar pamięci zasilany przez wewnętrzną baterię zegara, bardzo ograniczony rozmiar, ale dobra szybkość zapisu;
  • MEMFLASH - obszar ustawień kontrolera, dane zachowują się przy resecie, mały rozmiar i zwykle tylko do odczytu;
  • MEMFILE - rozszerzalny obszar plików, wymaga obecności karty pamięci z plikami zadań, średnia szybkość, ale doskonały rozmiar obszaru.

P: Dlaczego moje sprawdzenie IF pomija polecenie, nawet gdy warunek wydaje się prawdziwy?

O: Sprawdzenie IF traktuje wartości unknown jako FALSE. Jeśli Twoja zmienna nie została zainicjalizowana lub operacja READ się nie powiodła, wartość może być unknown. Użyj ISKNOWN, aby zweryfikować stan zmiennej przed jej sprawdzeniem.

P: Jak debugować mój program pliku zadania?

O: Użyj poleceń SYSLOG, aby zapisywać diagnostyczne komunikaty do dziennika systemowego. Możesz również mapować wartości pośrednie na rejestry Modbus za pomocą parametrów pamięci (np. MEMTEMP H 5000) i odczytywać je przez Modbus.

P: Czy mogę używać tego samego adresu Modbus dla różnych typów parametrów?

O: Tak, dla parametrów tego samego rozmiaru z tym samym adresem. Parametry przechowywane w pamięci w tym przypadku będą współdzielić ten sam obszar pamięci. Jest to przydatne do przesyłania danych między plikami zadań. Jednak parametry MEMFILE (przechowywane na karcie SD) nie obsługują funkcji współdzielenia.

P: Co się dzieje, gdy wystąpi błąd podczas wykonywania programu?

O: Wykonanie przeskakuje do obsługi błędów. Jeśli użyto TRYCALL, przeskakuje do określonej etykiety obsługi. W przeciwnym razie szuka najbliższej obsługi wyższego poziomu, a na końcu etykiety onerror w pliku zadania. Jeśli obsługa nie jest dostępna, błąd jest rejestrowany, a uruchomienie kończy się kodem błędu.

P: Jak wysłać SMS tylko raz po wywołaniu warunku alarmu?

O: Użyj zmiennej flagowej przechowywanej w pamięci trwałej (takiej jak MEMBAT), aby śledzić, czy SMS został już wysłany. Sprawdź flagę przed wysłaniem. Ustaw ją po wysłaniu i wyczyść flagę po zakończeniu warunku alarmu. Zobacz Przykład 3 dla działającej implementacji.

P: Jak sprawdzić przedział czasu, przez który zdarzenie jest aktywne?

O: Użyj licznika (parametru przechowywanego w pamięci do inkrementacji w każdym okresie aktualizacji, gdy zdarzenie trwa, i resetowania do 0 po zatrzymaniu zdarzenia) lub znacznika czasu (zmiennej do przechowywania zegara z rejestrów MC252 na początku zdarzenia i czyszczenia na końcu zdarzenia).

P: Jak sprawdzić, czy zadanie jest uruchamiane po raz pierwszy po resecie lub po wyłączeniu zasilania?

O: Flaga MEMTEMP, jeśli zostanie sprawdzona (a następnie ustawiona na 1, jeśli nie była ustawiona), może wskazać, czy uruchomienie zadania jest pierwsze po cyklu zasilania. Flaga MEMBAT lub MEMFILE może podobnie wskazać, czy jest to pierwsze uruchomienie.

P: Jak przeskanować tablicę? Jak wykonać część kodu określoną liczbę razy?

O: Użyj zmiennej jako indeksu pętli. Sprawdź przed lub po kodzie cyklu. Użyj 1 lub więcej operatorów GO, aby kontynuować cykl lub go zakończyć/przerwać. Nie zapomnij zwiększyć lub zmniejszyć zmiennej indeksu wewnątrz.

P: Czy mogę wykonać powtórzone wykonanie części kodu ze złożonym warunkiem zakończenia pętli?

O: Tak, używając IF i GO. Jednak nie jest to zalecane bez jawnych limitów czasu. Pętla, która nie jest ograniczona stałą, może stać się nieskończona lub w inny sposób przekroczyć skonfigurowany czas aktualizacji zadania. Może to spowodować pominięcia aktualizacji tego zadania lub opóźnienia innych zadań.

P: Czy mogę wywołać funkcję z funkcji? Ile jest poziomów zagnieżdżenia?

O: Tak, możesz wywołać CALL lub TRYCALL funkcję, która z kolei wywołuje inną funkcję. Rozmiar stosu zagnieżdżenia jest równy liczbie operatorów RETURN w pliku zadania. Ze względu na ograniczony rozmiar stosu rekursja nie jest zalecana.

W celu uzyskania wsparcia technicznego i pomocy: