Pymodbus 读/写浮点(REAL)

问题描述 投票:0回答:3

我的 AB Micro820 PLC 中有 modbus 映射设置。我有一个 40001 的数组用于写入,一个 42001 的数组用于读取。两者都是 200 个元素和 REAL 类型(32 位浮点数)。我目前可以读写,所以我知道代码可以工作,只是不正确。这些值被读/写为非常小的值(即 4.58577478E-19)。有人能指出我正确的方向吗?

#!/usr/bin/env python

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.client.sync import ModbusTcpClient

import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.INFO)

ip_address = "192.168.2.101"

client = ModbusTcpClient(ip_address)
if client.connect():    # connection is OK
    # write float
    builder = BinaryPayloadBuilder(endian=Endian.Little)
    builder.add_32bit_float(77.77)
    payload = builder.build()
    result  = client.write_registers(1, payload, skip_encode=True)
    # read floats
    result  = client.read_holding_registers(2001, 4)
    decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)
    print "read_holding_registers: " + str(decoder.decode_32bit_float())

    client.close()
python ethernet modbus plc
3个回答
7
投票

总长:

用途:

decoder = BinaryPayloadDecoder.fromRegisters(result.registers, Endian.Big, wordorder=Endian.Little)

而不是:

decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little)

解释尝试:

文档中描述了此包的

BinaryPayloadDecoder.fromRegisters的参数。

遇到这种情况我们要注意:

byteorder – 每个单词的字节顺序

wordorder – 单词的字节序(当字数 >= 2 时)

我相信适合 modbus 寄存器(2 字节)字节顺序的值始终必须是 Endian.Big

字序类似于字节序,但用于 modbus 寄存器。

对于 Modbus TCP 始终必须是 byteorder=Endian.Big、wordorder=Endian.Little,因为由 2 个以上字节组成的值的字节顺序在协议规范中精确指定

开放 MODBUS/TCP 规范(附录 B. 数据)非文字数据的编码) .

对于 Modbus RTU 值的字节顺序,由超过 2 个字节组成的值在协议规范中未准确指定

此处有所描述

大多数实现采用 Modbus TCP 方法并将浮点数传输为 [2, 1, 4, 3] 字节。

但是,还有其他可能性:

    [4, 3, 2, 1] - 字节顺序=Endian.Big,字序=Endian.Big
  • [3, 4, 1, 2] - 字节顺序=Endian.Little,字序=Endian.Big
  • [1, 2, 3, 4] - 字节顺序=Endian.Little,字序=Endian.Little

1
投票
我让它与 C++ 中的

libmodbus 一起工作:

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <vector> #include <iostream> using namespace std; extern "C" // needed to integrate C code into C++ { #include "libmodbus/modbus.h" } int main (void) { modbus_t *ctx; uint16_t read_reg[64]; uint16_t write_float_holder[2]; uint16_t read_float_holder[2]; vector <float> write_reg = {77.77, 15.69, 42.78, 50153.33, -56.23}; int rc, start_element = 0, j = 0; float rc_f[10]; ctx = modbus_new_tcp("192.168.2.101", 502); // PLC IP address and default Modbus Port (502) if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } ///// Reading 402000 /// REAL array in PLC // array fills up right to left with hex: 0x[1][0] >> 0x4174 0x28f6 >> read_from_plc[0] = 15.26 if (1) { rc = modbus_read_registers(ctx, 2000, 8, read_reg); // (connection, start position, how many to read, what read values go into) if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } for (int i = 0; i < rc; i++) { printf("read_reg[%d]=%d (0x%x)\n", i, read_reg[i], read_reg[i]); } for (int i = 0; i < rc; i += 2) { read_float_holder[0] = read_reg[i]; read_float_holder[1] = read_reg[i + 1]; rc_f[j] = modbus_get_float(read_float_holder); printf("rc_f[%d]: %f\n", j, rc_f[j]); j++; } } ///// Writing 40000 /// REAL array in PLC if (1) { for (size_t i = 0; i < write_reg.size(); i++) // write two registers (32-bit float) at a time { modbus_set_float(write_reg[i], write_float_holder); // set float to hexadecimal rc = modbus_write_registers(ctx, start_element, 2, write_float_holder); start_element += 2; cout << "modbus_set_float: writing write_reg[" << i << "] = " << write_reg[i] << "\trc: " << rc << endl; } } // close connection and free memory modbus_close(ctx); modbus_free(ctx); return 0; }
    

0
投票
这是使用 pymodbus 读取浮点数的最简单方法。

from pymodbus.client.sync import ModbusTcpClient from pymodbus.payload import BinaryPayloadDecoder from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadBuilder result = client.read_holding_registers(register,count=2,unit=1).registers decoder = BinaryPayloadDecoder.fromRegisters(result,byteorder= Endian.Big, wordorder=Endian.Little) value = decoder.decode_32bit_float() print(value)
    
© www.soinside.com 2019 - 2024. All rights reserved.