Skrypty w modułach akwizycji

Previous  Next

Moduły akwizycji danych, takie jak:


·    Modbus Master
·    Modbus Slave
·    GazModem
·    MitsubishiMX
·    MultiLon

posiadają wbudowany w swoją strukturę skrypt, który umożliwia przetwarzanie wartości kanałów odczytanych lub mających być zapisanych do urządzeń.
Skrypty takie umożliwiają przeliczenie wartości odczytywanych z urządzeń do wartości rzeczywistych i odwrotnie – przeliczenie wartości rzeczywistych do formatu danych zrozumiałych dla urządzenia.

Przykład 1.

Gdy odczytujemy wartości z urządzeń protokołu GazModem, to wartość określająca stan licznika gazu w warunkach normalnych odczytywana jest z urządzenia z dwóch rejestrów.
Rejestry te zawierają dwa składniki wartości rzeczywistej wskazania, którą można wyznaczyć ze wzoru LG = R1 + 10000 * R2
Operację przeliczenia najlepiej jest wykonać właśnie w skrypcie modułu komunikacyjnego.

W celu skonfigurowania takiego zadania, należy wykonać następujące czynności:

1.  Skonfigurować urządzenie, podłączyć je do modułu komunikacji szeregowej (ComDriver, lub IPSocket) i ustawić parametry transmisji, umożliwiające odczyt zdefiniowanych w IOBlock’u kanałów L0 i L1.

Przeczytaj o konfigurowaniu modułu GazModem.

Poniższy rysunek przedstawia przykładową konfigurację modułu GazModem, zawierającego jeden IOBlock obsługujący dwa kanały.
graphic


Mając tak skonfigurowany system, odczytujemy z urządzenia dwa kanały L0 i L1, których wartości możemy przedstawić w tabelce:


graphic


2.  Teraz należy dodać kanał wyjściowy, który będzie przedstawiał wartość rzeczywistą wskazania.


graphic

Po dodaniu kanału zmieniamy jego nazwę na L

graphic





3.  Dodany kanał o nazwie L, będzie udostępniał dane, które zostaną do niego wpisane przez skrypt.
  

proc notifyIOBlock { block_name } {
# inicjalizacja zmiennych globalnych w których znajdują się wartości
# odczytanych kanałów

  global "Current.L0" "Current.L1"

# wysłanie do kanału L wartości wyliczonej w wyrażeniu expr....
  antIOSetDeviceChannel L [expr [ set "Current.L0" ] \
+ 10000 * [ set "Current.L1" ] ]
}
 


Tak napisany skrypt należy zapisać w pliku tekstowym, i podać jego ścieżkę w konfiguracji urządzenia.

graphic


4.  Skonfigurowany moduł udostępnia wyliczaną wartość, którą można dodać do tabeli:

graphic





Dla lepszego zilustrowania przykładu, zmodyfikowano skrypt tak, aby do wartości L była dodawana stała wartość 100 000, modyfikując funkcję antIOSetDeviceChannel użytą w poprzednim skrypcie.
  

  antIOSetDeviceChannel L [expr [ set "Current.L0" ] \
+ 10000 * [ set "Current.L1" ] \
+ 100000 ]
 

Wyliczona wartość znajduje się w tabelce:

graphic


Przykład 2

Poniższy skrypt przelicza wartości kanałów zdefiniowanych w IOBlock’u „DB” CH0 i CH1, w których znajdują się wartości temperatury i wilgotności odczytane z urządzenia, do wartości T – temperatury po konwersji oraz DT – wyznaczonej temperatury punktu rosy.
  

proc notifyIOBlock { block_name } {

   if { $block_name == "DB"} {
       global "$block_name.CH0" "$block_name.CH1"
       
       # convert temperature to Celsius
       set T [expr [set "$block_name.CH0"] - 273.15]
       set RH [set "$block_name.CH1"]
       
       # saturation vapor pressure over water
       set EW [expr (0.66077+(7.5*$T/(237.3+$T))+(log10($RH)-2))]
       # calculate dewpoint
       set DP [expr ((0.66077-$EW)*237.3) / ($EW-8.16077) ]
       
       antIOSetDeviceChannel T $T
       antIOSetDeviceChannel DP $DP
   }
}
 










Przykład 3

Konfiguracja akwizycji danych w protokole Modbus, konwertująca dane odczytywane z urządzenia, oraz zapisująca do urządzenia konwertowane w skrypcie ustawienie.

graphic

Skrypt przetwarza odczytane z urządzenia wartości kanałów
IO16r.MonDay, IO16r.YeAr i IO16r.HourMin na łańcuch znaków określający datę i czas: N14.Date
Ponadto w skrypcie przetwarzana jest wartość kanału bright, którego wartości są w zakresie od 0 do 100 na wartości akceptowalne przez urządzenie 0-15

graphic


Skrypt przetwarzający dane w przykładzie nr 3

  

proc notifyIOBlock { block_name } {

  if { $block_name == "IO16r" } {
      global IO16r.HourMin IO16r.MonDay IO16r.YeAr
      set HourMin [format "%0.0f"  [ set IO16r.HourMin ] ]
      set MonDay  [format "%0.0f"  [ set IO16r.MonDay ] ]
      
      if { [ string length $MonDay ] == 3 } { set MonDay "0$MonDay" }
      if { [ string length $HourMin ] == 3 } { set HourMin "0$HourMin" }


      set min   [string replace $HourMin 0 1]
      set hour  [string replace $HourMin 2 3]
      set day   [string replace $MonDay  0 1]
      set month [string replace $MonDay  2 3]
      set year  [format "%0.0f" [set IO16r.YeAr] ]
      antIOSetDeviceChannel Date "$year-$month-$day $hour:$min"
  }


}

proc notifyIODeviceChannel { channel_name } {
  global $channel_name
  set br [expr 15 * [set $channel_name ] / 100 ]
  antIOSetBlockChannel IO16w.brt $br
}
 


Struktura skryptu przeliczającego wartości w modułach akwizycji danych.
  

proc notifyIOBlock { block_name } {

}


proc notifyIODeviceChannel { channel_name } {
      
}
 


W skryptach modułów akwizycji wywoływane są funkcje :

notifyIOBlock – po każdej wykonanej operacji odczytu kanałów z IOBlock’u o nazwie block_name

W procedurze notifyIOBlock { block_name } wpisuje się kod przeliczający wartości odczytanych z urządzenia kanałów.
   Wartości kanałów dostępne są w skrypcie jako zmienne globalne o nazwach odpowiadających kanałom zdefiniowanym w IOBlock’ach urządzenia, przy czym nazwy kanałów składają się tylko z członu nazwy bloku oraz samej nazwy kanału.

Ze względu na to, że nazwy kanałów zawierają znaki nieużywane w TCL w nazwach zmiennych, stosuje się funkcję set do pobierania wartości zmiennej.
  

proc notifyIOBlock { block_name } {
      global IOBlock.channel1
      set value [ set IOBlock.channel1 ]
}
 


Długa i krótka nazwa kanału
Przykład:
Pełna nazwa: GazModem.RPM-01.Current.L1
w skrypcie będzie określana jako Current.L1










Należy zwrócić uwagę na to, że zmienne globalne z wartościami kanałów są dostępne po wykonaniu operacji odczytu. Wszystkie zmienne globalne
są dostępne po wykonaniu operacji odczytu na wszystkich blokach.
Używając zmiennej globalnej należy się upewnić, że została przynajmniej raz poprawnie wykonana operacja odczytu jej wartości. Jeśli została wywołana funkcja notifyIOBlock to można operować na kanałach z tego bloku i wszystkich bloków, dla których została wcześniej wywołana ta funkcja.

Taki mechanizm powoduje wyjątek przy próbie wykonania obliczeń na nieodczytanej jeszcze wartości kanału.
Kanałom można przypisać wartości początkowe wpisując na początku skryptu
  

set nazwa_kanału wartość_początkowa
 



notifyIODeviceChannel { channel_name }   - gdy zostanie podana wartość do kanału wejściowego z folderu InputChannels.

W wywołaniu funkcji podawana jest nazwa kanału. Wartość kanału dostępna jest w zmiennej globalnej.

  

proc notifyIODeviceChannel { channel_name } {
  global $channel_name
      set value [set $channel_name]
      
}
 

Używając zmienne globalne należy stosować tę samą zasadę co w przypadku funkcji nofityIOBlock

Funkcje API używane w skryptach.

Funkcje PLCModules wykonywane w modułach skryptowych.




W skryptach modułów akwizycji można używać wszystkich funkcji TCL.
API Tk nie jest wspierane i funkcje z niego nie mogą być używane.
Nie można również wykorzystywać zewnętrznych pakietów TCL. (require package)



Uniwersalność skryptów – krótkie nazwy kanałów

Używanie krótkich nazw kanałów w skryptach powoduje, że są one uniwersalne dla wielu tych samych urządzeń posiadających w konfiguracji różne nazwy, lub/i pracujących w różnych modułach.
Raz napisany skrypt przetwarzający dane z pewnego modelu urządzenia, może być wykorzystany wielokrotnie we wszystkich występujących w konfiguracji programu modułach.