问题描述
使用: python3, pyModbusTCP, Linux 树莓派4, ViewMarq by Automation Direct
我有一个数字显示板,可以接收ModBusTCP ascii数据包。以下信息与我要作为测试邮件发送的信息类似。
我是python Modbus的新手,正在尝试使用pyModbus客户端通过端口502将数据发送到其411000的保持寄存器,我相信通过删除4可以将其发送给11000。我已经建立了一个简单的客户端脚本,与董事会沟通,但我必须对消息进行编码才能将其发送到寄存器。在PLC领域,这要简单得多,但这不是一个选择。
使用Windows应用程序填充开发板,如下检测到我的Wireshark modbus数据:
Ethernet II,Src: Dell_63:da:e2 (34:48:ed:63:da:e2),Dst: FACTSEng_06:6c:fc (60:52:d0:06:6c:fc)
Internet Protocol Version 4,Src: 169.254.108.210,Dst: 169.254.108.223
Transmission Control Protocol,Src Port: 55053,Dst Port: 502,Seq: 1,Ack: 1,Len: 85
Modbus/TCP
Transaction Identifier: 256
Protocol Identifier: 0
Length: 79
Unit Identifier: 1
Modbus
.001 0000 = Function Code: Write Multiple Registers (16)<nl>
Reference Number: 10999
Word Count: 36
Byte Count: 72
Register 10999 (UINT16): 18748
Register 11000 (UINT16): 8260
Register 11001 (UINT16): 12339
Register 11002 (UINT16): 15422
Register 11003 (UINT16): 19523
Register 11004 (UINT16): 15954
Register 11005 (UINT16): 22332
Register 11006 (UINT16): 20041
Register 11007 (UINT16): 12320
Register 11008 (UINT16): 12320
Register 11009 (UINT16): 12832
Register 11010 (UINT16): 14136
Register 11011 (UINT16): 13088
Register 11012 (UINT16): 15921
Register 11013 (UINT16): 20540
Register 11014 (UINT16): 21327
Register 11015 (UINT16): 12320
Register 11016 (UINT16): 12320
Register 11017 (UINT16): 15422
Register 11018 (UINT16): 19020
Register 11019 (UINT16): 15422
Register 11020 (UINT16): 19522
Register 11021 (UINT16): 20000
Register 11022 (UINT16): 15422
Register 11023 (UINT16): 21315
Register 11024 (UINT16): 12320
Register 11025 (UINT16): 15422
Register 11026 (UINT16): 21063
Register 11027 (UINT16): 15950
Register 11028 (UINT16): 21564
Register 11029 (UINT16): 21566
Register 11030 (UINT16): 29541
Register 11031 (UINT16): 15476
Register 11032 (UINT16): 21551
Register 11033 (UINT16): 3390
Register 11034 (UINT16): 52237
从这里开始,我对下一步该怎么办感到困惑。我试图读取那些寄存器地址,但在那里什么也没看到。
from pyModbusTCP.client import ModbusClient
client = ModbusClient('169.254.108.223',port=502)
client.open()
print(client.read_holding_registers(10999,100))
并收到...
[0,..... <all 100 zeros>]
有人可以帮助我了解我是否朝着正确的方向前进,下一步该怎么做?我正在尝试使其尽可能简单,感谢您的帮助。
谢谢。
更新:
提出建议后,我对文档进行了更深入的研究。显示器的文档中,执行完成后,这些寄存器会立即返回0。来自文档 *
c)假设以下情况,应检查字交换和字节交换: ViewMarq显示中的选择为关闭(默认)。 d)从站Modbus存储器的起始地址是命令块的位置 在ViewMarq显示中(400000 + 11000 = 411000)。 e)功能码应设置为16 –写多个寄存器。
我必须承认。我不知道如何编写有效载荷。我重写了代码,并尝试了有效负载构建方法。
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.compat import iteritems
from collections import OrderedDict
client = ModbusClient('169.254.108.223',port=502)
client.connect()
builder = BinaryPayloadBuilder(byteorder=Endian.Little,wordorder=Endian.Little)
builder.add_string("<ID 30><CLR>""$0D") #$0D is the termination code in the docs
payload = builder.build()
client.write_registers(10999,payload,skip_encode=True,unit=1)
这没有用。它运行了,但是董事会没有更新。建议非常受欢迎。
解决方法
这不是您问题的完整解决方案,仅是下一步的建议。
-
阅读显示器的文档。
- 也许命令缓冲区寄存器是只写的?
- 或者当显示器处理完命令后,您可能会读取全0?
-
尝试读取响应缓冲区寄存器。
-
将Wireshark日志中的数据转换为十六进制:
18748
=0x493c
->0x49
='I'
0x3c
='<'
-> little endian"<I"
8260
=0x2044
->0x20
=' '
0x44
='D'
-> little endian"D "
12339
=0x3033
->0x30
='0'
0x33
='3'
->小端"30"
这三个写入寄存器的值对应于"<ID 30"
等。
因此,每个Modbus寄存器似乎都以小尾数字节顺序对应于缓冲区的2个字节。
响应缓冲区很可能是相同的。
编辑:
如果您的程序无法运行,请将您的程序发送的数据与Windows应用程序发送的数据进行比较,例如使用Wireshark。