Dobry program do Modbus RTU nie zaczyna się od samego wysyłania bajtów, tylko od zrozumienia magistrali, ramek i tego, jak urządzenia naprawdę odpowiadają na żądania. W tym tekście pokazuję, jak ułożyć komunikację krok po kroku, jakie parametry ustawić, gdzie najczęściej pojawiają się błędy i jak diagnozować problemy bez zgadywania.
Najważniejsze rzeczy, które trzeba ustawić od razu
- W RTU liczy się poprawny format portu, CRC16, adres urządzenia i przerwy czasowe między ramkami.
- Na jednej magistrali jeden klient inicjuje zapytania, a urządzenia odpowiadają po kolei, bez równoległych transakcji.
- Najczęstsze ustawienia startowe to 9600 lub 19200 bodów, 8E1 i RS-485 w topologii liniowej.
- Adres 0 oznacza broadcast, więc program nie powinien oczekiwać odpowiedzi po zapisie rozgłoszeniowym.
- Wiele problemów wynika nie z kodu, tylko z okablowania, terminacji i złego mapowania rejestrów.
Jak działa komunikacja RTU, zanim napiszesz pierwszą linię kodu
W RTU wszystko opiera się na prostej zasadzie: jedno urządzenie inicjuje pytanie, drugie odpowiada. W nowszych materiałach Modbus Organization opisuje ten model jako client/server, choć w automatyce nadal często słychać stare określenia master/slave. Dla programu oznacza to jedno: trzeba pilnować kolejności żądań, adresowania i czasu odpowiedzi, bo magistrala nie wybacza chaosu.
Ramka RTU ma stałą logikę: adres, kod funkcji, dane i CRC16 na końcu. Dokumentacja dla serial line podaje też bardzo konkretne reguły czasowe: między ramkami musi być cisza trwająca co najmniej 3,5 znaku, a przerwa dłuższa niż 1,5 znaku wewnątrz ramki oznacza błąd i taką wiadomość należy odrzucić. To jeden z powodów, dla których program do Modbus RTU nie może być napisany jak zwykły „send and forget”.
| Typ danych | Kody funkcji | Zakres adresów widziany przez człowieka | Uwagi praktyczne |
|---|---|---|---|
| Coils | 01, 05, 15 | 00001–09999 | Bitowe wyjścia, zwykle zapis i odczyt stanu. |
| Discrete inputs | 02 | 10001–19999 | Wejścia tylko do odczytu. |
| Input registers | 04 | 30001–39999 | Rejestry 16-bitowe, tylko odczyt. |
| Holding registers | 03, 06, 16 | 40001–49999 | Najczęstszy obszar konfiguracji i nastaw. |
W praktyce ważny jest jeszcze jeden szczegół: w ramce wysyła się zwykle adres względny, a nie „ludzki” numer z zakresu 40001 czy 30001. To właśnie tu najczęściej rodzą się pomyłki, bo programista widzi w dokumentacji 40011, a w pakiecie powinien wysłać adres 10. Kiedy to uporządkuję na początku, reszta pracy staje się dużo prostsza.

Jak zbudować program do Modbus RTU krok po kroku
Ja zwykle zaczynam od trzech rzeczy: ustawień portu, mapy rejestrów i czasu odpowiedzi. Bez tego nawet poprawnie napisana biblioteka niewiele da, bo urządzenie może milczeć tylko dlatego, że program wysyła zapytanie z inną parzystością albo pod zły adres.
Konfiguruję port szeregowy
Najbezpieczniejszy punkt startowy to ustawienia zgodne z dokumentacją urządzenia, a jeśli jej nie ma pod ręką, to najczęściej 9600 bodów, 8E1 i interfejs RS-485. Taki zestaw daje 11 bitów na znak i dobrze pasuje do typowych sterowników, liczników oraz falowników. Gdy urządzenie wymaga 19200 bodów lub innej parzystości, przepisuję to 1:1, zamiast zgadywać.
Składam ramkę bez zgadywania adresów
Do własnego kodu lub biblioteki sprowadzam tylko to, co naprawdę trzeba wysłać. Struktura zapytania wygląda zwykle tak:
[adres urządzenia][kod funkcji][adres startowy_hi][adres startowy_lo][ilość_hi][ilość_lo][CRC_lo][CRC_hi]Nie warto dorabiać tu „inteligencji” na siłę. Jeśli chcę odczytać jeden holding register, używam funkcji 03. Jeśli zapisuję pojedynczą wartość, sięgam po 06. Jeśli przenoszę większy blok danych, używam 16. Zbyt kreatywne kodowanie ramek kończy się tym, że program niby działa, ale tylko z jednym egzemplarzem urządzenia z biurka.
Przeczytaj również: Regulator PID - Jak działa, jak stroić i unikać błędów?
Odbieram odpowiedź i od razu ją weryfikuję
Odbiór powinien być równie zdyscyplinowany jak wysyłka. Sprawdzam adres, kod funkcji, długość odpowiedzi i CRC. Jeśli urządzenie zwróci wyjątek, bit 7 w kodzie funkcji będzie ustawiony, a w polu danych pojawi się kod błędu. To nie jest „szum z linii”, tylko normalna odpowiedź protokołu, która mówi mi, że trzeba poprawić adres, zakres albo funkcję.
W kodzie trzymam też jedną zasadę: jedna magistrala, jeden tor komunikacji w danym momencie. Jeśli aplikacja ma wiele wątków, to dostęp do portu serial musi być serializowany. W przeciwnym razie nawet poprawne zapytania zaczynają się mieszać i diagnostyka staje się męcząca.
- Otwieram port z poprawnym baud rate, parzystością i liczbą bitów stopu.
- Buduję ramkę zgodną z mapą rejestrów urządzenia.
- Wysyłam ją jako ciągły strumień, bez sztucznych przerw w środku.
- Czekam na odpowiedź w czasie dostosowanym do prędkości i długości magistrali.
- Weryfikuję CRC, adres, kod funkcji i długość danych.
- Dopiero potem zamieniam bajty na wartość liczbową.
Najlepszy efekt daje prosta implementacja z logowaniem surowych ramek. Gdy coś się psuje, od razu widzę, czy problem leży po stronie kodu, czy po stronie magistrali.
Jakie parametry i ograniczenia decydują o stabilności
W RTU najwięcej problemów robi nie sam protokół, tylko granica między logiką a fizycznym łączem. Jeśli topologia, przewód i terminacja są słabe, program będzie wyglądał na winnego, choć faktycznie tylko pokazuje objawy.
| Obszar | Dobry punkt startowy | Dlaczego to ma znaczenie |
|---|---|---|
| Baud rate | 9600 lub 19200 | To najczęstsze, stabilne ustawienia dla urządzeń polowych. |
| Format znaku | 8E1 | Zapewnia typowy format 11-bitowy dla RTU. |
| Przerwa między ramkami | Co najmniej 3,5 znaku | Bez tej ciszy odbiornik nie wie, gdzie zaczyna się kolejna wiadomość. |
| Terminacja | Na obu końcach magistrali | Ogranicza odbicia sygnału i przypadkowe błędy CRC. |
| Topologia | Linia główna z krótkimi odgałęzieniami | RS-485 nie lubi gwiazd i długich odnóg. |
| Timeout programu | Startowo 100–300 ms, potem korekta | Za krótki timeout daje fałszywe błędy, za długi spowalnia cały system. |
Dokumentacja dla serial line podaje, że przy 9600 bodów i kablu AWG26 lub grubszym można dojść do 1000 m długości magistrali, ale w praktyce liczy się też jakość ekranowania, liczba urządzeń i odgałęzienia. Jeśli robisz własny stos komunikacyjny, pamiętaj jeszcze o tym, że powyżej 19200 bodów specyfikacja zaleca stałe wartości timerów t1.5 i t3.5 zamiast wyliczania ich z bieżącej prędkości transmisji. To ma znaczenie szczególnie wtedy, gdy program pracuje na słabszym sterowniku lub mikrokontrolerze z ograniczonym czasem procesora.
Ja zawsze traktuję parametry seriala i magistrali jako część programu, a nie osobny temat. To podejście oszczędza najwięcej czasu, bo eliminuje fałszywe tropy już na starcie.
Najczęstsze błędy w programie i na magistrali
Najwięcej czasu traci się na błędy, które nie wyglądają jak błędy wprost: timeouty, wyjątki Modbus albo odpowiedzi z błędnym CRC. Ja zawsze rozdzielam je na trzy grupy, bo od tego zależy diagnostyka.
| Objaw | Najbardziej prawdopodobna przyczyna | Co sprawdzić w pierwszej kolejności |
|---|---|---|
| Brak odpowiedzi | Zły adres, zła parzystość, zły baud rate albo urządzenie poza zasięgiem | Ustawienia portu, adres urządzenia i ciągłość okablowania. |
| Błąd CRC | Zakłócenia, odbicia sygnału, za długie odgałęzienia, zły format seriala | Terminację, ekranowanie, topologię i 8E1. |
| Exception 02 | Nieprawidłowy adres rejestru | Mapę rejestrów i to, czy używasz adresu względnego, a nie 4xxxx. |
| Exception 01 | Urządzenie nie obsługuje danej funkcji | Instrukcję urządzenia i listę dostępnych kodów funkcji. |
| Brak odpowiedzi po zapisie broadcast | Prawidłowe zachowanie protokołu | Nie czekać na reply, bo adres 0 służy do rozgłoszenia zapisu. |
| Losowe błędy przy większej prędkości | Za szybka transmisja dla danej instalacji | Długość magistrali, jakość przewodu i sensowność timeoutów. |
Jeśli w odpowiedzi widzę kod funkcji z ustawionym najwyższym bitem, nie próbuję zgadywać. To oznacza wyjątek protokołu, a nie „dziwną ramkę” z linii. Wtedy najpierw poprawiam adres, funkcję albo typ danych, a dopiero później sprawdzam warstwę elektryczną.
Warto też pilnować jednego, często pomijanego tematu: serializacja dostępu do portu. Dwa procesy albo dwa wątki, które wysyłają jednocześnie, potrafią wywołać objawy łudząco podobne do uszkodzonego kabla. W praktyce aplikacja powinna mieć jeden kolejkujący punkt dostępu do magistrali.
Jak wygląda odczyt rejestru w praktyce
Najprostszy sensowny scenariusz to odczyt jednego rejestru holdingowego i zamiana surowych bajtów na wartość liczbową. Dla przykładu: urządzenie ma adres 17, a program czyta rejestr 40011. W ramce nie wysyłam jednak numeru 40011, tylko adres względny 10, bo tak działa większość implementacji i tak opisuje to dokumentacja protokołu.
17 03 00 0A 00 01 CRC_lo CRC_hi- Wybieram adres urządzenia 17 i funkcję 03.
- Wysyłam startowy adres rejestru w postaci względnej.
- Ustalam liczbę rejestrów, tutaj: 1.
- Odbieram odpowiedź, sprawdzam CRC i długość danych.
- Składam dwa bajty w 16-bitową wartość.
Przy danych typu float trzeba uważać jeszcze bardziej, bo dwa 16-bitowe rejestry mogą być ułożone w innej kolejności niż oczekuje biblioteka. To jeden z tych problemów, które wyglądają jak błąd komunikacji, a są tylko błędem interpretacji. Dlatego przed uruchomieniem odczytu sprawdzam nie tylko adresy, ale też kolejność bajtów i słów w dokumentacji urządzenia.
Jeśli zapisuję wartość, używam funkcji 06 albo 16. Przy broadcastach dozwolone są tylko operacje zapisu i nie wolno zakładać, że urządzenie odeśle odpowiedź. To szczegół, który często psuje testy robione „na skróty”.
Co sprawdzam przed wdrożeniem na obiekcie
Przed uruchomieniem instalacji patrzę na kilka rzeczy, które w praktyce decydują o tym, czy system będzie działał stabilnie przez miesiące, czy będzie wymagał ciągłych poprawek:
- czy mapa rejestrów jest zgodna z dokumentacją konkretnego urządzenia,
- czy port serial ma ustawione dokładnie te same parametry po obu stronach,
- czy magistrala ma jedną linię główną i krótkie odgałęzienia,
- czy na końcach RS-485 są terminacje,
- czy program loguje surowe ramki i czas odpowiedzi,
- czy timeouty i liczba prób nie obciążają niepotrzebnie magistrali,
- czy jeden proces ma wyłączny dostęp do portu.
Jeśli mam z tego zostawić jedną regułę, to taką: w RTU najpierw porządkuję fizykę łącza, potem mapę rejestrów, a dopiero na końcu sam kod. Taki porządek oszczędza najwięcej czasu, bo eliminuje fałszywe tropy i pozwala odróżnić błąd programu od problemu magistrali.