Modbus

:::warning 目前,只有 KNOT、KNOT LR8G kit 和 KNOT LR9G kit 支持 Modbus 协议(具有 RS-485 端口)。 ::: 在 IoT 架构中广泛使用的协议之一称为 Modbus。

简介

警告

目前,只有 KNOT、KNOT LR8G kit 和 KNOT LR9G kit 支持 Modbus 协议(具有 RS-485 端口)。 在 IoT 架构中广泛使用的协议之一称为 Modbus。

您可以通过以下链接找到有关此协议的更多信息。

支持 Modbus 的设备应连接到 RS485 端口。设备支持两线连接(A+/B-)(一个 2 针端子块)。

需要注意的是,两个引脚不应混淆。颠倒 "A" 和 "B" 连接(极性错误)将导致通信失败。

另一点需要记住的是 Modbus 线缆距离。如果线缆长度小于 50 米——应该没有问题。如果使用 50 米以上的线缆,应在线缆末端安装 120 欧姆的终端电阻。

KNOT 支持:

  • Modbus TCP 服务器场景,允许您使用第三方 Modbus 客户端通过 Modbus TCP/IP 连接(TCP 端口 502)向 KNOT 的 IP 地址发送功能码命令。您可以使用任何 Modbus Client 软件(互联网上有很多)或者可以轻松地用 Python 编写/配置。在这种情况下,KNOT 将 Modbus TCP/IP 请求"转换/桥接"为 Modbus RTU。
  • Modbus RTU 控制器场景(仅从 v7.10 开始可用),允许您直接从 RouterOS 命令行通过 Modbus/RTU 发送功能码命令。

Modbus TCP 数据包结构

您可以使用此链接找到有关 Modbus 数据包结构的更多信息。

查询数据包由 Transaction ID、Protocol、Length、Unit ID、Function Code 和 Function Parameters 字段组成,最大大小为 260 字节。

  • Transaction ID - 从 0 到 65535 的整数,用于标识对特定查询的应答;
  • Protocol - 0x0000 代表 Modbus;
  • Length - 显示 Length 字段之后将跟随多少字节;
  • Unit ID - 通常称为 "Device address",0x00-0xff。特定系统中的每个终端设备应具有唯一的 ID;
  • Function Code - 描述将调用哪个功能。每个设备有多个寄存器,这些功能用于与寄存器交互。代码由标准定义,但制造商也可以实现具有特定代码的自定义功能;
  • Function Parameters/data - 通常指定寄存器地址、数据长度,以及在使用 "write" 功能时要写入的数据。 默认的 Unit ID、Function Codes 和 Parameters 可在特定产品的数据表中找到。应答消息的结构类似,也应在产品数据表中描述。

配置

子菜单: /iot modbus

一旦板卡连接到 Modbus 设备,请检查 "modbus" 端口配置(如果连接的 Modbus 设备期望其他值,可以更改 baud-rate):

[admin@MikroTik] > /port print
Columns: DEVICE, NAME, CHANNELS, USED-BY, BAUD-RATE
# DEVICE  NAME    CHANNELS  USED-BY  BAUD-RATE
0         modbus         1  modbus        9600
1 1-1     modem          4                9600

默认情况下,名为 "modbus" 的端口被分配给 Modbus 服务,但服务本身处于禁用状态。要激活 "Modbus" 服务,您需要执行如下所示的命令:

[admin@MikroTik] > /iot modbus print       
                disabled: yes
           hardware-port: modbus
                tcp-port: 502
                 timeout: 1000ms
  disable-security-rules: yes
[admin@MikroTik] > /iot modbus set disabled=no

此外,当您希望允许 Modbus 客户端使用 TCP(502)/IP 协议与 Modbus 服务器通信时,您需要确保设备的 IP+502 TCP 端口可访问。从 LAN 访问应该从一开始就被允许,因为没有任何防火墙规则限制此类访问。从外部(如果"从属"设备从 WAN 侧连接)——默认情况下不允许。您可以在手册中找到有关如何配置防火墙的信息。不建议让公共/WAN 访问对所有人开放,如果需要此类访问,您应指定允许的公共"客户端"的源 IP 地址(借助防火墙规则内的 src-address 参数)。否则,您将 Modbus 端口开放给所有人探测。

PropertyDescription
disabled (yes | no; Default: yes)启用或禁用 Modbus 功能。
hardware-port (list of string; Default: modbus)为服务分配端口。使用默认的 "modbus" 端口。
tcp-port (integer:0..4294967295; Default: 502)指定设备将用于 Modbus TCP 通信的 TCP 端口。
timeout(integer:0..1000; Default: 1000)指定超时值,以毫秒为单位。发送 Modbus 请求并接收回复所允许的最长时间。如果请求和回复之间的时间长于配置的值,则返回 "failure"。
disable-security-rules (yes | no; Default: yes)启用或禁用 security-rule 功能。
interframe-gap (integer; Default: 0)Modbus 是"半双工"→ 同一时间要么打开 Tx 窗口,要么打开 Rx 窗口。根据标准,在 Tx 之后必须跟随一个 3.5 字符(不同波特率下有所不同)的静默间隔。但是,并非所有 Modbus Slave 设备都遵循该规则,它们可能更早或更晚地开始回传 Tx。这可能导致信息位丢失和通信失败。此参数可用于"从属"设备不遵循标准规则的情况。interframe-gap=0 代表 ~4 ms 的 3.5 字符间隔。
rx-switch-offset (integer;)定义 Modbus 窗口(引脚方向)从 Tx 切换到 Rx 的速度。

通过 Modbus RTU 发送功能码命令

仅从 v7.10 开始可用。这适用于 "Modbus RTU" 场景。此功能允许直接从 RouterOS 发送功能码命令(支持所有功能码)。对于 "Modbus TCP" 场景,您必须使用第三方软件来发送功能码命令。

子菜单: /iot modbus transceive

PropertyDescription
address (integer:0..255; Default: )指定设备地址或 unit ID。
function (integer:0..255; Default: )指定功能码。例如:function=3 → Read Holding Register 功能码;function=6 → Write Single Holding Register 功能码。
data (string, max length 504; Default: )输入数据字符串,通常指定寄存器地址和要发送的数据。例如:data=20000001 数据字符串长度为 4 字节。"0x2000" 是发送到寄存器的命令(2 字节长),"0x0001"(2 字节长)是设备的地址。有关需要发送的确切数据字符串,请参阅 Modbus 设备的规格。
values (integer:0..4294967295; Default: )发送数据的另一种方式(参见上面的 data 参数)。在这种情况下,指定的每个值代表数据载荷/字符串的 1 个字节。例如:values=32,0,0,1 等同于 data=20000001 的输出。32(dec)=0x20(hex)、0(dec)=0x00(hex)、0(dec)=0x00(hex)、1(dec)=0x01(hex) → 0x20000001。

使用 "transceive" 功能发送功能码 3 命令的示例:

/iot modbus transceive address=1 function=3 data=20000001 
   address: 1
  function: 3
      data: 01030164
    values: 100
      time: apr/27/2023 14:05:15
    status: ok

从上面的输出可以看出,Modbus 连接的设备回复了值 "100" 或数据 "01030164"(01→ 地址;03→ 功能码;01→ 字节数;64(十六进制转十进制=100)→ 回复)。

通过 Modbus TCP 发送功能码 "3" 命令

专门针对功能码 3(这不适用于任何其他功能码),您可以使用如下所示的附加选项:

[admin@device] > {:local output [/iot modbus read-holding-registers slave-id=0x03 num-regs=0x1 reg-addr=0x0 as-value once];:put [($output->"values")]}
2349
[admin@device] > {:local output [/iot modbus read-holding-registers slave-id=0x03 num-regs=0x5 reg-addr=0x0 as-value once];:put [($output->"values")]}
2353;3;500;75;38

可以变化的参数有 "reg-addr"(数据字符串中的地址)、"num-regs"(发送到寄存器的数据字符串命令/寄存器数量)和 "slave-id"(设备地址或 unit ID)。它们都取决于 MODBUS 连接的设备支持哪些值。

Modbus 安全性

从 v7.12 开始可用。

子菜单: /iot modbus security-rules

Modbus 安全功能允许您设置特定规则,以限制或允许对 Modbus 连接设备的访问。这仅适用于 Modbus TCP 通信(这些规则不适用于 Modbus RTU 通信)。它使得可以允许特定 IP 范围/网络访问特定的功能码命令。

要启用此功能,请输入命令:

/iot modbus set disable-security-rules=no

启用该功能后,添加规则本身。例如:

/iot modbus security-rules add ip-range=0.0.0.0/0 allowed-function-codes=3,6

上面的规则将允许任何可能的 IP 地址向 Modbus 连接的设备发送功能码 3 和 6 命令。其他所有内容都受到限制。

PropertyDescription
ip-range (Address/Netmask; Default: )指定将允许发送功能码命令的 IP 地址范围(或网络)。
allowed-function-codes (integer:0..4294967295; Default: )指定只能从已配置的 ip-range 访问的功能码。