RaspberryPi 3 中的 Pymodbus

Pymodbus in RaspberryPi 3

我正在尝试通过 pymodbus 在 raspberrypi 3 中从 modbus 设备获取数据

from pymodbus.client.sync import ModbusSerialClient as ModbusClient

client = ModbusClient(method = 'rtu', port = '/dev/ttyUSB0', baudrate = 115200)
client.connect()

result = client.read_input_registers(0x3100,6,unit=1)
solarVoltage = float(result.registers[0] / 100.0)
solarCurrent = float(result.registers[1] / 100.0)
batteryVoltage = float(result.registers[4] / 100.0)
chargeCurrent = float(result.registers[5] / 100.0)

# Do something with the data

client.close()

上面的代码运行良好。但是我想从下面给出的信息中得到一些信息

例如我正在尝试这样的事情

result = client.read_input_registers(0x3200,unit=1)

但是当我调用 result.registers 时,它显示的输出是 0 但我想获得 D0 到 D15 的值。 我怎样才能做到这一点?谢谢

我认为您缺少要读取的寄存器数量的值。我猜你想读两个寄存器。所以命令是

result = client.read_input_registers(0x3200, 2, unit=1)

文档中的描述告诉您如何解释您的值的每一位。
pymodbus's read_input_registers() returns a units16 (unsigned int 2 bytes) 每个寄存器(见official documentation), 这意味着它可以是 0 到 65535 之间的值。

result = client.read_input_registers(0x3200, 2, unit=1)
value1 = result.registers[0] # 33059
value2 = result.registers[1] # 9359

这些值可以转换为二进制值:

print format(value1, '016b') # 1000000100100011
print format(value2, '016b') # 0010010010001111

这些位中的每一位都可以从 0 到 15(从右到左)进行索引,然后我们可以按照文档中的描述拆分它们:

value1 D3-D0: 0011
Value1 D7-D4: 0010
Value1 D8: 1
Value1 D15: 1

对于位的每个子集,文档为我们提供了一个十六进制值的数字,并且十六进制值中的每个数字都可以转换为二进制:

D3-D0:
00H (bin: 0000) Normal
01H (bin: 0001) Overvolt
02H (bin: 0010) Undervolt
03H (bin: 0011) Low Volt Disconnect
04H (bin: 0100) OverTemp
and same for other sets...

如果集合只包含一位,我们考虑 True(1)/False(0) 行为。

这个值和我们的设置比较,我们了解到33059意味着:低压断开,低温,电池内阻异常,额定电压错误识别(灾难!)或者在您的情况下,0 表示正常、正常、正常、正确识别额定电压。

如果我们把同样的套用到value2(9359),我们就会明白:

1 D0----|---Standby
1 D1----|---Fault
1 D2----|---|---Equalization
1 D3----|---|
0 D4----|---ok
0 D5----|---//
0 D6----|---//
1 D7----|---The load is short
0 D8----|---ok
0 D9----|---ok
1 D10---|---Input is over current
0 D11---|---ok
0 D12---|---ok
1 D13---|---Charging MOSFET is short
0 D14---|---|---Normal
0 D15---|---|

显然你不想手工完成所有这些:即使有很多方法可以对这项工作进行编程,我还是建议你使用 bitmask:

# Define each mask as a tuple with all the bit at 1 and distance from the right:
D3_D0_mask = (0b1111, 0)
D7_D4_mask = (0b1111, 4)
D8_mask = (0b1, 8)
D15_mask = (0b1, 15)
# compare each mask to the value, after shifting to the right position:
print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 4 # False, Fault
print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 3 # True, Low Volt Disconnect
print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 2 # False, Under Volt
print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 1 # False, Overvolt
print D3_D0_mask[0]&(value1>>D3_D0_mask[1]) == 0 # False, Normal

print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 2 # True, Low Temp
print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 1 # False, Over Temp
print D7_D4_mask[0]&(value1>>D7_D4_mask[1]) == 0 # False, Normal

print D8_mask[0]&(value1>>D8_mask[1]) == 1 # True, Battery internal resistance abnormal

print D15_mask[0]&(value1>>D15_mask[1]) == 1 # True, Wrong identification for rated voltage

这段代码的优化应该是显而易见的。
如您所见,无论如何,我们得到了预期的输出。