我使用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
我在维基百科上查找了这个异常代码,并看到:
在查询中接收的函数代码不被从服务器识别或允许。
你认为这是否意味着我的设备真的不支持这个功能代码?或者我有语法问题/误用这个函数吗?
我已经把我的完整剧本放在下面了。
全代码示例
输入
#!/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上使用Python3.6。
pyserial==3.4
modbus-tk==1.1.0发布于 2020-02-02 00:14:41
在@maxy的回答之后,modbus规范指出异常代码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)这在我看来是正确的,只有一个例外;不清楚“写开始地址”来自哪里(并且怀疑它与函数代码相同)。看着来源
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岁)。在提交dcb0a2f115d7a9d63930c9b4466c4501039880a3中,代码被更改为此;以前是:
pdu = struct.pack(
">BHHHHB",
function_code, starting_address, quantity_of_x, starting_addressW_FC23,
len(output_value), byte_count
)这对我来说更有意义(您需要一种传递地址的方式来开始编写,而当前的接口似乎没有提供此功能)。我已经在github问题中添加了一个注释。
因此,总之,您的问题可能是由于设备,但是即使设备支持命令,我也不认为它会因为modbus-tk中的错误而工作。
发布于 2020-02-01 22:28:12
调试输出包含以下跟踪:
-> 1-23-0-2-0-1-0-23-0-1-2-0-1-55-131
<- 1-151-1-143-240请考虑以下几点:
剩下的唯一可能是错误的地方是库将实际请求的编码搞砸了。我没有检查其他字节,但作为英国人的评论,在modbus-tk中可能存在编码错误。实现奴隶的人可能决定用“非法函数代码”来响应格式错误的请求。
在我看来,他们只是懒得去实现这个函数代码,这似乎也是合理的。例如,简便车甚至没有列出它。
发布于 2020-02-04 01:20:31
基于@maxy的回答的严谨性,然后基于@英国人的回答,我决定进一步调查。目标是确定根本原因是modbus-tk错误,还是我的设备不支持函数代码23。
在modbus-tk第121期中,OP提到pymodbus使用函数代码23,读写多个寄存器。
因此,我安装了pymodbus==2.3.0,然后给了它一个旋转。下面是我使用的代码:
输入
#!/usr/bin/env python3
import sys
import logging
from collections import namedtuple
from pymodbus.pdu import ModbusResponse, ExceptionResponse
from pymodbus.client.sync import ModbusSerialClient
from pymodbus.register_read_message import ReadWriteMultipleRegistersResponse
log = logging.getLogger()
log.addHandler(logging.StreamHandler(sys.stdout))
log.setLevel(logging.DEBUG)
ModbusHoldingReg = namedtuple(
"ModbusHoldingRegister", ["name", "address", "last_read_value", "to_write_value"]
)
sensor_mode = ModbusHoldingReg("sensor on, off, and standby enum", 0, None, None)
PORT = "COM3"
SLAVE_NUM = 1
BAUD_RATE = 9600
with ModbusSerialClient(
method="rtu", port=PORT, baudrate=BAUD_RATE, strict=False
) as modbus_client:
regs_to_write = [0, 1, 3]
response = modbus_client.readwrite_registers(
read_address=sensor_mode.address,
read_count=len(regs_to_write),
write_address=sensor_mode.address,
write_registers=regs_to_write,
unit=SLAVE_NUM,
) # type: ModbusResponse
if response.isError():
response: ExceptionResponse
print(
f"Exception! Original function code = {response.original_code}, "
f"exception_code = {response.exception_code}."
)
else:
response: ReadWriteMultipleRegistersResponse
print(f"Success! response.registers = {response.registers}.")输出
Current transaction state - IDLE
Running transaction 1
SEND: 0x1 0x17 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x3 0x6 0x0 0x0 0x0 0x1 0x0 0x3 0x5d 0xce
New Transaction state 'SENDING'
Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
RECV: 0x1 0x97 0x1 0x8f 0xf0
Getting Frame - 0x97 0x1
Factory Response[151]
Frame advanced, resetting header!!
Adding transaction 1
Getting transaction 1
Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Original function code = 23, exception code = 1.结论
可以看到,设备响应的异常代码1,Illegal Function。所以我认为这个设备不支持功能代码23。
如果我找到一个支持fn代码23的设备,我会回过头来。
https://stackoverflow.com/questions/60013544
复制相似问题