Neu: Die KI-Firewall überwacht die gesamte Plattform und erklärt jeden Vorfall in einfachen Worten. So funktioniert es

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

Gelöst 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.
Akzeptierte Lösung♥ 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
Ansicht von 6 Beiträgen – 1 bis 6 (von insgesamt 6)
  • Du musst angemeldet sein, um auf dieses Thema antworten zu können.

Mitdiskutieren

Melde dich an, um Fragen zu stellen und zu beantworten, hilfreiche Beiträge mit „Gefällt mir“ zu markieren und die Antwort zu kennzeichnen, die dein Problem gelöst hat. Jeder Beitrag bringt Punkte und Stufen.

Teilen