Modbus设备4字节转32位无符号整数技术求助
Let's break this down clearly, since the original documentation lacks concrete byte-level examples. First, let's align with your sensor's setup: Register 2 is the low 16 bits, Register 3 is the high 16 bits of the 32-bit unsigned (u32) pressure value.
Core Conversion Formula
The final 32-bit unsigned pressure value (in Pa) is calculated as:
u32_pressure = (uint16_high) * 65536 + uint16_low
Where:
uint16_low: The unsigned 16-bit equivalent of Register 2's valueuint16_high: The unsigned 16-bit equivalent of Register 3's value
How to get uint16_low/uint16_high from signed 16-bit reads:
If your Modbus client reads registers as signed 16-bit integers (int16):
- If the register value is positive:
uint16_val = reg_value - If the register value is negative:
uint16_val = reg_value + 65536(since 2¹⁶ = 65536, this converts the two's complement negative value to its unsigned counterpart)
If your client reads registers directly as unsigned 16-bit integers (uint16), you can skip the sign conversion step and use the raw values directly.
Step-by-Step Verification with Your Documentation Example
Your docs use these values:
- Register 2 (low 16 bits) signed value:
-30072 - Register 3 (high 16 bits) signed value:
-65535
Let's apply the formula:
- Convert Register 2 to uint16:
-30072 + 65536 = 35464 - Convert Register 3 to uint16:
-65535 + 65536 = 1 - Calculate high 16 bit contribution:
1 * 65536 = 65536 - Merge values:
35464 + 65536 = 101000 Pa
This matches the result in your docs—perfect.
Concrete 4-Byte Example
Let's map this to actual 4-byte data (the raw bytes you'd receive over Modbus):
Each 16-bit register uses big-endian formatting per Modbus standards. So:
- Register 3 (high 16 bits) is
0x0001, which translates to bytes0x00followed by0x01 - Register 2 (low 16 bits) is
0x8A88, which translates to bytes0x8Afollowed by0x88
The full 4-byte sequence you'd receive is 0x00 0x01 0x8A 0x88. When read as signed 16-bit registers:
- Register 3 (
0x0001) →1(positive, no conversion needed) - Register 2 (
0x8A88) →-30072(two's complement for -30072), so convert to uint16:35464
Applying the formula gives the same 101000 Pa result.
Pseudocode for Implementation
Here's a simple function to handle the conversion, regardless of whether your register reads are signed or unsigned:
def modbus_regs_to_u32_pressure(reg2_value, reg3_value): # Convert signed int16 to uint16 if needed def to_uint16(val): return val if val >= 0 else val + 65536 uint16_low = to_uint16(reg2_value) uint16_high = to_uint16(reg3_value) return uint16_high * 65536 + uint16_low
Testing this with your example:
print(modbus_regs_to_u32_pressure(-30072, -65535)) # Output: 101000
内容的提问来源于stack exchange,提问作者Baptiste

