In deze les

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.

Een float32: 230,5 V0x42C80x0000Hoog woordLaag woordHoog woord eerst (big-endian)0x42C80x0000Register nRegister n+1✓ leest 230,5Laag woord eerst (little-endian)0x00000x42C8✗ leest onzin
De standaard legt de volgorde binnen een register vast, tussen registers niet.

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:

RegisterWaardeBytes
n0x436643 66
n+10x800080 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:

VeldBitsBetekenis
teken0b0positief
exponentveld0b10000110134, min bias 127 geeft exponent 7
mantisse0b110011010000000000000006.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:

VolgordeNaam in toolsRegister nRegister n+1Als float32
ABCDbig-endian0x43660x8000230,5
BADCbyte swap0x66430x00802,3 x 10^23
CDABword swap0x80000x4366-2,4 x 10^-41
DCBAlittle-endian0x00800x66431,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.

Vier bytes uit twee holding registers43A66B80C00DWat je verwachteen netspanning, dus rond de230 VABCD, big-endian230,5BADC, byte swap2,3 x 10^23CDAB, word swap-2,4 x 10^-41DCBA, little-endian1,2 x 10^-38Alleen ABCD geeft een spanning die een meter ooit meet. Zet declient op big-endian.
Vier interpretaties, een plausibele uitkomst. Zo vind je de volgorde zonder jargon.

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:

VolgordeRegister nRegister n+1Als int32
ABCD0x00120xD6871.234.567
BADC0x12000x87D6302.024.662
CDAB0xD6870x0012-695.795.694
DCBA0x87D60x1200-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.

40200550×10^402011=5500 W
40200
ruwe waarde, actief vermogen
40201
schaalfactor, datatype sunssf
5500 W
werkelijke waarde
De echte waarde is de ruwe waarde maal tien tot de macht van het schaalfactorregister ernaast.

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.

TypeSentinel voor "niet ingevuld"
int16, int32 en sunssf0x8000, bij int32 0x80000000
uint160xFFFF
float320x7FC00000

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. 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 100 hierboven is de 1-gebaseerde telling van mbpoll; geeft jouw datasheet PDU-adressen, zet er dan -0 bij.

  2. 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. 3

    Lees dezelfde bytes twee keer als float

    Draai commando 2 en daarna commando 3. Dezelfde bytes, twee interpretaties, twee getallen.

  4. 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. 5

    Doe hetzelfde in Python

    Draai het fragment hieronder met word_order="big" en daarna met word_order="little". Je hoort dezelfde twee getallen terug te zien.

  6. 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 00 zijn 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, 0x7FC00000 of 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
Twee opeenvolgende registers bevatten 0x4366 en 0x8000. Wat lees je af als je ze als float32 interpreteert met het hoge woord eerst?
Je leest een netspanning uit twee registers en krijgt waarden rond de min 2,4 maal tien tot de macht min 41. Wat probeer je als eerste?
Je leest een kWh-stand van ongeveer 1.000.000 kWh uit als float32. Wat is het gevolg?
Waarom legt de Modbus-standaard de volgorde van twee registers in een 32-bits waarde niet vast?

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