In deze les

Wat deze les behandelt

  • De vier velden van een RTU-frame, byte voor byte
  • Waarom alleen de CRC met het low byte eerst in het frame staat
  • Wat er gebeurt als de CRC niet klopt: een timeout, geen foutmelding

Lees eerst: Exception codes lezen en de juiste function code kiezen, Baudrate en pariteit: waarom 8E1 de default is

Een Modbus RTU frame is niet meer dan vier velden achter elkaar: een adresbyte, een function code, de data en twee CRC-bytes. Er zit geen startteken in en geen lengteveld, dus de bytes zelf zijn alles wat je hebt. Na deze les ontleed je elk frame uit een capture, reken je vooraf uit hoe lang het antwoord wordt, en zie je aan de CRC of een frame heel is aangekomen.

Een echt frame, byte voor byte

Zo gaat een compleet leesverzoek over een RS485-bus:

01 03 00 6B 00 03 74 17

Acht bytes, meer niet. Zo lees je ze:

ByteHexVeldWat het betekent
101serveradreshet verzoek is voor het apparaat op adres 1
203function codeFC03, Read Holding Registers
3 en 400 6Bstartadreshigh byte eerst, dus 0x006B is 107. Dat is het PDU-adres; in datasheettaal register 40108
5 en 600 03aantal registersdrie registers, dus de PDU-adressen 107, 108 en 109
7 en 874 17CRC-16de CRC-waarde 0x1774, low byte eerst

Pas nu de regel eronder. Elk RTU-frame heeft dezelfde vier velden in dezelfde volgorde: 1 adresbyte, 1 function code byte, 0 tot 252 databytes en 2 CRC-bytes. Wat die databytes betekenen bepaalt de function code; welke codes bestaan staat in de referentie van de Modbus function codes. Voor Modbus RTU als transport is de uitleg over Modbus RTU de naslagpagina bij deze les.

1 byteServeradres1 byteFunction code0 tot 252 bytesData2 bytes, low byte eerstCRC-163,5 karaktertijdenStiltet = 0einde framevolgend frame
Vijf vaste onderdelen. De stilte hoort erbij, want die markeert de grens tussen twee frames.

Het antwoord op datzelfde frame

Het apparaat op adres 1 antwoordt met elf bytes:

01 03 06 02 2B 00 00 00 64 05 7A
ByteHexVeldWat het betekent
101serveradreshetzelfde apparaat antwoordt
203function codeweer FC03, dus dit is een normaal antwoord
306byte counter volgen zes databytes
4 en 502 2Beerste register0x022B is 555
6 en 700 00tweede register0
8 en 900 64derde register0x0064 is 100
10 en 1105 7ACRC-16de CRC-waarde 0x7A05, low byte eerst

Twee dingen lees je hier meteen af. De function code is ongewijzigd 03, dus er ging niets mis. En het derde veld telt bytes, geen registers: bij drie registers staat er 6. Dat veld heet in datasheets en tools byte count.

Daarmee heb je de rekenregel. Een FC03-verzoek is altijd 8 bytes; het antwoord is 5 + 2N bytes, met N het aantal registers: 1 adres, 1 function code, 1 byte count en 2 CRC, plus twee bytes per register.

Nu een voorbeeld dat op precies een punt afwijkt:

01 83 02 C0 F1

Zelfde apparaat, zelfde vraag, maar de function code is 83 in plaats van 03. Dat is 0x03 plus 0x80: het hoogste bit staat aan, en dat betekent exception-antwoord. De byte erna is de exception code, hier exception 02. Wat die codes betekenen behandelt de les over function codes en exceptions.

Waar begint en eindigt een frame?

Een frame begint en eindigt met stilte, want een andere markering is er niet. In beide frames hierboven zit geen startteken en geen lengteveld: de ontvanger weet alleen dat de lijn stil was en dat er daarna karakters kwamen.

Die stilte is vastgelegd in karaktertijden, niet in milliseconden. Een RTU-karakter is altijd 11 bits, dus bij 19200 baud duurt een karakter 0,573 ms. Daaruit volgen de twee grenzen uit de les over baudrate, pariteit en timing, nu met een frame ernaast: t3,5 is 2,005 ms stilte tussen twee frames, en t1,5 is 0,859 ms maximale gaping binnen een frame.

Frame 1: 01 03 00 6B 00 03 74 17Frame 2: 01 03 06 02 2B 00 00 00 64 05 7A1 karakter = 11 bits, bij 19200 baud 0,573 ms12Tijd op de bus1t1,5: maximale gaping binnen een frame0,859 ms bij 19200 baud2t3,5: stilte die het frame afsluit2,005 ms bij 19200 baudBoven 19200 baud beveelt de standaard vastewaarden aan: 750 microseconden en 1,750 ms.
Zonder lengteveld is de stilte voor en na het frame de enige berichtgrens die Modbus RTU kent.

De maximale framegrootte ligt wel vast: 256 bytes voor een compleet RTU-frame, dus 1 adresbyte, 253 bytes PDU en 2 CRC-bytes. Van die PDU gaat 1 byte naar de function code en blijven er 252 databytes over. Trek daar in een FC03-antwoord de byte count af, dan blijven er 251 bytes voor registerwaarden over. Een register is 2 bytes, dus passen er 125 in, en dat is precies de bovengrens van 125 registers die de spec voor FC03 noemt.

Wat de CRC precies is, en wat hij niet vangt

De CRC-16 is een controlegetal dat de zender over alle voorgaande bytes uitrekent en achter het bericht plakt, zodat de ontvanger ziet of er onderweg iets veranderd is. Met de hand hoef je hem nooit uit te rekenen, maar je moet wel weten waar hij over gaat.

Drie afspraken leggen de berekening vast: de startwaarde is 0xFFFF, het polynoom is 0xA001 in de gespiegelde vorm die je in code gebruikt, en er is geen finale XOR. De CRC loopt over het adresbyte, de function code en alle databytes. Niet over de start-, stop- en pariteitsbits, want die horen bij het transport en niet bij het bericht.

Daarmee is ook duidelijk waarom pariteit en CRC naast elkaar bestaan. Pariteit werkt per karakter en ziet alleen een oneven aantal omgeklapte bits in dat ene karakter; de CRC werkt over het hele bericht. Ze vervangen elkaar niet, ze vullen elkaar aan. Het algoritme zelf hoef je alleen uit te schrijven als je een eigen library bouwt.

Waarom de CRC omgekeerd in het frame staat

Omdat de standaard het zo voorschrijft, en omdat dit de enige plek in een RTU-frame is waar dat gebeurt. De berekende CRC-waarde van het verzoek uit de eerste sectie is 0x1774, maar op de lijn staat 74 17: eerst de low byte, dan de high byte.

Alle andere 16-bits velden gaan andersom. Het startadres 0x006B staat als 00 6B in het frame, het aantal registers 3 als 00 03, en de registerwaarde 555 als 02 2B. Allemaal high byte eerst. Alleen de twee CRC-bytes zijn omgedraaid.

Nog een voorbeeld, zodat je het patroon herkent: het verzoek 01 03 00 00 00 0A heeft CRC-waarde 0xCDC5 en gaat als 01 03 00 00 00 0A C5 CD over de bus.

De truc die ontvangers gebruiken

Een ontvanger hoeft de meegestuurde CRC niet met een zelf berekende waarde te vergelijken. Hij rekent de CRC over het complete frame inclusief de twee CRC-bytes, en de uitkomst moet 0x0000 zijn. Dat klopt voor 01 03 00 6B 00 03 74 17 en voor 01 03 00 00 00 0A C5 CD.

Elk frame uit een capture kun je dus zelf nacontroleren. De decoder hieronder doet dat, en noemt de verwachte waarde als de CRC niet klopt.

CRC klopt

01
0
03
1
00
2
6B
3
00
4
03
5
74
6
17
7
  • Serveradres
  • Function code
  • Data
  • CRC-16
VeldHexDecimaalBetekenis
Serveradres011
Function code033Read Holding Registers
Startadres00 6B107
Aantal00 033
CRC-1674 176004
Plak een frame uit je eigen buscapture en controleer de CRC voordat je de bekabeling verdenkt.

Wat er gebeurt als de CRC niet klopt

Niets. De server voert het bericht niet uit en bouwt geen antwoord, dus de client wacht tot zijn response timeout afloopt. Er komt geen exception, geen foutcode en geen melding.

Dat is de belangrijkste praktijkregel uit deze les, want het bepaalt hoe je een storing leest. Een exception betekent dat de communicatie op orde is en dat er een logisch probleem is: verkeerd registeradres, verkeerde function code, te veel registers tegelijk. Een timeout betekent dat het eerder misgaat: verkeerd serveradres, verkeerde baudrate of pariteit, een onderbroken lijn, of te veel bitfouten. De standaard noemt bij 9600 bps een response timeout van een seconde tot enkele seconden, dus je merkt zo'n stil frame pas na die wachttijd.

Welke oorzaken je in welke volgorde nagaat staat in de les over storingen op een RTU-bus. Wil je eerst weten welke apparaten antwoorden, dan is een scan van je Modbus-netwerk de snelste stap.

Veelgemaakte fouten

De CRC-bytes omdraaien. De CRC-waarde 0x1774 hoort als 74 17 in het frame te staan. Wie hem als 17 74 schrijft krijgt van geen enkel apparaat antwoord. Adressen, aantallen en registerwaarden gaan wel high byte eerst; de CRC is de enige uitzondering.

Byte count en aantal registers verwisselen. In een antwoord staat een byte count, geen registerteller. Bij drie registers staat er 6, en wie die 6 als "zes registers" leest zoekt zes waarden waar er maar drie staan. Deel de byte count altijd door 2 voordat je gaat tellen.

Een timeout lezen als "het apparaat is er niet". Een CRC-fout geeft stilte, en stilte ziet er in een log precies zo uit als een afwezig apparaat. Controleer daarom eerst de fysieke laag en de seriele instellingen voordat je het adres in twijfel trekt.

Denken dat een pauze halverwege het frame niet uitmaakt. Een gaping van meer dan t1,5 tussen twee karakters maakt het frame ongeldig, ook als alle bytes kloppen. Een USB-adapter die zijn buffers in stukjes doorgeeft veroorzaakt precies dat.

Aan de slag

Je ontleedt eerst een frame op papier en controleert daarna je antwoord met de decoder. Stap 1 tot en met 5 hebben geen hardware nodig.

  1. 1

    Schrijf het frame over

    Neem 01 03 00 00 00 0A C5 CD en schrijf per byte op wat je denkt dat hij doet, voordat je iets opzoekt.

  2. 2

    Benoem de vier velden

    Bepaal het serveradres, de function code, het startadres en het aantal registers. Let op dat de twee 16-bits velden high byte eerst staan.

  3. 3

    Reken de lengte van het antwoord uit

    Er worden 10 registers gevraagd, dus 20 databytes. Plus 1 adres, 1 function code, 1 byte count en 2 CRC: samen 25 bytes.

  4. 4

    Controleer met de decoder

    Plak het frame in de decoder hierboven en vergelijk veld voor veld met je eigen ontleding.

  5. 5

    Sloop een byte

    Verander een enkele byte, bijvoorbeeld de 0A in een 0B, en kijk welke CRC-waarde de decoder dan verwacht. Zo zie je dat een verschil van een bit een compleet andere CRC oplevert.

  6. 6

    Kijk mee op je eigen bus

    Heb je hardware, draai dan mbpoll (gratis te gebruiken, ook zakelijk) met de schakelaar -v, zodat de verzonden en ontvangen bytes op je scherm komen. Vergelijk die bytes met je ontleding. Of open de Protocol Analyzer in ModbusCloud Diagnostics, die dezelfde bytes per frameonderdeel kleurt en er een korte beschrijving bij zet.

Je bent klaar als je ontleding gelijk is aan wat de decoder toont, en als je bij het gesloopte frame de verwachte CRC-waarde ziet staan.

Samenvatting

  • Elk Modbus RTU frame bestaat uit een adresbyte, een function code, 0 tot 252 databytes en 2 CRC-bytes, met een maximum van 256 bytes voor het hele frame.
  • Een FC03-verzoek is 8 bytes lang en het antwoord 5 + 2N bytes, want de byte count telt bytes en geen registers.
  • Adressen, aantallen en registerwaarden staan high byte eerst, en alleen de CRC staat omgedraaid: 0x1774 gaat als 74 17 over de lijn.
  • Een ontvanger berekent de CRC over het complete frame inclusief de CRC-bytes en verwacht als uitkomst 0x0000.
  • Een CRC-fout levert stilte op en geen exception, dus een timeout wijst op de fysieke laag, de seriele instellingen of het serveradres.

Controleer jezelf

Vier vragen over deze les. Je krijgt bij elk antwoord uitleg.

Vraag 1 van 4
In het frame 01 03 00 6B 00 03 74 17: welk startadres wordt opgevraagd, in decimaal?
Hoeveel bytes lang is het antwoord op 01 03 00 00 00 0A C5 CD?
Een frame komt binnen met een verminkte byte, waardoor de CRC niet klopt. Wat stuurt de server terug?
Je ziet in een capture 01 03 06 02 2B 00 00 00 64 05 7A. Wat staat er in het derde register?

Loopt het vast op een project?

Beschrijf wat je ziet en waar het misgaat. We kijken mee en zeggen wat we zouden doen.

Verder lezen in de kennisbank