Pymodbus读/写浮点(REAL)

时间:2015-06-11 15:22:21

标签: python ethernet modbus

我的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()

2 个答案:

答案 0 :(得分:1)

没关系。我让它使用libmodbus C ++代替:

#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;
}

答案 1 :(得分:0)

TLDR:

使用:

Private Sub resert_button_Click(sender As Object, e As EventArgs) Handles resert_button.Click
        Dim client = New client_entry
        client.Show()
        Me.Close()
End Sub

而不是:

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

解释尝试:

此软件包的BinaryPayloadDecoder.fromRegisters参数在文档中进行了描述。

在这种情况下,我们应该注意:

  

byteorder - 每个单词的字节顺序

     

wordorder - 单词的结尾(当wordcount为&gt; = 2时)

我相信一个适合modbus寄存器的值(2个字节)byteorder总是必须是Endian.Big

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

对于Modbus TCP,必须始终是byteorder = Endian.Big,wordorder = Endian.Little,因为valuse的字节顺序由超过2个字节组成,在协议规范OPEN MODBUS/TCP SPECIFICATION(Appendix B. Data Encoding for non-word data)中准确指定。

对于valuse的Modbus RTU字节顺序,在协议规范Somehow described here中没有精确指定超过2个字节。

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

但是,还有其他可能性:

  • [4,3,2,1] - byteorder = Endian.Big,wordorder = Endian.Big
  • [3,4,1,2] - byteorder = Endian.Little,wordorder = Endian.Big
  • [1,2,3,4] - byteorder = Endian.Little,wordorder = Endian.Little