Yeni: Yapay zekâ güvenlik duvarı tüm platformu izliyor ve her olayı sade bir dille açıklıyor. Nasıl çalıştığını görün

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

Çözüldü 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.
Kabul edilen çözüm♥ 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
6 yazı görüntüleniyor – 1 ile 6 arası (toplam 6)
  • Bu konuyu yanıtlamak için giriş yapmış olmalısınız.

Sohbete katılın

Soru sormak ve yanıtlamak, yararlı gönderileri beğenmek ve sorununuzu çözen yanıtı işaretlemek için oturum açın. Her katkı puan ve seviye kazandırır.

Paylaş