我正在使用 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
设备细节
9600/8-N-1
软件包
我在 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/