Bekijk alle lessen
Deel 1
Basis
Deel 2
Modbus RTU
- Les 5RS485 uitgelegd: A, B, common en terminatie20 min
- Les 6Baudrate en pariteit: waarom 8E1 de default is16 min
- Les 7Het Modbus RTU frame byte voor byte, plus CRC18 min
- Les 8Meerdere Modbus apparaten op een bus zetten16 min
- Les 9Je eerste Modbus apparaat uitlezen met mbpoll22 min
- Les 10Modbus RTU storing zoeken: symptoom en oorzaak20 min
Deel 3
Modbus TCP
Deel 4
Gevorderd
- Les 16Veilig naar een Modbus apparaat schrijven18 min
- Les 17Word order en float: dezelfde bytes, andere waarde22 min
- Les 18Pollinterval en busbelasting zelf berekenen18 min
- Les 19Modbus beveiligen: het protocol doet het niet16 min
- Les 20Modbus integreren: PLC, Home Assistant of cloud20 min
- Les 21Modbus checklist voor oplevering en overdracht18 min
Word order en float: dezelfde bytes, andere waarde
Modbus word order bepaalt of je 230,5 of pure onzin leest. Leer de vier permutaties, IEEE 754 floats, schaalfactoren en sentinelwaarden snel te herkennen.
Wat deze les behandelt
- De vier permutaties waarin twee registers een float32 vormen
- De plausibiliteitstoets die de juiste woordvolgorde aanwijst
- Sentinelwaarden, en waarom een energieteller niet in een float32 past
Lees eerst: Modbus adressering: van 40001 naar het adres, Een Modbus registerkaart lezen zonder gokken
Word order is de afspraak in welke volgorde twee registers samen een 32-bits getal vormen, en de Modbus-standaard laat die afspraak open. Dezelfde vier bytes leveren daardoor 230,5 op, of een getal met veertig nullen achter de komma. Na deze les haal je een float32 uit twee registers, ken je de vier permutaties, en vind je de juiste met een toets die je aan de meetwaarde zelf doet.
Wat de standaard wel en niet vastlegt
Binnen een register ligt de bytevolgorde vast, tussen twee registers niet. De standaard is daar kort over: van de 16-bits waarde 0x1234 gaat eerst byte 0x12 over de lijn en daarna 0x34, de meest significante byte eerst. Dat heet big-endian en het geldt voor elk register dat je leest of schrijft.
Boven de 16 bits houdt het op. Het Modbus-datamodel kent vier blokken met bits en 16-bits woorden, meer niet. Een float32, een uint32 of een int32 bestaat in Modbus niet als type. Wie er een leest, plakt twee registers aan elkaar volgens een afspraak van de fabrikant, niet volgens de standaard. Die afspraak heet word order, in het Nederlands woordvolgorde, en in datasheets kom je hem ook tegen als register order.
Er is precies een uitzondering op big-endian in het hele protocol: de CRC in een Modbus RTU-frame gaat low byte eerst. Hoe je uit een datasheetregel de function code, de telling en het datatype haalt, staat in de les over een registerkaart lezen.
Een float32 uit twee registers halen
Je leest twee opeenvolgende holding registers en krijgt dit terug:
| Register | Waarde | Bytes |
|---|---|---|
| n | 0x4366 | 43 66 |
| n+1 | 0x8000 | 80 00 |
Achter elkaar gezet zijn dat de vier bytes 43 66 80 00, oftewel 0x43668000. Uitgeklapt naar de drie velden van een IEEE 754 float32:
| Veld | Bits | Betekenis |
|---|---|---|
| teken | 0b0 | positief |
| exponentveld | 0b10000110 | 134, min bias 127 geeft exponent 7 |
| mantisse | 0b11001101000000000000000 | 6.717.440 van 8.388.608 |
Invullen geeft (1 + 6717440 / 8388608) x 2^7, dus 1,80078125 x 128 = 230,5. Een netspanning.
Nu pas de regel, kort: een float32 is 1 tekenbit, 8 exponentbits en 23 mantissebits, met exponent bias 127. Twee registers leveren de vier bytes, en de volgorde waarin je die twee registers aan elkaar plakt bepaalt de uitkomst.
Zelfde oefening, een punt anders. Een energiestand van 1.234.567 Wh is 0x0012D687, dus registers 0x0012 en 0xD687. Draai die twee om en je leest 0xD687 gevolgd door 0x0012, wat als int32 min 695.795.694 is. Bij een float valt zo'n omdraaiing meteen op, bij een geheel getal niet.
De vier permutaties, en hoe ze heten
De vier bytes heten in volgorde A, B, C en D, dus A is 0x43, B is 0x66, C is 0x80 en D is 0x00. Daaruit komen de vier afkortingen. Hier met de bytes van 230,5:
| Volgorde | Naam in tools | Register n | Register n+1 | Als float32 |
|---|---|---|---|---|
| ABCD | big-endian | 0x4366 | 0x8000 | 230,5 |
| BADC | byte swap | 0x6643 | 0x0080 | 2,3 x 10^23 |
| CDAB | word swap | 0x8000 | 0x4366 | -2,4 x 10^-41 |
| DCBA | little-endian | 0x0080 | 0x6643 | 1,2 x 10^-38 |
In de Modbus-integratie van Home Assistant heten dezelfde vier: geen swap is ABCD, swap: byte is BADC, swap: word is CDAB en swap: word_byte is DCBA. Andere tools gebruiken weer andere namen, en dat is precies waarom je er niet op moet leunen.
De plausibiliteitstoets in plaats van jargon
Je hoeft geen enkele permutatienaam te onthouden om de juiste volgorde te vinden. Kies een grootheid waarvan je de orde van grootte kent, lees hem in alle vier de volgordes en houd de enige uitkomst over die een meter ooit meet.
Een netspanning, een netfrequentie rond de 50 Hz of een buitentemperatuur zijn geschikte proefgrootheden. Toets nooit op een teller. Bij een float32 valt een verkeerde volgorde meteen op, bij een int32 niet, en dezelfde 1.234.567 Wh uit de vorige paragraaf laat zien waarom:
| Volgorde | Register n | Register n+1 | Als int32 |
|---|---|---|---|
| ABCD | 0x0012 | 0xD687 | 1.234.567 |
| BADC | 0x1200 | 0x87D6 | 302.024.662 |
| CDAB | 0xD687 | 0x0012 | -695.795.694 |
| DCBA | 0x87D6 | 0x1200 | -2.016.013.824 |
Alle vier zien eruit als een meterstand die zou kunnen kloppen. Dat de volgorde per merk instelbaar is, is geen theorie: bij Eastron schrijf je de bekende float 2141,0 naar een parameter, en de meter leidt uit de ontvangen bytes zelf af hoe jouw client het doet.
Sommige tools doen die vergelijking voor je: ModbusCloud Diagnostics bepaalt in de Register Explorer automatisch welke byte order de plausibelste waarde oplevert. Bij een teller blijft het oordeel bij jou, want daar zien alle vier de volgordes er geloofwaardig uit.
Schaalfactoren die in een eigen register staan
Niet elke fabrikant zet een kommagetal in een float. SunSpec doet het anders: de meetwaarde is een geheel getal, en er staat een tweede register naast met de macht van tien. Dat register heeft datatype sunssf en een bereik van min 10 tot plus 10.
Bij een SMA-omvormer staat op datasheetnummer 40200 het actieve vermogen en op datasheetnummer 40201 de bijbehorende schaalfactor. Ruw 550 met schaalfactor 1 is 5.500 W. Op datasheetnummer 40217 staat het DC-vermogen met schaalfactor 2, dus met een resolutie van 100 W: ruw 57 betekent 5.700 W, en wie de factor vergeet rapporteert 57 W op een string die 5,7 kW levert. En datasheetnummer 40219, de interne temperatuur, heeft helemaal geen schaalfactorregister. De regel "elke waarde heeft een schaalfactor" gaat dus niet op. Hoe zo'n kaart is opgebouwd staat in de uitleg over SunSpec bij Modbus.
Wanneer een getal geen meting is
Een register dat niet is ingevuld levert geen leeg veld op maar een vaste waarde, een sentinel. Filter die eruit voordat je schaalt en voordat je alarmeert.
| Type | Sentinel voor "niet ingevuld" |
|---|---|
| int16, int32 en sunssf | 0x8000, bij int32 0x80000000 |
| uint16 | 0xFFFF |
| float32 | 0x7FC00000 |
Daikin doet het met leesbare decimale waarden: 32767 betekent dat het apparaat dit register niet kent, 32766 dat het in deze configuratie niet bestaat, en 32765 dat de waarde nog niet geladen is. Een Daikin-temperatuurregister met 32767 is dus geen 327,67 graden.
Waarom je een energieteller niet in een float stopt
Een float32 heeft 24 bits effectieve precisie. Boven 2^24 = 16.777.216 kan hij niet meer elk heel getal weergeven: 16.777.216 en 16.777.217 zijn in float32 exact hetzelfde getal, en de stapgrootte wordt 2.
Voor een teller in Wh is dat einde verhaal boven 16,78 MWh. Voor een teller in kWh gaat het veel langer goed: bij 1.000.000 kWh is de kleinste stap 0,0625 kWh. Dat verklaart ook waarom meters hun energie in kWh publiceren en niet in Wh. Wil je een teller die blijft kloppen, gebruik dan uint32 of uint64 met een schaalfactor. Lees hem dan wel als unsigned: een uint32-teller in Wh passeert 2.147.483.648 Wh bij ongeveer 2,15 GWh, en wie hem signed leest ziet zijn teller op dat moment negatief worden.
Veelgemaakte fouten
Byte order en word order door elkaar halen. Iemand draait in de tool aan "byte swap" terwijl "word swap" nodig is. De waarde blijft onzin en de conclusie wordt "dit apparaat doet raar". Binnen een register ligt de volgorde vast, tussen registers niet, dus alleen de tweede knop doet hier iets.
Op jargon vertrouwen in plaats van op de meting. Twee tools noemen dezelfde permutatie anders, dus wie de naam uit de ene handleiding in de andere tool invult, komt op de verkeerde stand uit. De plausibiliteitstoets werkt altijd, de terminologie niet.
Een sentinel in een grafiek zetten. 0x7FC00000 en 0x80000000 betekenen "geen waarde". Wie ze meeschrijft, krijgt 's nachts een piek van gigawatts en daarna een alarm dat nergens over gaat. Filter op sentinel in de mapping, niet in de grafiek.
Een kWh-teller in een float32 lezen. Boven 16.777.216 raak je precisie kwijt. Bij een miljoen kWh is de kleinste stap 0,0625 kWh, en dan lopen kleine verbruiksverschillen niet meer mee in je rapportage.
Aan de slag
Je leest twee registers drie keer en beslist zelf welke uitkomst kan kloppen. Zowel mbpoll als pymodbus is gratis te gebruiken, ook zakelijk.
#1. de ruwe registers, als hex
mbpoll -m rtu -a 1 -b 9600 -P none -t 4:hex -r 100 -c 2 -1 /dev/ttyUSB0
#2. dezelfde registers als float32
mbpoll -m rtu -a 1 -b 9600 -P none -t 4:float -r 100 -c 2 -1 /dev/ttyUSB0
#3. dezelfde registers, andere woordvolgorde
mbpoll -m rtu -a 1 -b 9600 -P none -t 4:float -B -r 100 -c 2 -1 /dev/ttyUSB0
- 1
Kies twee registers die samen een float vormen
Neem een grootheid waarvan je de orde van grootte kent, bij voorkeur een spanning of een frequentie. De
-r 100hierboven is de 1-gebaseerde telling van mbpoll; geeft jouw datasheet PDU-adressen, zet er dan-0bij. - 2
Lees ze eerst als hex
Draai commando 1 en noteer de twee registerwaarden. Dit zijn de vier bytes waar alles om draait, en die veranderen niet meer.
- 3
Lees dezelfde bytes twee keer als float
Draai commando 2 en daarna commando 3. Dezelfde bytes, twee interpretaties, twee getallen.
- 4
Kies op plausibiliteit
Zet beide uitkomsten naast elkaar. Een van de twee ligt in de buurt van wat je verwacht, de andere is absurd klein of absurd groot. De eerste is jouw woordvolgorde.
- 5
Doe hetzelfde in Python
Draai het fragment hieronder met
word_order="big"en daarna metword_order="little". Je hoort dezelfde twee getallen terug te zien. - 6
Leg de combinatie vast
Noteer merk, model, datatype en woordvolgorde in je projectdossier. Voor dit apparaat hoef je hem nooit meer te zoeken.
value = client.convert_from_registers(
rr.registers, data_type=client.DATATYPE.FLOAT32, word_order="big"
)
Zonder hardware. Start de pymodbus-simulator, zoals in oefenen met de simulator, en vervang -m rtu -a 1 -b 9600 -P none door -m tcp -p 5020 en /dev/ttyUSB0 door -0 127.0.0.1, met -r 6. De -0 zet mbpoll op PDU-telling. Op PDU-adres 6 staat over twee registers een float32 rond de 404 die bij elke lezing oploopt. Probeer beide woordvolgordes en houd de reeks over die netjes oploopt.
Verwacht resultaat: twee interpretaties van dezelfde vier bytes, waarvan er precies een plausibel is, en een aantekening in je dossier.
Samenvatting
- Modbus legt de bytevolgorde binnen een register vast (big-endian), maar niet de volgorde van twee registers in een 32-bits waarde.
- De vier bytes
43 66 80 00zijn als float32 met het hoge woord eerst de waarde 230,5, en in de andere drie volgordes een getal dat geen enkele meter meet. - De namen ABCD, BADC, CDAB en DCBA helpen bij het instellen, maar de plausibiliteitstoets op een bekende grootheid vindt de juiste volgorde altijd.
- Een sentinel als
0x8000,0xFFFF,0x7FC00000of 32767 is geen meetwaarde, dus filter hem eruit voordat je schaalt of alarmeert. - Boven 16.777.216 kan een float32 niet elk heel getal meer weergeven, dus zet een grote energieteller in een uint32 of uint64 met een schaalfactor.
Controleer jezelf
Vier vragen over deze les. Je krijgt bij elk antwoord uitleg.
Vraag 1 van 4
Zelf zien hoe het werkt?
De ModbusCloud Gateway leest de apparaten uit deze cursus uit zonder dat je registers hoeft te programmeren.