Modbus function codes uitgelegd: complete referentie voor installateurs (2026)
Modbus function codes uitgelegd voor installateurs. Read holding registers (0x03), write multiple (0x10), exception codes, en de 40001 vs 0x0000 valkuil.

Modbus function codes vertellen elke slave op de bus wat de master wil: lezen of schrijven, een bit of een 16-bit register, één adres of een blok. Wie de codes uit zijn hoofd kent, leest een Wireshark trace meteen en weet bij een exception response in vijf seconden waar het misgaat. Wie dat niet kent, schiet in elke storing een uur verloren tijd in.
Dit artikel geeft je de volledige function code lijst, de byte voorbeelden die je in de praktijk tegenkomt op een Eastron SDM630 of een Viessmann warmtepomp, en het verschil tussen function code 0x03 en het legacy "40001" adres dat je in oude PLC handleidingen ziet. Bedoeld voor installateurs, niet voor protocol auteurs.
Key takeaways
- Modbus heeft vier register types (coils, discrete inputs, holding registers, input registers) en negen veel gebruikte function codes die daar één op één op mappen.
- Function code 0x03 (read holding registers) en 0x10 (write multiple registers) dekken samen ongeveer 80 procent van het verkeer in HVAC en koeltechniek.
- Een exception response heeft dezelfde function code als het verzoek, maar met bit 7 op 1 gezet. 0x03 wordt dan 0x83.
Wat is een Modbus function code precies?
Een Modbus function code is een 1 byte veld in elk Modbus frame dat aangeeft welke operatie de master vraagt en welke register klasse hij aanspreekt. De code zit altijd direct na het slave adres (RTU) of na de MBAP header (TCP), zoals beschreven in de Modbus Application Protocol Specification V1.1b3 van de Modbus Organization.
Function codes zijn niet hetzelfde als register adressen. De function code zegt WAT je doet (lezen of schrijven, één of meerdere, bit of word), het register adres zegt WAAR. Dat onderscheid is het meest gemiste detail bij installateurs die net beginnen met Modbus. Voor de bredere context van het protocol zelf, zie ook onze complete gids over Modbus en de Modbus RTU uitleg voor de frame opbouw.
In de praktijk zijn er twee groepen function codes: de publieke codes (toegewezen door Modbus.org, gedocumenteerd in de spec), en de user defined codes in de ruimte 0x41 tot 0x48 en 0x64 tot 0x6E die fabrikanten zelf mogen invullen. Voor 99 procent van het werk in HVAC, energiemeting en koeltechniek heb je alleen de eerste groep nodig.
De vier register types en hun function codes
Modbus organiseert geheugen in vier register types. Elke type heeft één leescode en, als het type schrijfbaar is, twee schrijfcodes (één voor één stuk, één voor meerdere). Negen function codes mappen op dit raster:
Coils zijn 1 bit waarden die je kunt lezen en schrijven. Denk aan de status van een relais of een digitale uitgang. Read coils gebruikt 0x01, write single coil 0x05, write multiple coils 0x0F.
Discrete inputs zijn 1 bit waarden die alleen leesbaar zijn. Een ingang van een drukschakelaar of een eindeloopschakelaar valt hieronder. Read discrete inputs gebruikt 0x02. Een function code om hierin te schrijven bestaat niet, want het is per definitie een input.
Holding registers zijn 16 bit waarden die je kunt lezen en schrijven. Hier zit het meeste werk in HVAC en koeltechniek: setpoints, configuratie waarden, modus selectie. Read holding registers gebruikt 0x03, write single holding register 0x06, write multiple 0x10.
Input registers zijn 16 bit waarden die alleen leesbaar zijn. Meetwaarden zoals temperaturen, drukken, vermogens en energie totalen. Read input registers gebruikt 0x04. Net als bij discrete inputs is er geen schrijfcode.
In de praktijk gebruiken veel fabrikanten alleen holding registers, ook voor meetwaarden, omdat dat de toolchain simpeler maakt. Een Eastron SDM630 stopt bijvoorbeeld zowel configuratie als meetwaarden in holding registers (0x03), terwijl een Carel pCO koelregelaar wel het volledige onderscheid tussen holding en input registers respecteert.
De negen function codes die je echt nodig hebt
Onder de 19 publieke function codes in de Modbus spec zijn er negen die je dagelijks tegenkomt. De andere tien zijn vooral RTU bus diagnose (0x07, 0x08, 0x0B, 0x0C, 0x11) of file record operaties (0x14, 0x15) die in moderne installaties zelden voorbijkomen.
| Function code | Naam | Toepassing | Frequentie |
|---|---|---|---|
| 0x01 | Read Coils | Status van digitale uitgangen lezen | gemiddeld |
| 0x02 | Read Discrete Inputs | Status van digitale ingangen lezen | gemiddeld |
| 0x03 | Read Holding Registers | Setpoints, configuratie, meetwaarden | heel hoog |
| 0x04 | Read Input Registers | Read-only meetwaarden | hoog |
| 0x05 | Write Single Coil | Eén relais aan of uit | gemiddeld |
| 0x06 | Write Single Holding Register | Eén setpoint of configuratie waarde | hoog |
| 0x0F | Write Multiple Coils | Meerdere relais in één frame | laag |
| 0x10 | Write Multiple Holding Registers | Setpoint blokken atomair schrijven | hoog |
| 0x17 | Read/Write Multiple Registers | Lezen plus schrijven in één transactie | laag |
Function codes 0x03 en 0x10 zien je het vaakst. 0x03 omdat het de generieke "lees data van dit apparaat" call is, 0x10 omdat alle moderne integratie tools (Home Assistant, Node-RED, PLC's) FC 16 prefereren boven FC 06, ook voor één register, omdat het programmeer model simpeler is.
Function code 0x03 in detail: lezen van holding registers
Function code 0x03 is veruit de meest gebruikte code in een installatie. Een leesverzoek naar holding registers bestaat uit zes bytes data (na het slave adres):
| Byte positie | Veld | Voorbeeld waarde |
|---|---|---|
| 1 | Slave adres | 0x01 |
| 2 | Function code | 0x03 |
| 3 tot 4 | Start register adres | 0x0000 (= register 0) |
| 5 tot 6 | Aantal registers | 0x000A (= 10 registers) |
| 7 tot 8 | CRC-16 | (berekend over bytes 1 tot 6) |
Een concreet voorbeeld: master vraagt slave 1 om de eerste 10 holding registers (0 tot 9):
01 03 00 00 00 0A C5 CD
De slave antwoordt met het slave adres, dezelfde function code, één byte met de byte count (aantal data bytes, 2x het aantal registers), de register waarden, en de CRC:
01 03 14 00 64 00 C8 01 2C ... C5 7B
Bytes 1 tot 3 zijn header: slave adres 0x01, function code 0x03, byte count 0x14 (= 20 bytes data, 10 registers x 2). Daarna komen 20 data bytes met de waarden, gevolgd door 2 bytes CRC.
Exception responses: wat een 0x83 in een log betekent
Wanneer een slave een verzoek niet kan uitvoeren, antwoordt hij niet met een nieuwe function code, maar met dezelfde function code waarbij bit 7 (MSB) op 1 staat. Function code 0x03 (read holding registers) wordt in een exception response dus 0x83. 0x10 (write multiple) wordt 0x90. Bit 7 zetten betekent OR met 0x80 (binair 1000 0000).
Na de exception function code volgt één byte exception code die zegt WAAROM het verzoek faalde. De volledige exception response is dus altijd vijf bytes (RTU): slave adres, exception function code, exception code, en 2 bytes CRC. Bij Modbus TCP wordt het zeven bytes na de MBAP header.
De Modbus Application Protocol Specification V1.1b3, sectie 7, definieert negen standaard exception codes:
| Exception code | Naam | Wat het betekent in de praktijk |
|---|---|---|
| 0x01 | Illegal Function | Slave ondersteunt deze FC niet (probeer 0x10 in plaats van 0x06) |
| 0x02 | Illegal Data Address | Adres bestaat niet op deze slave (off-by-one tussen HMI en wire) |
| 0x03 | Illegal Data Value | Waarde of aantal registers buiten range (te veel registers in één keer) |
| 0x04 | Slave Device Failure | Hardware probleem in slave (sensor stuk, geheugen corrupt) |
| 0x05 | Acknowledge | Slave verwerkt het, vraag later opnieuw met poll status |
| 0x06 | Slave Device Busy | Slave staat in self test of firmware update, wacht en probeer opnieuw |
| 0x08 | Memory Parity Error | File record geheugen fout (zelden in HVAC) |
| 0x0A | Gateway Path Unavailable | Modbus gateway kan de target slave niet bereiken (kabel los, slave uit) |
| 0x0B | Gateway Target Failed to Respond | Target slave reageert niet binnen timeout (verkeerde slave ID) |
Een concreet exception voorbeeld: master vraagt slave 1 om holding register 0x0064 (= 100) maar de slave heeft slechts 64 registers. De slave antwoordt:
01 83 02 C0 F1
Slave adres 0x01, function code 0x83 (= 0x03 + bit 7), exception code 0x02 (illegal data address), CRC 0xC0F1. Een logger die dit toont als "function code 131" is technisch niet fout, maar het is duidelijker om dit te lezen als "FC 0x03, exception code 0x02".
De 40001 valkuil: 1-based versus 0-based adressering
Een van de hardnekkigste problemen bij Modbus is het verschil tussen wat een HMI of PLC handleiding zegt en wat er op de wire gebeurt. Veel oude documentatie gebruikt 5-cijferige adressen met een prefix:
- 0xxxx voor coils (bijvoorbeeld 00001 voor de eerste coil)
- 1xxxx voor discrete inputs (10001 voor de eerste)
- 3xxxx voor input registers (30001 voor de eerste)
- 4xxxx voor holding registers (40001 voor de eerste)
Deze notatie komt uit de oorspronkelijke Modicon Modbus Protocol Reference Guide PI-MBUS-300 uit 1996 en is 1-based: 40001 verwijst naar het EERSTE holding register. Het Modbus protocol zelf gebruikt echter 0-based adressering op de wire: het eerste holding register zit op adres 0x0000.
Wanneer de fabrikant 40001 noemt, stuur je op de wire 0x0000. Trek altijd 1 af van de 4xxxx waarde voor het zet je hem in de request.
De praktische regel: zie je in een datasheet "40001 = nettospanning", dan zet je in je polling tool register adres 0 (niet 1, niet 40001) met function code 0x03. Een Eastron SDM630 datasheet bijvoorbeeld noemt voltage L1 op "30001" (input register notatie), wat op de wire adres 0x0000 wordt met function code 0x04.
FC 06 versus FC 16: wanneer kies je welke?
In het schrijven naar holding registers heb je twee opties: FC 06 (write single) of FC 16 (write multiple). Een terechte vraag is wanneer welke gebruikt:
Gebruik FC 06 als:
- Je één enkele waarde schrijft en de slave het ondersteunt
- Je een minimaal frame wilt (8 bytes total bij RTU)
- Je werkt met een legacy slave die alleen FC 06 kent (bijvoorbeeld oudere Carel pCO regelaars)
Gebruik FC 16 als:
- Je meerdere aangrenzende registers atomair wilt schrijven (bijvoorbeeld setpoint plus modus tegelijk)
- Je slave alleen FC 16 ondersteunt (bijvoorbeeld Daikin Altherma)
- Je consistent in je code wilt blijven (altijd FC 16, ook voor één register)
Het verschil is niet alleen aantal registers. FC 06 antwoordt met een echo van het verzoek (zelfde 8 bytes terug). FC 16 antwoordt met een korter frame: slave adres, FC, start adres, aantal registers, CRC. Voor een logger maakt dat het response patroon makkelijker te herkennen.
- 1
Bepaal welke FC de slave ondersteunt
Lees de datasheet of vraag bij de fabrikant uit welke schrijfcodes het apparaat accepteert. Een apparaat hoeft niet ALLE schrijfcodes te implementeren. Veel HVAC apparaten ondersteunen alleen 0x10.
- 2
Stel je polling tool in op die FC
In modpoll:
-m rtu -f 16voor write multiple. In Home Assistant Modbus:write_type: holdingsmetcount: 1triggert FC 16 voor één register. In een Python script: gebruikclient.write_registers(address, values)van pymodbus, nietwrite_register(address, value). - 3
Verifieer met een leesverzoek na het schrijven
Stuur direct na de write een FC 03 read op hetzelfde adres en vergelijk de gelezen waarde met wat je hebt geschreven. Slaagt de write zonder exception maar leest hij anders terug, dan zit er een interne herschaling in de slave (bijvoorbeeld factor 10, waardoor je 250 schrijft maar 25,0 wordt opgeslagen).
Veelvoorkomende installatie scenarios
Voor wie weleens een storing oplost, hier de drie meest voorkomende function code situaties:
Scenario 1: een Modbus poller toont "FC 131" of "FC 0x83". Dat is geen onbekende function code, dat is een exception response op FC 0x03. Lees byte 5 (de exception code) en kijk in de tabel hierboven. Meestal is dit 0x02 (illegal data address: adres bestaat niet) of 0x03 (illegal data value: te veel registers gevraagd).
Scenario 2: schrijf naar holding register werkt niet. Eerste check: is het echt een holding register en niet een input register? Input registers zijn read only, schrijfpogingen geven exception 0x01 (illegal function). Tweede check: ondersteunt de slave FC 06 of alleen FC 16? Switch zo nodig.
Scenario 3: lees retourneert "altijd nul". Vaak een adres offset probleem (zie de 40001 sectie hierboven). Stuur ook eens met function code 0x04 (input registers) in plaats van 0x03. Sommige fabrikanten zetten meetwaarden in input registers en alleen configuratie in holding registers.
Voor het bredere verhaal van Modbus RTU versus TCP en wanneer welke transport laag te kiezen, zie onze vergelijking RTU vs TCP. Voor specifieke warmtepomp scenarios met function codes in een installatie context, zie warmtepomp Modbus monitoring.
Veelgestelde vragen
Wat is het verschil tussen Modbus function code 0x03 en 0x04?
Function code 0x03 leest holding registers (read/write, 16-bit), function code 0x04 leest input registers (read only, 16-bit). Beide geven 16 bit waarden terug, maar holding registers zijn ook beschrijfbaar via 0x06 en 0x10. Veel fabrikanten kiezen ervoor om alleen holding registers te gebruiken, ook voor meetwaarden.
Hoeveel Modbus function codes zijn er in totaal?
De Modbus Application Protocol spec definieert 19 publieke function codes. Daarnaast zijn er twee user defined ranges (0x41 tot 0x48 en 0x64 tot 0x6E) voor fabrikant specifieke functies. In de praktijk dekken negen codes (0x01 tot 0x06, 0x0F, 0x10 en 0x17) ongeveer 99 procent van het verkeer.
Hoe lees ik een Modbus exception code?
Een exception response bestaat uit het slave adres, de oorspronkelijke function code met bit 7 op 1 (bijvoorbeeld 0x83 voor een FC 0x03 exception), en één byte exception code. De negen standaard exception codes lopen van 0x01 (illegal function) tot 0x0B (gateway target failed to respond). Lees byte 3 (na slave adres en exception FC) en zoek de betekenis op.
Waarom werkt mijn write naar register 40001 niet?
De 4xxxx notatie is 1-based en de protocol adressering op de wire is 0-based. Schrijf je naar 40001 op de wire, dan stuur je naar holding register 40000, dat meestal niet bestaat. De juiste mapping is 40001 in de HMI gelijk aan 0x0000 op de wire. Trek altijd 1 af voor je het in je tool zet, of laat de tool de conversie doen.
Wat is het maximum aantal registers in één Modbus request?
Voor function code 0x03 (read holding registers) is het maximum 125 registers per request. Voor 0x10 (write multiple registers) is het maximum 123 registers. Voor 0x01 en 0x02 (read coils en discrete inputs) is het maximum 2000 bits per request. Vraag je meer, dan komt exception code 0x03 (illegal data value) terug.
Volgende stappen
Function codes zijn de werktaal van Modbus: wie ze leest, leest het protocol. Combineer deze kennis met de Modbus RTU frame structuur om byte voor byte een trace te kunnen ontleden, en met de Modbus TCP frame structuur voor de moderne IP transport variant.
Wil je deze function codes niet handmatig in een script schrijven maar de data direct in de cloud zien? De ModbusCloud Gateway doet het polling werk voor je en exposeert de registers via een dashboard plus alerts. Boek een korte demo om te zien hoe dat in jouw fleet uitpakt.
Klaar om te beginnen?
Bestel de ModbusCloud Gateway en monitor je installaties binnen 5 minuten.
Bekijk de gatewayKlaar om te beginnen?
Bestel de ModbusCloud Gateway en monitor je installaties binnen 5 minuten.
Bekijk de gateway