我正在使用 modbus-tk 通过 RS-485 网络通过 Modbus RTU 与设备进行串行通信。

我想弄清楚如何使用函数 23, READ_WRITE_MULTIPLE_REGISTERS 。这是我第一次使用函数 23。这是我当前的实现:

response = modbus_master.execute(
    slave=SLAVE_NUM,
    function_code=cst.READ_WRITE_MULTIPLE_REGISTERS,
    starting_address=2,
    quantity_of_x=1,
    output_value=[1],
)

运行此命令时,出现以下错误:Modbus Error: Exception code = 1
我在 Wikipedia 上查找了这个异常代码,看到:



你觉得我的设备真的不支持这个功能码吗?还是我有语法问题/我误用了这个函数?

我已经把我的完整脚本放在下面。

完整代码示例

输入

#!/usr/bin/env python3


import time
from collections import namedtuple
from logging import Logger

from serial import Serial
from modbus_tk.modbus_rtu import RtuMaster
import modbus_tk.defines as cst  # cst = constants
from modbus_tk.utils import create_logger


PORT = "COM3"
SLAVE_NUM = 1
MODBUS_MASTER_TIMEOUT_SEC = 5.0

ModbusHoldingReg = namedtuple(
    "ModbusHoldingRegister", ["name", "address", "last_read_value", "to_write_value"]
)
shutdown_delay = ModbusHoldingReg("shutdown delay", 2, 0, None)  # sec

logger = create_logger(name="console")  # type: Logger

serial_ = Serial(PORT)
modbus_master = RtuMaster(serial_)
modbus_master.set_timeout(MODBUS_MASTER_TIMEOUT_SEC)
modbus_master.set_verbose(True)
# Sleep some time per [1]
# [1]: https://github.com/ljean/modbus-tk/issues/73#issuecomment-284800980
time.sleep(2.0)

# Read/write from/to multiple registers
response = modbus_master.execute(
    slave=SLAVE_NUM,
    function_code=cst.READ_WRITE_MULTIPLE_REGISTERS,
    starting_address=shutdown_delay.address,
    quantity_of_x=1,
    output_value=[1],
)  # type: tuple
print(response)

输出

2020-01-31 10:43:24,885 INFO    modbus_rtu.__init__     MainThread      RtuMaster COM3 is opened
2020-01-31 10:43:26,890 DEBUG   modbus.execute  MainThread      -> 1-23-0-2-0-1-0-23-0-1-2-0-1-55-131
2020-01-31 10:43:31,933 DEBUG   modbus.execute  MainThread      <- 1-151-1-143-240
---------------------------------------------------------------------------
ModbusError                               Traceback (most recent call last)
<ipython-input-1-f42d200d6c09> in <module>
     37     starting_address=shutdown_delay.address,
     38     quantity_of_x=1,
---> 39     output_value=[1],
     40 )  # type: tuple
     41 print(response)

c:\path\to\venv\lib\site-packages\modbus_tk\utils.py in new(*args, **kwargs)
     37             ret = fcn(*args, **kwargs)
     38         except Exception as excpt:
---> 39             raise excpt
     40         finally:
     41             if threadsafe:

c:\path\to\venv\lib\site-packages\modbus_tk\utils.py in new(*args, **kwargs)
     35             lock.acquire()
     36         try:
---> 37             ret = fcn(*args, **kwargs)
     38         except Exception as excpt:
     39             raise excpt

c:\path\to\venv\lib\site-packages\modbus_tk\modbus.py in execute(self, slave, function_code, starting_address, quantity_of_x, output_value, data_format, expected_length)
    312                 # the slave has returned an error
    313                 exception_code = byte_2
--> 314                 raise ModbusError(exception_code)
    315             else:
    316                 if is_read_function:

ModbusError: Modbus Error: Exception code = 1

设备细节
  • 设备:SST Sensing 的 OXY-LC-485
  • Modbus RTU,9600/8-N-1
  • User Guide(第 7.1.2.1 节包含一组输入寄存器)
  • 设备已插入我运行此 Python 脚本的 Windows 机器

  • 软件包

    我在 Windows 10 上使用 Python 3.6。

    pyserial==3.4
    modbus-tk==1.1.0
    

    最佳答案

    进一步来自@maxy 的回答; modbus spec 指出异常代码 1(非法功能)意味着:



    因此,在这种情况下,我会说设备不支持此命令。

    但是,鉴于另一个用户报告了此命令的问题,我认为值得检查编码:

    1- Slave ID
    23- Function Code
    0, 2- Read Starting Address
    0, 1- Quantity to Read
    0, 23- Write Starting Address
    0, 1 - Quantity to write
    2, Write Byte Count
    0,1, - Write Registers value
    55,131 - CRC (have not checked)
    

    除了一个异常(exception),这对我来说看起来是正确的;不清楚“写起始地址”从何而来(怀疑它与函数代码相同)。查看 source :

    pdu = struct.pack(
        ">BHHHHB",
        function_code, starting_address, quantity_of_x, defines.READ_WRITE_MULTIPLE_REGISTERS,
        len(output_value), byte_count
    )
    

    这在我看来是错误的(defines.READ_WRITE_MULTIPLE_REGISTERS 将始终为 23)。代码在 commit dcb0a2f115d7a9d63930c9b4466c4501039880a3 中改成这样;以前是:

    pdu = struct.pack(
        ">BHHHHB",
        function_code, starting_address, quantity_of_x, starting_addressW_FC23,
        len(output_value), byte_count
    )
    

    这对我来说更有意义(您需要一种方法来传递地址才能开始写入,而当前界面似乎没有提供此功能)。我在 github issue 中添加了一个注释。

    因此,总而言之,您的问题可能是由于设备造成的,但即使设备支持该命令,我也不认为它会因 modbus-tk 中的错误而起作用。

    关于python - modbus-tk 用于 Modbus RTU,读/写多个寄存器(fn 代码 23),返回异常代码 1,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60013544/

    10-11 08:34