Protokół ADAM-ASCII
Czyli prosta implementacja protokołu komunikacyjnego
Komunikacja modułów serii ADAM-4000/5000 wyposażonych w interfejs RS-485 z innymi
urządzeniami pełniącymi funkcje jednostek nadrzędnych w systemie pomiarowym oparta jest w głównej
mierze o prosty protokół w formacie komend ASCII opracowany przez producenta (wszystkie moduły
wejść/wyjść w serii ADAM-4000 oraz kasety komunikacyjne bez wbudowanych kontrolerów w serii
ADAM-5000 wyposażone w port szeregowy RS-485). Każda z komend protokołu składa się praktycznie z
czterech części:
• znak początku,
• adres modułu,
• kod komendy,
• znak kończący.
Znakiem poczatku jest zazwyczaj $ lub #. Adres modułu (do którego wysyłamy komendę) określany jest
za pomocą dwóch znaków odpowiadających reprezentacji jego adresu w systemie szesnastkowym
(wymagane są duże litery). W zależności od typu komendy, jej kod składa się z jednego do kilku znaków.
Znakiem kończącym jest zawsze znak powrotu karetki <cr>=0x13. W przypadku odpowiedzi sytuacja jest
podobna. Rozpoczyna się znakiem potwierdzenia (jest to zazwyczaj > lub !), po którym występuje (np. w
przypadku odpowiedzi na komendy typu "Read...") wartość zwracana przez moduł, a kończy się także
znakiem powrotu karetki.
Specyfikacja całości protokołu zawiera łącznie kilkadziesiąt komend (wśród których występują te
odpowiedzialne za samą konfigurację i diagnostykę sprzętu oraz komendy wykorzystywane już podczas
samej pracy modułów) i została oczywiście zawarta w instrukcji użytkownika sprzętu. Kilka przykładów
zawarto w poniższej tabeli:
Typ komendy
Format zapytania
Format odpowiedzi
Przykład
zapytania
Przykład
odpowiedzi
Read Module
Name
$AAM<cr>
!AA(ModuleName)<cr>
$01M<cr>
$02M<cr>
!014017P<cr>
!024055<cr>
Read Firmware
Version
$AAF<cr>
!AA(Version)<cr>
$01F<cr>
$02F<cr>
!01A2.02<cr>
!02A2.04<cr>
Read Conf. Status
$AA2<cr>
!AATTCCFF<cr>
$012<cr>
!01FF0600<cr>
Set Configuration
%AANNTTCCFF<cr>
!AA<cr>
%0112050600<cr>
!12<cr>
...
...
...
...
...
Read Analog Input
#AAN<cr>
>(data)<cr>
#010<cr>
>+04.416<cr>
Digital Data In
$AA6<cr>
!(dataout)(datain)00<cr>
$026<cr>
!FCFC00<cr>
Digital Data Out
#AABB(data)<cr>
><cr>
#02003A<cr>
><cr>
Wymieniona na pierwszym miejscu komenda "Read Module Name" jest najprostszą, bardzo ważną i
pomocną komendą, pozwalającą na sprawdzenie poprawności komunikacji z danym modułem.
Wykorzystywana jest także np. przez program narzędziowy Adam Utility do wyszukiwania wszystkich
modułów (z aktywowanym protokołem ADAM-ASCII) włączonych do danej sieci RS-485. Komendą dość
rozbudowaną jest np. ostatnia z wymienionych - "Digital Data Out", więc dla przykładu przeanalizujemy
jej strukturę. Dokładny opis komendy znajdujemy oczywiście w dokumentacji do serii ADAM-4000:
• # is a delimiter character.
• AA (range 00-FF) represents the 2-character hexadecimal address of the output value.
• BB is used to indicate whether all channels will be set or a single channel will be set. In the last case, BB will also
indicate which channel it is. Writing data (a byte) to all channels should make both characters to be zero (BB=00).
Writing data (a bit) to a single channel; however, will make the first character 1 and the second character ranging from
0 to B. The second character indicates the channel number.
• (data) is the hexadecimal representation of the digital output value(s). Two characters are for ADAM-4050, 4055,
4060 and 4068. Four characters are for ADAM-4056S and 4056SO.
Okazuje się więc, że wygenerowanie odpowiedniej zawartości komendy nie jest wcale aż tak
skomplikowane. Pierwszy znak musi być znakiem rozpoczynającym #. Dwa kolejne znaki muszą
reprezentować adres modułu w formacie heksadecymalnym (np. 21 dla modułu o adresie 33). Dwa kolejne
znaki określają czy chcemy zapisać całą paczkę danych, czy tylko jeden bit. A ostatnie znaki (2 lub 4 - w
zależności od ilości wyjść cyfrowych w danym module; przed kończącym komendę znakiem powrotu
karetki) reprezentować muszą heksadecymalną wartość odpowiadającą wymuszanemu stanowi wyjść
cyfrowych. I tak na przykład:
• #140005<cr> - to zapis wartosci 05h (00000101, odpowiednio dla wszystkich wyjść CH7÷Ch0) w module
o adresie 20,
• #211201<cr> - to zapis wartości 01 (ustawienie stanu wysokiego) dla wyjścia CH2 w module o adresie 33.
UWAGA: Opisywany protokół umożliwia także korzystanie z sumy kontrolnej. Zgodnie z dokumentacją producenta:
"The checksum is represented by a 2-character ASCII hexadecimal format and is transmitted just prior to the carriage
return. The checksum equals to the result after performing modulus-256 (100h) of all the ASCII values sum preceding
the checksum. If the checksum is missing or incorrect, the module will not respond."
Jeżeli chcemy skorzystać z tej
możliwości to:
• sumę kontrolną musimy włączyć przy konfiguracji danego modułu (ta opcja tylko w trybie INIT),
• i oczywiście dwa znaki reprezentujące tę sumę kontrolną dodawać musimy do każdej wysyłanej komendy.
Algorytm jej generowania jest bardzo prosty - przykładowa implementacja w języku Pascal/Delphi może wyglądać
następująco:
function ADAMCHECKSUM(komenda:string):byte;
var i,suma:integer;
begin
suma:=0;
for i:=1 to length(komenda) do suma:=suma+ord(komenda[i]);
suma:=suma mod 256;
ADAMCHECKSUM:=suma;
end;
Korzystając z opisu protokołu zawartego w dokumentacji do modułów ADAM, komunikację z
urządzeniami można więc implementować we własnym zakresie w oparciu o bezpośrednią obsługę łącza
szeregowego (zarówno w przypadku współpracy modułów z komputerem, jak i innym urządzeniem typu
sterownik PLC itp). W przypadku komunikacji modułów kontrolno-pomiarowych z komputerem
wykorzystać można także bezpłatne biblioteki dll dostarczane przez producenta. W tym celu należy:
• zainstalować pakiet menadżera urządzeń (devmgr.exe),
• zainstalować pakiet bibliotek (adamdll.exe),
• opcjonalnie: zainstalować pakiet przykładowych programów (examples.exe),
• w konfiguracji urządzeń dodać i odpowiednio skonfigurować:
• port szeregowy,
• podłączone do niego moduły pomiarowe,
• w tworzonej aplikacji wykorzystać odpowiedni plik nagłówkowy (np. w przypadku Delphi będzie to
driver.pas),
• wykorzystać odpowiednie funkcje biblioteczne do obsługi sprzętu.
Przykładowy kod programu (Delphi) pozwalający na opdczyt wejścia analogowego będzie bardzo prosty:
DRV_SelectDevice(Handle,true,DeviceNumber,@szbuffer[0]);
DRV_DeviceOpen(DeviceNumber,DeviceHandle);
ptAIVoltageIn.chan:=0;
ptAIVoltageIn.voltage:=@Voltage;
DRV_AIVoltageIn(DeviceHandle,ptAIVoltageIn);
DRV_DeviceClose(DeviceHandle);
Czyli polegać będzie praktycznie tylko na:
• wyborze urządzenia,
• otwarciu urządzenia,
• odczycie wejścia,
• zamknięciu urządzenia.