Gedetailleerde handleiding voor het analyseren van Modbus-communicatieprotocolberichten
I. Overzicht van het Modbus-protocol
Modbus is een serieel communicatieprotocol dat in 1979 is ontwikkeld door Modicon (nu Schneider Electric) voor communicatie tussen programmeerbare logische controllers (PLC's). In meer dan vier decennia van ontwikkeling is het uitgegroeid tot een van de de facto standaardcommunicatieprotocollen op het gebied van industriële automatisering.
Belangrijkste kenmerken:
- Master/slave-architectuur: één masterhost met meerdere slaves, waarbij de master verzoeken initieert en de slaves passief reageren.
- Open protocol: Geen licentiekosten; elke fabrikant kan het gratis implementeren.
- Meerdere transmissiemodi: RTU (binair), ASCII (tekst), TCP (Ethernet).
- Ondersteunt diverse fysieke lagen: RS485 (meest voorkomend), RS232, TCP/IP (Ethernet).
- Duidelijk datamodel: Vier objecttypen – spoelen, discrete ingangen, ingangsregisters en vasthoudregisters.
1.1 Vergelijking van drie protocolvarianten

1.2 Beperkingen van de protocolspecificatie

II. Modbus-datamodel en adresregels
2.1 Vier soorten operationele objecten

2.2 Adresweergave (Cruciaal!)
Verschillende fabrikanten gebruiken verschillende coderingsschema's voor Modbus-adressen, wat de meest voorkomende valkuil is bij praktische implementaties:

Betekenis van het adresvoorvoegsel (standaardweergave in de branche):
- Beginnend met 0: Protocoladres (hexadecimaal), bijvoorbeeld 0x0000
- 4 xxxx: Onderhoudsregisters; bijvoorbeeld, 40001 geeft het protocoladres aan van onderhoudsregister 0.
- 3xxxx: Invoerregister; bijvoorbeeld 30001 geeft het protocoladres van invoerregister 0 aan.
- 0xxxx: Spoel; bijvoorbeeld 00001 geeft het protocoladres van spoel 0 aan. ·
- 1xxxx: Discrete invoer; bijvoorbeeld 10001 geeft het protocoladres van discrete invoer 0 aan.
2.3 Regels voor de verwerking van big data
1.1. Maximaal aantal registers dat per bewerking wordt gelezen: 125 (functiecodes 0x03/0x04)
2.2. Maximaal aantal spoelen/discrete ingangen per bewerking uitgelezen: 2000 (functiecodes 0x01/0x02)
3.3. Maximaal aantal registers waarnaar per bewerking wordt geschreven: 123 (functiecode 0x10)
4.4. Maximaal aantal spoelen waarnaar per bewerking wordt geschreven: 1968 (functiecode 0x0F)
5.5. Overschrijding van deze limieten vereist bloksgewijs lezen/schrijven; zorg voor gespreide polling-intervallen om busconflicten te voorkomen.
III. Gedetailleerde analyse van Modbus RTU-berichten
De RTU (Remote Terminal Unit) is de meest gebruikte Modbus-transmissieprotocol In industriële toepassingen wordt binaire codering gebruikt voor een hoge transmissie-efficiëntie en compatibiliteit met RS485/RS232 seriële interfaces. Een minimale stilteperiode van 3,5 tekens tussen frames is vereist om framegrenzen te kunnen onderscheiden.
3.1 Complete raamwerkstructuur van de RTU
Een compleet instructiedataframe in een RTU bestaat uit de volgende vier onderdelen:

3.2 RTU-berichtvoorbeeld – Holding-registers uitlezen (functiecode 0x03)
[Verzoekbericht] De master leest de holdingregisters van Slave 1 (startadres 0x0001, leest 3 registers):
01 03 00 01 00 03 54 0B
Byte-voor-byte analyse van het verzoekbericht:

[Antwoordbericht] Slave Station 1 retourneert gegevens uit drie registers: 01,03,06,02,2B,00,00,00,64, D5, 87
Byte-voor-byte analyse van het antwoordbericht:

3.3 Gedetailleerde uitleg van standaardfunctiecodes

3.4 Gedetailleerde beschrijving van elke functiecode en berichtindeling
(1) Spoel uitlezen / Discrete ingang uitlezen (functiecodes 0x01/0x02)
[Formaat van het aanvraagframe] (8 bytes in totaal)

[Reactiekaderindeling]

[Voorbeeld van positieanalyse] De responsgegevens bestaan uit 3 bytes (spoelen 20–38):

(2) Lees het holdingregister/lees het inputregister (functiecode 0x03/0x04)
[Formaat van het aanvraagframe] (8 bytes in totaal)

[Reactiekaderindeling]

(3) Schrijf een enkel hold-register (functiecode 0x06)
[Formaat van het aanvraagframe] (totaal 8 bytes)

[Reactiekader] Identiek aan het verzoekkader, bevestigt het dat het schrijven succesvol is verlopen.
(4) Schrijf meerdere onderhoudsregisters (functiecode 0x10)
[Formaat van het aanvraagframe]

[Responsframe-indeling] (8 bytes in totaal): [Adres][0x10][Startadres (2 bytes)][Nummer (2 bytes)][CRC (2 bytes)]
(5) Schrijf een enkele spoel (Functiecode: 0x05)
[Formaat van het aanvraagframe] (8 bytes in totaal): Er worden slechts twee geldige waarden ondersteund voor het schrijven:
- 0xFF00 – Spoel ingesteld op AAN (gesloten)
- 0x0000 – Spoel ingesteld op UIT (open)

[Reactiekader] Identiek aan het verzoekkader, bevestigt het dat het schrijven succesvol is verlopen.
IV. Gedetailleerde analyse van Modbus TCP-berichten
Modbus TCP werkt via het Ethernet TCP/IP-protocol en gebruikt standaard poort 502. In tegenstelling tot de RTU-modus gebruikt Modbus TCP een MBAP-header (Modbus Application Protocol) om berichtgrenzen te definiëren en vereist geen CRC-verificatie (in plaats daarvan vertrouwt het op het ingebouwde foutcontrolemechanisme van het TCP-protocol).
4.1 MBAP-headerstructuur (7 bytes, opgenomen in alle TCP-pakketten)

4.2 Voorbeeld van een Modbus TCP-bericht
[Verzoekbericht] Het hold-register van Slave 1 wordt uitgelezen (startadres 0x0000, er worden 3 waarden uitgelezen):
00 01 00 00 00 06 01 03 00 00 00 03
Veld-voor-veld analyse van het verzoekbericht:

[Antwoordbericht] De slave retourneert gegevens uit drie registers:
00 01 00 00 00 09 01 03 06 02 2B 00 00 00 64
Veld-voor-veld analyse van het antwoordbericht:

4.3 Kernverschillen tussen RTU- en TCP-pakketstructuren

V. Gedetailleerde uitleg van de CRC-16-verificatie
Het CRC-algoritme (Cyclic Redundancy Check) is het frameverificatiemechanisme van Modbus RTU's, ontworpen om fouten tijdens de berichtoverdracht te detecteren. Het genererende polynoom voor CRC-16 is x¹⁶ + x¹⁵ + x² + 1 (gelijk aan 0x8005); in de praktijk wordt het omgekeerde polynoom 0xA001 gebruikt.
5.1 Stappen voor de CRC-16-berekening
6.1. Initialiseer het 16-bits CRC-register met 0xFFFF
7.2. Voer een XOR-bewerking uit tussen de eerste byte en de laagste 8 bits van het CRC-register; sla het resultaat terug op in de laagste 8 bits van het CRC-register.
8.3. Verschuif het CRC-register 1 bit naar rechts, waarbij de hoge bits met 0 worden gevuld; bepaal de uitgeschoven bit (LSB):
9.4. Als de uitgeschoven bit 0 is: Ga door met het naar rechts verschuiven van slechts 1 bit.
10.5. Als de uitgeschoven bit 1 is: Voer een XOR-bewerking uit tussen het CRC-register en 0xA001
11.6. Herhaal stap 3 totdat de verwerking van alle 8 bits van de huidige byte is voltooid.
12.7. Neem de volgende byte en herhaal stappen 2-6 totdat alle bytes zijn verwerkt. 13.8. Nadat alle byteverwerking is voltooid, verwissel je de hoge en lage bytes van het CRC-register om de uiteindelijke checksum te verkrijgen.
14.9. Voeg de uiteindelijke checksum toe aan het einde van het bericht, met de lage byte eerst en de hoge byte laatst.
5.2 CRC-16 berekeningsvoorbeeld (Python-code)
De volgende Python-functie kan direct worden gebruikt om de CRC-16-checksum voor een Modbus RTU te berekenen:
def modbus_crc16(data: bytes) -> bytes:
"""tel Modbus RTU CRC-16 controlecode (Retourneer de eerste twee bytes met de minst significante bit eerst)"""
crc = 0xFFFF
voor byte in data:
crc ^= byte
voor _ in bereik(8):
als crc & 0x0001:
crc = (crc >> 1) ^ 0xA001
anders:
crc >>= 1
# Retourneer eerst de lage byte, gevolgd door de hoge byte
retourneer bytes([crc & 0xFF, (crc >> 8) & 0xFF])
# Geef typische voorbeelden: aantal 01 03 00 01 00 03 CRC
frame = bytes([0x01, 0x03, 0x00, 0x01, 0x00, 0x03])
crc = modbus_crc16(frame)
print(crc.hex()) # export: 540b (0x54 0x0B)
5.3 Locatie van de CRC-controle in het bericht
Aan de hand van verzoekbericht 01 03 00 01 00 03 54 0B als voorbeeld:

De ontvanger berekent de CRC-waarde van de eerste 6 bytes opnieuw en vergelijkt deze met de laatste 2 bytes van het pakket. Als deze verschillen, wordt een transmissiefout gedetecteerd en wordt er geen antwoord teruggestuurd.
VI. Afhandeling van uitzonderingen en details over foutcodes
Wanneer een slave-station een verzoek van het master-station niet kan uitvoeren (bijvoorbeeld vanwege niet-ondersteunde functiecodes of een adres buiten bereik), stuurt het een exception response frame terug. De exception response functiecode is gelijk aan de oorspronkelijke functiecode + 0x80 (dat wil zeggen, de hoogste bit wordt op 1 gezet).
6.1 Abnormaal responsformaat (RTU)
[Slaveadres][Functiecode | 0x80][Abnormale code][CRC-16]

6.2 Betekenis van standaard uitzonderingscodes

6.3 Voorbeeld van een abnormale reactie
[Scenario] Het masterstation vraagt om een register op een ongeldig adres te lezen van slavestation 1, en het slavestation retourneert een uitzondering:
Verzoek: 01 03 00 20 00 01 XX XX (register lezen op adres 0x0020);
Uitzonderingsreactie: 01 83 02 C0 F1;
Byte-voor-byte analyse van het antwoord op de uitzondering:

VI. Inleiding tot Modbus ASCII-berichten
De Modbus ASCII-modus codeert alle databytes als twee ASCII-tekens (bijvoorbeeld 0x0F wordt gecodeerd als "0F"). Hoewel dit goed leesbaar is, biedt het een lage transmissie-efficiëntie en wordt het voornamelijk gebruikt voor debugdoeleinden.
7.1 ASCII-framestructuur
Volledig ASCII-frameformaat:

7.2LRC-verificatiealgoritme
Stappen voor het berekenen van LRC (Longitudinal Redundancy Check):
15.1. Voer binaire sommatie uit op alle bytes van het adresveld, de functiecode en het dataveld (met uitzondering van de begin- en eindmarkeringen).
16.2.Negeer overdrachtsbits (als het resultaat groter is dan 255, ga dan automatisch terug naar de beginpositie en behoud alleen de onderste 8 bits).
17.3. Bereken het complement van het sommatieresultaat modulo 1 (d.w.z. 0xFF − sum).
18.4. Verhoog het complement met 1 om de uiteindelijke LRC-controlecode te verkrijgen (1 byte).
19.5. Codeer de LRC-controlecode als twee ASCII-tekens en voeg deze toe aan het einde van het bericht.
VIII. Praktische tips en veelvoorkomende problemen
8.1 Problemen met bytevolgorde (big-endian/micro-endian)
De Modbus-standaard Het maakt gebruik van big-endian-volgorde (met de meest significante byte eerst) voor het verzenden van 16-bits of langere gegevens. Sommige apparaten (bijvoorbeeld bepaalde ARM-gebaseerde apparaten) gebruiken micro-endian-volgorde; conversie van de bytevolgorde is nodig om numerieke parseerfouten te voorkomen.

8.2 Limiet voor de grootte van de registratie-eenheid (PDU ≤ 253 bytes)

8.3 Aanbevelingen voor de configuratie van de communicatietime-out en herhaalpogingen
Aanbevolen configuraties:
- Pollinginterval: ingesteld op 2-3 keer de maximale reactietijd van de slave (doorgaans 100-500 ms) • Time-outduur: aanbevolen bereik van 1000-3000 ms, instelbaar op basis van de reactiesnelheid van de slave
- Herhaalpogingen: Aanbevolen limiet van 3; activeer een alarm als het mislukt
- Polling van meerdere slaves: Plan gespreide polling-intervallen tussen de slaves om busconflicten te voorkomen. • Byte-time-out: In RTU-modus wordt een tekeninterval dat langer is dan 1,5 tekentijd beschouwd als een framefout.
8.4 Aanbevolen debugtools
Bijlage: Snel naslagtabel voor veelvoorkomende berichten
Spoel uitlezen (functiecode 0x01)
[Verzoek]: Lees van slavestation 1 op startadres 0 (spoel 1), ontvang 8 spoelstatusberichten: 01 01 00 00 00 08 3D CC
[Reactie]: Acht spoelstatussen: 0x55 (01010101B);
Bericht: 01 01 01 55 94 36
Schrijf naar één enkele spoel (functiecode 0x05)
[Verzoek] Zet spoel op adres 0 op AAN (schrijf waarde 0xFF00):
Bericht: 01 05 00 00 FF 00 8C 3A
[Verzoek] Zet spoel op adres 0 op UIT (schrijf waarde 0x0000):
Bericht: 01 05 00 00 00 00 CD CA
[Reactie] Identiek aan het verzoekframe
Schrijf naar één register (functiecode 0x06):
[Verzoek] Schrijf waarde 0x1234 naar het register op adres 0.
Bericht: 01 06 00 00 12 34 XX XX (XX is CRC, moet nog berekend worden).
[Reactie] Identiek aan het verzoekframe.
Schrijven naar meerdere registers (functiecode 0x10)
[Verzoek]: Schrijf naar twee registers, beginnend bij adres 0, met respectievelijk de waarden 0x1234 en 0xABCD.
Bericht: 01 10 00 00 00 02 04 12 34 AB CD XX XX
[Antwoord]: Geef het startadres en het aantal beschreven registers terug.
Bericht: 01 10 00 00 00 02 41 C8
Lees de invoerregisters (functiecode 0x04)
[Verzoek]: Lees van slave 1 op startadres 0, lees twee ingangsregisters
berichten: 01 04 00 00 00 02 71 CB
[Reactie]: Retourneer twee waarden uit het invoerregister
berichten: 01 04 04 00 64 01 90 XX XX (Retourwaarden: 100 en 400)










