Pymodbus 基本示例

Pymodbus Basic Example

我有一个简单的 modbus 设备 (Ebyte MA02-XACX0440),我正在尝试学习如何使用它。使用称为串行端口监视器 (www.serial-port-monitor.org) 的第三方 GUI,我能够或多或少地“偶然发现”打开和关闭离散输出所需的正确十六进制输入。我不明白这些单位、地址、线圈、寄存器等术语,以及它们与十六进制方面的关系。打破我认为我到目前为止所知道的(下面是将第一个离散输出'ON'转换的十六进制字符串):

0x20 0x05 0x00 0x00 0xFF 0x00 0x8A 0x8B

我知道 0x20 是十六进制的设备地址。 Ebyte设备的文档规定默认硬件地址是'31',第一个软件地址是'1'。如果我理解正确,那意味着我线上的第一个物理 modbus 设备的地址为“32”,如果我将其他 modbus 设备放在线上(RS485 或 TCP(?)),下一个设备将是'33'等等。

我知道下一个字节0x05是'write coil'.

我不知道'0x00'和'0x00'接下来的两个字节指的是什么。

接下来的两个字节基本上是 on/off,'0xFF00' 是 'ON' 和 0x0000 是 'OFF'。

最后两个字节只是 CRC 校验和。

到目前为止,我可以让我的 DO(离散输出)打开、打开并点亮 LED,作为一个简单的概念证明。现在,当我采用这种方法来使用 pymodbus 库(我的最终目标)时,事情似乎并不一致。

我可以使用 pymodbus REPL 连接到我的设备

pymodbus.console serial --baudrate 9600 --bytesize 8 --parity N --stopbits 1 --port /dev/cu.usbserial-AH01F4EN

我可以确认设备已连接:

    ----------------------------------------------------------------------------
__________          _____             .___  __________              .__
\______   \___.__. /     \   ____   __| _/  \______   \ ____ ______ |  |
 |     ___<   |  |/  \ /  \ /  _ \ / __ |    |       _// __ \____ \|  |
 |    |    \___  /    Y    (  <_> ) /_/ |    |    |   \  ___/|  |_> >  |__
 |____|    / ____\____|__  /\____/\____ | /\ |____|_  /\___  >   __/|____/
           \/            \/            \/ \/        \/     \/|__|
                                        v1.3.0 - [pymodbus, version 2.5.3]
----------------------------------------------------------------------------

> client.connect
true

然而,当我尝试 运行 之前使用串行监视器执行的相同命令时,我很难将十六进制值映射到 pymodbus 中的 'client.write_coil' 命令所期望的整数:

    > client.write_coil address=32 value=255 unit=1
{
    "original_function_code": "5 (0x5)",
    "error": "[Input/Output] No Response received from the remote unit/Unable to decode response"
}

地址是什么意思?这是 coil/register 地址还是设备地址?对于 'value',我输入了“255”,因为这会将所有位翻转为“1”,认为这会被视为 'ON',而值“0”将被关闭。我还尝试了“65280”,这是十进制的 0xFF00。单位是什么意思?我之前确定的值是“32”以针对线路上的特定设备吗?或者地址可能是'31'(这是硬件地址)然后单元地址是'1',使得整体'address' 32?

编辑:这显示在 client.write_coil 命令的 'help' 中,但仍然无法帮助我弄清楚如何将正确的部分放在正确的位置。我不知道 'coil offset' 是什么以及它与离散输出的关系。我没有看到任何映射到将被视为 'coil offset' 的十六进制字符串的内容。这是为那些可能知道如何正确形成请求的人提供的上下文。

我有时也会遇到这个错误,而且不一致。如果这是一个权限问题,人们会认为您每次都会得到它吗?我不认为改变指定文件的权限或 运行 具有根权限的 pymodbus 服务器是没有意义的。

    Unhandled exception in event loop:
  File "/usr/local/Cellar/python@3.9/3.9.7/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/input/vt100.py", line 170, in callback_wrapper
    callback()
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/application/application.py", line 708, in read_from_input
    self.key_processor.process_keys()
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/key_binding/key_processor.py", line 271, in process_keys
    self._process_coroutine.send(key_press)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/key_binding/key_processor.py", line 186, in _process
    self._call_handler(matches[-1], key_sequence=buffer[:])
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/key_binding/key_processor.py", line 321, in _call_handler
    handler.call(event)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/key_binding/key_bindings.py", line 124, in call
    result = self.handler(event)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/shortcuts/prompt.py", line 798, in _accept_input
    self.default_buffer.validate_and_handle()
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/buffer.py", line 1877, in validate_and_handle
    self.append_to_history()
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/buffer.py", line 1385, in append_to_history
    self.history.append_string(self.text)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/history.py", line 74, in append_string
    self.store_string(string)
  File "/usr/local/lib/python3.9/site-packages/prompt_toolkit/history.py", line 295, in store_string
    with open(self.filename, "ab") as f:

Exception [Errno 13] Permission denied: '../.pymodhis'
{ress ENTER to continue...

Modbus specs describe the protocol and are worth a look. I use this online Modbus parser当我想快速解析一个命令时;您提供的字节串 (20 05 00 00 FF 00 8A 8B) 的输出是:

Part of Data Package Description Value
20 Slave address 0x20 (32)
05 Function code 0x05 (5) - Write Single Coil
00 00 Output address Physical: 0x0000 (0) Logical: 0x0001 (1)
FF 00 Output value On
8A 8B CRC 0x8A8B (35467)

从属地址表示您希望与总线上的哪个设备通信。这是在设备上设置的(您不能只添加设备并期望一切正常)。用于设置从属 ID 的方法因设备而异(有些有实用程序来执行此操作,有些使用开关或通过自己的用户界面进行设置,有些对此进行了硬编码)。您的设备 (Ebyte MA02-XACX0440) 默认为 32,但这可以使用设备上的 DIP 开关更改(这在手册中有介绍)。

您正在使用功能代码 5 - 'Write Single Coil'。线圈是比特,所以可以打开或关闭。

'output address' 表示您要写入设备上的哪个线圈。这个地址的含义因设备而异(一般文档中会有一个table解释这个)。对于您的设备,这在手册的 table 7.1(“寄存器列表”)中。

值就是写什么。对于 'write single coil' 函数,这必须是两个值之一:

value meaning
0x0000 Off
0xFF00 On

所有其他值均无效。然而,许多库(包括 pymodbus)会为你处理这个细节,允许你传递 True/False.

把这些放在一起你需要这样的东西:

client.write_coil(0, True, unit=32)

注意:您问了很多问题,因此本文可能无法完全回答这些问题,但希望能为您指明正确的方向(太多信息无法放入评论!)。