In deze les

Wat deze les behandelt

  • FC05, FC06, FC15 en FC16, met de grens van 1968 coils en 123 registers
  • Waarom FC05 alleen de waarden 0xFF00 en 0x0000 accepteert
  • De routine die de oude waarde bewaart, en wat een echo niet bewijst

Lees eerst: Exception codes lezen en de juiste function code kiezen, Een Modbus registerkaart lezen zonder gokken

Naar een Modbus register schrijven is de enige handeling in dit protocol die iets kan stukmaken: een leesverzoek laat het apparaat precies zoals het was, een schrijfactie verandert de toestand van een installatie die op dat moment draait. Modbus kent geen ongedaan maken. Na deze les kies je bewust tussen FC05, FC06, FC15 en FC16, weet je wat een echo wel en niet bewijst, en volg je een routine die elke schrijfactie terugdraaibaar houdt.

Wat er misgaat als je zomaar schrijft

Het apparaat vraagt niet of je het zeker weet. Een laadpaal die zijn stroomlimiet in een holding register bijhoudt neemt jouw waarde net zo gehoorzaam aan als die van zijn eigen lastbalancering. Modbus kent geen gebruikers, geen rechten en geen logboek.

Daar komt bij dat lezen en schrijven vlak naast elkaar liggen. Bij mbpoll is het verschil precies een getal achter de poortnaam: staat het er niet, dan lees je, staat het er wel, dan schrijf je. Welke function code bij welk datablok hoort, staat in de referentie van alle Modbus function codes; deze les gaat over de vraag daarna.

Welke function code hoort bij welke schrijfactie?

Twee vragen bepalen het antwoord: schrijf je een bit of een register, en schrijf je er een of meer. Neem het spec-voorbeeld dat de waarde 3 schrijft naar het holding register dat op de datasheet register 2 heet (1-gebaseerd), dus naar PDU-adres 0x0001:

01 06 00 01 00 03 98 0B
ByteWaardeBetekenis
101serveradres
206function code FC06, write single register
3 en 400 01PDU-adres 1, op de datasheet register 2
5 en 600 03de waarde die je schrijft, decimaal 3
7 en 898 0BCRC-16, low byte eerst

Vier function codes doen het dagelijkse schrijfwerk, en hun grenzen volgen uit de maximale PDU van 253 bytes. FC05 zet een enkele coil, FC06 een enkel holding register met een waarde tussen 0x0000 en 0xFFFF, FC15 tot 1968 coils en FC16 tot 123 holding registers per verzoek. Discrete inputs en input registers ontbreken omdat ze per definitie alleen leesbaar zijn: schrijven daarheen levert exception 01 of 02 op.

ActieFunction codeEffect op het apparaatRisicoRegisters lezenFC03 en FC04Geen. Het apparaat verandertniet van toestand.laagEen coil ofregister schrijvenFC05 en FC06Een setpoint verspringt. Je kuntde oude waarde terugschrijven.Een blok registersschrijvenFC15 en FC16Tot 123 registers in eenverzoek. Bij een timeout weetje niet of het is uitgevoerd.Broadcast naar adres 0FC06 of FC16 opserveradres 0Elk apparaat op het segment voerthet uit en niemand bevestigt.hoog
Het risico loopt op terwijl de bevestiging juist terugloopt. Weet op welke trede je staat voordat je een setpoint aanraakt.

Waarom FC05 alleen twee waarden accepteert

Omdat de standaard hier geen getal verwacht maar een van twee vaste constanten. 0xFF00 betekent aan, 0x0000 betekent uit, en de spec zegt er letterlijk bij dat alle andere waarden ongeldig zijn en de uitgang niet beïnvloeden. Het spec-voorbeeld zet een coil aan op PDU-adres 0x00AC:

01 05 00 AC FF 00 4C 1B

Verander daar nu een ding aan: zet 00 01 in het waardeveld, omdat 1 toch aan betekent. De PDU wordt 05 00 AC 00 01, en het antwoord is geen echo maar twee bytes:

85 03

0x85 is 0x05 plus 0x80, de vaste opslag die van elke function code een exception maakt, en 03 is de exception code die in het Engels illegal data value heet. De coil staat daarna nog precies zoals hij stond.

Exception codes en waar je gaat zoekenFout in jouw verzoekHet apparaat leeft en antwoordt netjes. Corrigeer je adres, je functioncode of je waarde.01Illegal function02Illegal data address03Illegal data valueProbleem in het apparaatJe verzoek klopt, maar het apparaat kan het nu niet uitvoeren. Kijk inhet apparaat zelf.04Server device failure05Acknowledge06Server device busy08Memory parity errorProbleem in de gatewayDit antwoord komt van de gateway, niet van het eindapparaat erachter.0AGateway path unavailable0BGateway target device failed to respond
Een exception op een schrijfactie is goed nieuws: het apparaat antwoordt en heeft niets uitgevoerd.

Het antwoord op een schrijfactie lezen

FC05 en FC06 sturen je eigen verzoek terug, FC15 en FC16 sturen alleen het startadres en het aantal terug. Op het FC06-frame uit de tweede sectie antwoordt de server dus met exact dezelfde acht bytes:

01 06 00 01 00 03 98 0B

Dat is de regel en niet het toeval van dit voorbeeld: de standaard omschrijft de normale respons op FC05 en FC06 als een echo van het verzoek, teruggestuurd nadat de waarde geschreven is. Bij FC15 en FC16 zou een echo het hele datablok herhalen, dus daar bevestigt de server alleen wat hij waar heeft weggezet. Gaat er iets mis, dan komt in alle vier de gevallen de function code plus 0x80 terug met 1 byte exception code erachter.

En dan het punt dat in de praktijk de meeste tijd kost: een echo bewijst dat de waarde in het register staat, niet dat het apparaat er iets mee doet. Veel apparaten hebben een aparte modusinstelling, een bevestigingsregister of een herstart nodig voordat een setpoint meetelt. Lees dus altijd terug en controleer het effect.

Een blok schrijven zonder halve toestanden

Drie losse FC06-acties zijn drie verzoeken met twee momenten ertussen waarop het apparaat een deel van je nieuwe instelling heeft en een deel van de oude. FC16 haalt die tussenmomenten weg. Dit spec-voorbeeld schrijft twee registers vanaf datasheetnummer 2 (PDU-adres 0x0001) met de waarden 0x000A en 0x0102:

01 10 00 01 00 02 04 00 0A 01 02 92 30

Het verschil met het FC06-frame zit in twee velden: na het startadres staat nu het aantal registers (00 02), en daarna een byte count (04) die altijd twee keer dat aantal is. Klopt die verhouding niet, dan antwoordt de server met exception 03 en gebeurt er niets. Het antwoord is kort: de PDU 10 00 01 00 02.

FC16 schrijft maximaal 123 registers per verzoek, minder dan de 125 die FC03 leest, omdat het verzoek zelf ook een startadres, een aantal en een byte count meedraagt. FC23 combineert schrijven en lezen in een enkel bericht, waarbij het schrijven volgens de standaard voor het lezen gaat: tot 121 schrijven en tot 125 lezen. En om een enkele bit om te zetten zonder de rest van het register aan te raken bestaat FC22, met een And_Mask en een Or_Mask.

De routine die je elke keer volgt

Vier stappen, en alleen de derde raakt het apparaat aan.

  1. Lees de oude waarde en schrijf hem op. Niet in je hoofd en niet in de scrollback van je terminal.
  2. Controleer de telling. Een datasheetnummer telt vanaf 1 en het adres op de draad vanaf 0, dus het PDU-adres is het datasheetnummer min 1. Naar het verkeerde adres schrijven kost meer dan van het verkeerde adres lezen.
  3. Schrijf de nieuwe waarde.
  4. Lees terug en controleer het effect, niet alleen het register.

Kies ook je moment. Pas je een setpoint aan terwijl een regeling actief stuurt, dan trekken jij en het apparaat aan hetzelfde register en verdwijnt je eigen waarde binnen enkele seconden. Of een register schrijfbaar is, staat in de R/W-kolom van de registerkaart; hoe je die leest staat in de les over het lezen van een registerkaart.

Wanneer je beter niet schrijft

Drie situaties waarin je de hand van de knop houdt. De eerste is broadcast op serveradres 0: elk apparaat op het segment voert de schrijfactie uit en niemand antwoordt, en daarom bestaat broadcast alleen bij schrijven. Je weet achteraf niet of het is aangekomen en niet welk apparaat het niet heeft uitgevoerd:

00 06 00 01 00 03 99 DA

De tweede is een register waarover de datasheet zwijgt. Fabrikanten leggen kalibratiewaarden en fabrieksinstellingen vaak in dezelfde adresruimte als de gewone setpoints, dus een adres dat niet in de tabel staat is geen leeg vakje maar onbekend terrein.

De derde is een apparaat dat elke schrijfactie meteen in niet-vluchtig geheugen vastlegt. Dat geheugen heeft een eindig aantal schrijfcycli, dus schrijven in een pollus van een seconde is geen monitoring maar slijtage. Automatiseer je vanuit Home Assistant met de Modbus integratie, zoek dan eerst op of het apparaat elke waarde vastlegt.

Veelgemaakte fouten

Schrijven zonder de oude waarde te noteren. Je verandert een setpoint, het apparaat gedraagt zich anders dan verwacht, en je kunt niet terug omdat niemand weet wat er stond. Lees eerst, noteer, en pas dan schrijven.

0x0001 sturen om een relais aan te zetten. FC05 kent alleen 0xFF00 en 0x0000. Je krijgt exception 03, de coil verandert niet, en omdat er wel een antwoord komt lijkt de bus in orde. Vervolgens ga je bekabeling controleren die niets mankeert.

Een echo voor bevestiging aanzien. FC05 en FC06 sturen je verzoek terug zodra de waarde is weggeschreven. Dat zegt niets over wat de applicatie in het apparaat ermee doet.

Broadcast gebruiken om tijd te winnen. Op serveradres 0 antwoordt niemand. Je weet niet of het bericht is aangekomen, je weet niet welk apparaat het niet heeft uitgevoerd, en je raakt in een keer alles wat aan de bus hangt. Schrijf per apparaat, ook als dat langer duurt.

Aan de slag

Je voert een keer een volledige schrijfroutine uit en lokt daarna bewust een fout uit. Zowel mbpoll als de pymodbus-simulator zijn gratis te gebruiken, ook zakelijk.

  1. 1

    Kies een register dat niets beweegt

    Zoek in de datasheet een register dat als schrijfbaar staat aangemerkt en dat niets aanstuurt wat draait of schakelt. Een displayinstelling is goed, een klepstand niet.

  2. 2

    Lees de oude waarde en noteer hem

    Draai het leescommando en schrijf de uitkomst op papier, niet alleen in je terminal.

    mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 20 -c 1 -1 /dev/ttyUSB0
    
  3. 3

    Schrijf de nieuwe waarde

    Hetzelfde commando met een waarde erachter is een schrijfactie.

    mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 20 /dev/ttyUSB0 1234
    
  4. 4

    Lees terug en controleer

    Draai het commando uit stap 2 opnieuw en kijk of er nu 1234 staat. Controleer daarna op het apparaat zelf of er iets veranderd is.

  5. 5

    Zet de oude waarde terug

    Gebruik het commando uit stap 3 met de genoteerde waarde en lees nog een keer terug.

  6. 6

    Lok een exception uit

    Stuur naar een coil bewust 0x0001 in plaats van 0xFF00 en noteer wat je terugkrijgt. Volgens de standaard is dat exception 03.

Zonder hardware. Doe stap 2 tot en met 6 tegen de pymodbus-simulator op poort 5020. Bouw met SimData en SimDevice een server met een schrijfbaar holding register, zoals in de les over oefenen met de simulator.

Verwacht resultaat: een waarde die je hebt veranderd en weer hebt teruggezet, met de oude waarde op papier, plus een exception die je zelf hebt uitgelokt.

Samenvatting

  • Lezen verandert niets aan een apparaat, schrijven wel, en Modbus kent geen gebruikers, geen rechten en geen ongedaan maken.
  • FC05 schrijft een coil, FC06 een holding register, FC15 tot 1968 coils en FC16 tot 123 registers in een enkel verzoek.
  • FC05 accepteert alleen 0xFF00 voor aan en 0x0000 voor uit, en elke andere waarde levert exception 03 op zonder dat de coil verandert.
  • FC05 en FC06 echoën je verzoek en FC15 en FC16 bevestigen adres en aantal, maar geen echo bewijst dat het apparaat de waarde ook gebruikt.
  • De routine is elke keer dezelfde: lees de oude waarde, noteer hem, schrijf, lees terug en controleer het effect.

Controleer jezelf

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

Vraag 1 van 4
Je stuurt met FC05 de waarde 0x0001 naar een coil om een relais aan te zetten. Wat gebeurt er?
Je moet drie samenhangende setpoints tegelijk aanpassen. Waarom gebruik je daarvoor FC16 en niet drie keer FC06?
Je schrijft een nieuwe waarde, krijgt netjes een echo terug, maar het apparaat gedraagt zich niet anders. Wat is de meest waarschijnlijke verklaring?
Hoeveel registers kun je maximaal in een enkel FC16-verzoek schrijven, en waarom is dat minder dan bij lezen?

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