Novedad: el cortafuegos de IA supervisa toda la plataforma y explica cada incidente con palabras sencillas. Vea cómo funciona

Freezer at -12.5 C shows up as 65411 after going through my Modbus slave

Freezer at -12.5 C shows up as 65411 after going through my Modbus slave

Resuelto 5 5

Student, first Modbus project. Arduino Mega reads a freezer probe and acts as a Modbus RTU slave (ModbusRTUSlave library). I store the temperature times 10 in holding register 0 so I keep one decimal. A Raspberry Pi polls it with pymodbus and sends temp to Hermetry.

Positive temperatures are perfect: 4.2 C goes in as 42 and comes out as 4.2. But the freezer is below zero, and there I get nonsense. -12.5 C turns into 6541.1 in Hermetry. Raw register value on the Pi is 65411.

rr = client.read_holding_registers(0, count=1, slave=3)
temp = rr.registers[0] / 10      # 6541.1 ??

On the Arduino I write holdingRegisters[0] = temp * 10; where temp is a float. What am I doing wrong?

♥ 0

Maybe Modbus just doesn’t do negative numbers? Could you add 100 to everything and subtract it again later?

Ask me about 4–20 mA.
♥ 0

An offset works, people do it, but you don’t need it here. The number is fine, it’s the reading side.

♥ 0

Had the exact same thing in a lab last term with a fridge logger. Modbus registers are just 16 bits, they don’t know about signs. Your Arduino stores -125 as two’s complement, which is 0xFF83, and as an unsigned number that’s 65411. The Pi then reads it as unsigned.

So convert it back on the Pi:

raw = rr.registers[0]
if raw > 32767:          # top bit set means negative in int16
    raw -= 65536
temp = raw / 10           # -12.5

Or let pymodbus do it, the client has a helper for this (in 3.x):

temp = client.convert_from_registers(rr.registers, data_type=client.DATATYPE.INT16) / 10

On the Arduino side, cast before the register so rounding is explicit: holdingRegisters[0] = (uint16_t)(int16_t)lround(temp * 10);. With int16 x10 you have -3276.8 to 3276.7 C, plenty for a freezer.

If a gateway polls it instead of your script, set that register’s type to signed 16-bit in the gateway config and it does the same conversion.

Timestamps in UTC or it didn't happen.
Solución aceptada♥ 9

Same goes for 32-bit values split over two registers, then you also have to get the word order right. Fun times.

♥ 0

The raw -= 65536 fix works, Hermetry shows -12.5 now and the chart doesn’t jump to 6000 anymore. Yesterday’s 6541 points are still sitting in the history, but everything new is right lol. Thanks Aoife.

♥ 0
Viendo 6 entradas – de la 1 a la 6 (de un total de 6)
  • Debes estar registrado para responder a este debate.

Únete a la conversación

Inicia sesión para preguntar y responder, dar me gusta a las publicaciones útiles y marcar la respuesta que resolvió tu problema. Cada aportación suma puntos y niveles.

Compartir