Modbus RTU V3 及以上版本指令集介绍

TIA Portal V13 SP1 版本开始软件中提供了两个版本的 Modbus RTU 指令集,如图 1 所示。

图 1. 两个版本 Modbus RTU 指令集

早期版本的 Modbus RTU 指令集(图 1 中 MODBUS (V2.2))仅可通过主机架 CM1241 通信模块或 CB1241 通信板进行 Modbus RTU 通信。 具体使用请参见文档 :主站从站。主要用于早期项目和 V4.0 之前版本的 CPU。

新版本的 Modbus RTU 指令集(图 1 中红框指令集)扩展了 Modbus RTU 的功能,该指令集除了支持主机架 CM1241 通信模块、CB1241 通信板,还支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的点对点通信模块实现 Modbus RTU 通信。从这个版本开始 S7-1200 与 S7-1500 在 Modbus RTU 指令集开始一致,并且之后版本更新也是基于该版本,建议 V4.0 以后的 CPU 和串口模块使用该版本指令集。

硬件要求:

新版本 Modbus RTU 指令集所支持的点对点模块如图 2 所示。

图 2. 新版本 Modbus RTU 指令集所支持的点对点模块

Modbus RTU 指令的使用

新版本 Modbus RTU 指令集中包含 Modbus RTU 主站指令和从站指令。

本文以 CPU1217C + CM1241 RS422/485 + ET200SP CM PtP 模块为例,介绍新版本 Modbus RTU 指令主从通信的编程步骤。 其中 CPU 机架 CM1241 RS422/485 作为 Modbus RTU 从站,分布式机架 ET200SP 中 CM PtP 模块作为 Modbus RTU 主站。网络结构图如图 3 所示。

图 3. Modubs RTU 网络通信结构图

本项目中使用到的硬件和软件如下:

主要硬件:

软件:

文档链接:

1. 设备组态

a. 组态 CM1241 RS422/485 模块

打开设备视图,添加 S7-1200CPU,并在硬件目录里找到“通信模块”→“点到点”→“CM1241(RS422/485)”,拖拽此模块至 CPU 左侧即可,如图 4 所示:

图 4. 添加 CM 1241 RS422/485 模块

注意:

固件版本>=V2.1 的 CM 1241 RS422/485 模块,才支持新版本 Modbus RTU 指令集。

在“设备视图”中用鼠标选中 CM1241(RS422/485) 模块,在“属性”→“端口组态”中配置此模块硬件接口参数, 本例以传输率 = 9.6 kbps,奇偶校验 = 无,数据位 = 8 位字符,停止位 = 1 为例。

CM 1241 端口组态设置如图 5 所示。

图 5. CM1241 RS422/485 模块端口组态

在“硬件标识符”里确认一下硬件标识符为 269(该参数在程序编程中会被使用),如图 6 所示。

图 6. 硬件标识符

另外,S7-1200 还提供了系统和时钟存储器功能,为了便于后续指令方便使用,建议使能该功能。在 CPU “属性”→“常规”→“系统和时钟存储器”使能系统和时钟存储器功能,如图 7 所示。

图 7. 系统和时钟存储器功能

b. 组态 ET200 SP CM PtP 模块

(1) 插入一个 ET200SP 分布式站点。

打开网络视图并拖入一个 ET200SP 站点,并将其分配给相应的 IO 控制器(本例 CPU1217C 为 IO 控制器),如图 8 所示。

图 8. 插入 ET200SP 站点

(2) 组态 ET200SP 站点。

在 ET200SP 的"设备视图"环境下,为 ET200SP 站点添加信号、通信模块和服务模块,在本例中只添加了 CM PtP 模块和服务模块。

注意:

ET200SP 站点中,服务模块是必须组态的。服务模块随接口模块一起采购,无需单独购买。

ET200SP 接口模块需要为其分配 IP 地址和设备名称,有关 ET200SP 分布式 IO 组态详细步骤,请参考文档

在 ET200SP "设备视图"中用鼠标选中 CM PtP,在“属性”→“常规”→“接口”→“操作模式”中配置此模块硬件接口参数, 本例设定“指定工作模式":"半双工(RS485)2 线制操作";"接收线路的初始状态":"无"。如图 9 所示。

图 9. CM PtP 操作模式

接下来,在“属性”→“常规”→“接口”→“端口组态”中配置此模块端口组态参数, 本例设定"协议":"Freeport/Modbus";"端口参数"设置:传输率 = 9600 bps,奇偶校验 = 无,数据位 = 8 位字符,停止位 = 1 为例。端口组态设置如图 10 所示。

图 10. CM PtP 端口组态

最后需要在“硬件标识符”里确认一下 CM PtP 模块硬件标识符,该参数在程序编程中会被使用。如图 11 所示。

图 11. 系统常量

2. 软件编程

a. Modbus RTU 主站编程

Modbus RTU 主站编程需要调用 Modbus_Comm_Load 指令和 Modbus_Master 指令,其中 Modbus_Comm_Load 指令通过 Modbus RTU 协议对通信模块进行组态,Modbus_Master 指令可通过由 Modbus_Comm_Load 指令组态的端口作为 Modbus 主站进行通信, Modbus_Comm_Load 指令的 MB_DB 参数必须连接到 Modbus_Master 指令的(静态)MB_DB 参数。

本例中分布式机架 ET200SP 中 CM PtP 模块作为 Modbus RTU 主站,其相关编程步骤如下:

(1) OB1 中插入一个 FC,并在 FC 中拖入 Modbus_Comm_Load 指令和 Modbus_Master 指令。如图 12 所示。

图 12. Modbus RTU 主站指令

Modbus_Comm_Load 指令各参数意义如表 1 所示:

引脚

说明

REQ

上升沿触发

PORT

通信端口的硬件标识符

BAUD

波特率选择:3600,6000,12000,2400,4800,9600,19200,38400,57600,76800,115200

PARITY

奇偶检验选择:0-无;1-奇校验;2-偶校验

FLOW_CTRL

流控制选择:0-(默认值)无流控制

RTS_ON_DLY

RTS 延时选择:0-(默认值)

RTS_OFF_DLY

RTS 关断延时选择:0-(默认值)

RESP_TO

响应超时: 默认值 = 1000 ms。Modbus_Master 允许用于从站响应的时间(以毫秒为单位)。

MB_DB

对 Modbus_Master 或 Modbus_Slave 指令的背景数据块的引用。 MB_DB 参数必须与 Modbus_Master 或 Modbus_Slave 指令中的静态变量 MB_DB 参数相连。

DONE

如果上一个请求完成并且没有错误,DONE 位将变为 TRUE 并保持一个周期。

ERROR

如果上一个请求完成出错,则 ERROR 位将变为 TRUE 并保持一个周期。 STATUS 参数中的错误代码仅在 ERROR = TRUE 的周期内有效。

STATUS

端口组态错误代码,请参考 TIA Portal 软件在线帮助或 S7-1200 系统手册。

表 1. Modbus_Comm_Load 指令参数意义

Modbus_Master 指令各参数意义如表 2 所示。

引脚

说明

EN

使能端

REQ

TRUE = 请求向 Modbus 从站发送数据 ,建议采用上升沿触发

MB_ADDR

Modbus RTU 从站地址。默认地址范围:0 至 247;扩展地址范围:0 至 65535。值 0 被保留用于将消息广播到所有 Modbus 从站。

MODE

模式选择: 指定请求类型(读取或写入)。

DATA_ADDR

从站中的起始地址:指定 Modbus 从站中将供访问的数据的起始地址。

DATA_LEN

数据长度:指定要在该请求中访问的位数或字数。

DATA_PTR

数据指针: 指向要进行数据写入或数据读取的 M 区或数据块地址。

DONE

完成位:上一请求已完成且没有出错后,DONE 位将保持为 TRUE 一个扫描周期时间。

BUSY

FALSE – Modbus_Master 无激活命令;TRUE – Modbus_Master 命令执行中

ERROR

如果上一个请求完成出错,则 ERROR 位将变为 TRUE 并保持一个周期。 STATUS 参数中的错误代码仅在 ERROR = TRUE 的周期内有效。

STATUS

端口组态错误代码,请参考 TIA Portal 软件在线帮助或 S7-1200 系统手册。

表 2. Modbus_Master 指令参数意义

注意:

① Modbus_Comm_Load 指令不建议在启动组织块 OB100 中调用,建议在 OB1 中调用。

Modbus_Comm_Load 指令在 OB1 中调用时,其输入位“REQ”需使用上升沿触发,本例中该输入位采用 “FirstScan” 系统存储器位。

② Modbus_Comm_Load 指令背景数据块中的静态变量 “MODE” 用于描述点对点模块的工作模式,有效的工作模式包括:

该静态变量 “MODE” 默认数据为 0(RS232 全双工模式),需要根据点对点模块实际组态修改该数值,本例中 CM PtP 模块工作在 RS485 半双工模式需要将该数值修改为 4,如图 13 所示。

图 13. Modbus_Comm_Load 背景数据块静态变量 “MODE” 修改为 4

③ Modbus_Master 指令的 “DATA_PTR” 参数用于指向要进行数据写入或数据读取的数据区域地址,该数据区域在 V3.0 支持非优化(标准的)数据块。一般建议使用指针方式填写,例如程序中的 P#DB3.DBX0.0 WORD 5,此外也可以使用基本数据类型数组方式填写。指针的含义参见链接

从 V4.0 版本开始支持优化 DB 块,具体参见链接

在数据块的属性中取消“优化的块访问”即可将数据块修改为非优化访问的数据块(鼠标右键数据块,选择“属性”,取消“优化的块访问”),如图 14 所示。

图 14. 设置数据块为非优化访问

④ 当 Modbus RTU 网络中存在多个 modbus RTU 从站或一个 modbus RTU 从站同时需要多个作业,例如需要读和写或者读多个区域等,则需要调用多个 Modbus_Master 指令,Modbus_Master 指令之间需要采用轮询方式调用,并且使用相同背景数据块。

如图 15 所示,用于描述两个 Modbus_Master 指令轮询调用的方式。

图 15. Modbus_Master 轮询调用方式

⑤ MB_MODE、MB_DATA_ADDR、MB_DATA_LEN、 Modbus RTU 功能码等之间的关系,如表 3 所示。

MB_MODE MB_DATA_ADDR MB_DATA_LEN Modbus RTU 功能码 操作和数据
0 1 - 9999 1 - 2000 01
  • 读取输出位
    • 每个请求 1 - 2000 个位
0 10001 - 19999 1 - 2000 02
  • 读取输入位
    • 每个请求 1 - 2000 个位
0
  • 40001 - 49999(等同于 400001 - 409999)
  • 400001 - 465535
1 - 125 03
  • 读取保持寄存器
    • 每个请求 1 - 125 个字
0 30001 - 39999 1 - 125 04
  • 读取输入字
    • 每个请求 1 - 125 个字
1 10001 - 19999 1 05
  • 写入输出位
    • 每个请求 1 个位
1
  • 40001 - 49999(等同于 400001 - 409999)
  • 400001 - 465535
1 06
  • 写入保持寄存器
    • 每个请求 1 个字
1 10001 - 19999 2 - 1968 15
  • 写入多个输出位
    • 每个请求 2 - 1968 个位
1
  • 40001 - 49999(等同于 400001 - 409999)
  • 400001 - 465535
2 - 123 16
  • 写入多个保持寄存器
    • 每个请求 2 - 123 个字
2 10001 - 19999 1 - 1968 15
  • 写入输出位
    • 每个请求 1 - 1968 个位
2
  • 40001 - 49999(等同于 400001 - 409999)
  • 400001 - 465535
1 - 123 16
  • 写入保持寄存器
    • 每个请求 1 - 123 个字
11 - 11
  • 读取服务器的状态字和事件计数器:
    • 状态字反映了处理的状态(0 - 未处理,0xFFFF - 正在处理)
    • Modbus 请求成功执行时,事件计数器将递增。如果执行 Modbus 功能时出错,则服务器将发送消息,但不会递增事件计数器。
80 - 1 08
  • 通过诊断代码 0x0000 检查服务器状态(返回循环测试 - 服务器发回请求):
    • 每次调用 1 个字
81 - 1 08
  • 通过诊断代码 0x000A 复位服务器的事件计数器:
    • 每次调用 1 个字
104 0 - 65535 1 - 125 04
  • 读取输入字
    • 每个请求 1 - 125 个字

注:

表 3. 对应关系

⑥ 对于一般的支持 Modbus RTU 设备,可能无法在其设备手册中查找到诸如 40001、30001 这种数据地址,而是以功能码 + 十六进制数形式的变量地址,就需要这样解决:

通过判断功能码决定是读是写,决定 MB_MODE 为 0 读还是 1 写(2 写比较特殊,只用于不支持 5、6 号功能码的设备),然后将十六进制地址数转化为十进制数,然后对于不同的功能码,十进制数增加不同的偏移量,对于功能码 1、5、15 偏移量为 1,对于功能码 2 偏移量为 10001,对于功能码 3、6、16 偏移量为 40001(对于超过 9999 的地址,偏移量为 400001),对于功能码 4 偏移量为 30001。例如从站设备使用 0x03 功能码,地址 0x00FF ,因为是读,所以 MB_MODE = 0, 0x00FF 转换为十进制为 255,加上偏移量 40001 就是 40256,这样 MB_DATA_ADDR = 40256。

此外对于功能码 4,如果十进制地址数超过 9998 的,加上偏移量 30001 将超过 39999,此时可以使用 MB_MODE = 104,然后 MB_DATA_ADDR 使用不增加偏移量的十进制地址数也是可以的。例如从站设备使用 0x04 功能码,地址 0x4000 , 0x4000 转换为十进制为 16384,加上偏移量 30001 将超过 39999,此时使用 MB_MODE = 104,MB_DATA_ADDR = 16384。

⑦ 对于分布式 IO 上的串口模块,还需要考虑模块拔出或者掉站的情况,具体处理参见常见问题 5

b. Modbus RTU 从站编程

Modbus RTU 从站编程需要调用 Modbus_Comm_Load 指令和 Modbus_Slave 指令,其中 Modbus_Comm_Load 指令通过 Modbus RTU 协议对通信模块进行组态,Modbus_Slave 指令可通过由 Modbus_Comm_Load 指令组态的端口作为 Modbus 从站进行通信,Modbus_Comm_Load 指令的 MB_DB 参数必须连接到 Modbus_Slave 指令的(静态)MB_DB 参数。

本例中 CPU 机架 CM1241 RS422/485 作为 Modbus RTU 从站,其相关编程步骤如下:

OB1 中插入一个 FC,并在函数中拖入 Modbus_Comm_Load 指令和 Modbus_Slave 指令。如图 16 所示。

图 16. 拖入Modbus RTU 从站指令

Modbus_Slave 指令各参数意义如表 4 所示:

引脚

说明

MB_ADDR

Modbus 从站的标准寻址: 标准寻址范围(1 到 247), 扩展寻址范围(0 到 65535)

MB_HOLD_REG

数据指针,指向 Modbus 保持寄存器的地址, Modbus 保持寄存器可以为 M 存储区或 DB 数据区。

NDR
可用的新数据:
  • FALSE : 无新数据
  • TRUE : 表示新数据已由 Modbus 主站写入,如果上一个请求完成并且没有错误,NDR 位将变为 TRUE 并保持一个周期。
DR
读取数据:
  • FALSE : 无新数据
  • TRUE :表示该指令已将 Modbus 主站接收到的数据存储在目标区域中。如果上一个请求完成并且没有错误,DR 位将变为 TRUE 并保持一个周期。

ERROR

如果上一个请求完成出错,则 ERROR 位将变为 TRUE 并保持一个周期。 如果执行因错误而终止,则 STATUS 参数中的错误代码仅在 ERROR = TRUE 的周期内有效。

STATUS

错误代码

表 4. Modbus_Slave 指令参数意义

注意:

① Modbus_Comm_Load 指令不建议在启动组织块 OB100 中调用,建议在 OB1 中调用。

Modbus_Comm_Load 指令在 OB1 中调用时,其输入位“REQ”需使用上升沿触发,本例中该输入位采用 “FirstScan” 系统存储器位。

② Modbus_Comm_Load 指令背景数据块中的静态变量 “MODE” 用于描述点对点模块的工作模式,有效的工作模式包括:

该静态变量 “MODE” 默认数据为 0(RS232 全双工模式),需要根据 CM PtP 模块实际组态修改该数值,本例中 CM PtP 模块工作在 RS485 半双工模式需要将该数值修改为 4,参考图 13 。

③ Modbus_Slave 指令的 “MB_HOLD_REG” 用于定义 CPU 的 Modbus 保持寄存器的数据区域地址,该数据区域在 V3.0 支持非优化(标准的)数据块。一般建议使用指针方式填写,例如程序中的 P#DB6.DBX0.0 WORD 100,此外也可以使用基本数据类型数组方式填写。指针的含义参见链接

从 V4.0 版本开始支持优化 DB 块,具体参见链接

在数据块的属性中取消“优化的块访问”即可将数据块修改为非优化访问的数据块(鼠标右键数据块,选择“属性”,取消“优化的块访问”),参考图 14 。

④ Modbus RTU 从站数据区定义,参见表 5。

地址区 定义 说明
输出位 Q0.0 开始
  • Q0.0 为地址 1,Q0.1 为地址 2,Q0.7 为地址 8,Q1.0 为地址 9...
输入位 I0.0 开始
  • I0.0 为地址 10001,I0.1 为地址 10002,I0.7 为地址 10008,I1.0 为地址 10009...
输入寄存器 IW0 开始
  • IW0 为地址 30001,IW2 为地址 30002,IW4 为地址 30003...
保持寄存器 由 MB_HOLD_REG 定义
  • 指针指向的第一个字为 40001,第二个字为 40002...
    • 例如:MB_HOLD_REG 为 P#M100.0 WORD 8,则 MW100 为 40001,MW102 为 40002,MW104 为 40003...MW114 为 40008
    • 例如:MB_HOLD_REG 为 优化 DB 中 INT 数组[0..7],数组名为 “XXX”.AA,则 “XXX”.AA[0] 为 40001,“XXX”.AA[1] 为 40002,“XXX”.AA[2] 为 40003...“XXX”.AA[7] 为 40008

注意:数据区从指令集版本 V4.0 开始,可以自由定义,方法参见链接

表 5. 数据区定义

⑤ 如果是分布式 IO 上的串口模块,还需要考虑模块拔出或者掉站的情况,具体处理参见常见问题 5

c. 编译下载

之后将程序和组态编译下载到 PLC 中,即可测试 Modbus RTU 通信了。

3. 常见问题 FAQ

1. 新版本 Modbus RTU 指令的使用是否存在些限制条件?

新版本 Modbus RTU 指令通过 CM1241 通信模块或 CB1241 通信板进行 Modbus RTU 通信时,需要满足如下条件:

S7-1200 V4.0 固件 CPU 可以通过固件更新到 V4.1 及以上版本,V2.0 固件的 CM1241 通信模块也可以通过固件更新的方式更新到 V2.1 及以上版本。 相关固件更新的方法请参考 S7-1200 固件更新

2. Modbus_Comm_Load 指令背景数据块中的静态变量 “MODE” 的作用是什么?为什么一般项目中,都需要对该变量进行修改?

新版本的 Modbus RTU 指令扩展了 Modbus RTU 的功能,该指令除了支持 CM1241 通信模块、CB1241 通信板还支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的点对点通信模块实现 Modbus RTU 通信。 而分布式 I/O 机架上的点对点通信模块可以支持多种工作模式,以 ET200SP CM PtP 模块(订货号:6ES7137-6AA0x-0BA0)为例,其可以支持 RS232、RS485 以及 RS422 等多种工作模式。

Modbus_Comm_Load 指令背景数据块中的静态变量 “MODE” 则用于定义点对点模块的工作模式,具体如下说明。 “MODE” 的默认数值为 0,代表“全双工 (RS232)”工作模式,实际项目组态中则需要根据实际工作模式对该变量进行修改。

3. Modbus_Comm_Load 指令能否在启动组织块 OB100 中调用?

Modbus_Comm_Load 指令可以但不建议在启动组织块 OB100 中调用。

新版本的 Modbus RTU 指令扩展了 Modbus RTU 的功能,该指令支持 PROFINET 或 PROFIBUS 分布式 I/O 机架上的点对点通信模块实现 Modbus RTU 通信。 操作系统需要调用读取数据记录和写入数据记录等指令来实现与分布式 I/O 机架上点对点模块的 Modbus RTU 通信。读取数据记录和写入数据记录指令为异步读写指令,指令需要多次执行,所以不建议 Modbus_Comm_Load 指令在启动组织块 OB100 中调用。如果需要,可以参考常见问题 5 中的方式,在 OB100 中反复执行 Modbus_Comm_Load 指令,直到指令完成。

4. 如何查询 Modbus RTU 通信错误时的错误代码?

以 Modbus_Master 指令为例,当通信出现错误时,Modbus_Master 指令的 “ERROR” 输出位将变为 TRUE 但是只保持一个扫描周期,所以通过 TIA Portal 软件程序监控时无法查询到错误。 Modbus_Master 指令 “STATUS” 参数中的错误代码仅在 “ERROR” = TRUE 的扫描周期内有效,为了获取了 Modbus RTU 通信错误的错误代码可以采用如图 17 所示方式编程。

图 17. 获取 STATUS

5. 对于分布式 IO 上的串口模块,如果出现从站掉站或者模块拔出应该怎么办?

对于分布式 IO 的串口模块,一旦出现故障以及故障恢复,系统会自动执行相关 OB,拔出插入会执行 OB83,掉站与恢复会执行 OB86。所以需要在相应 OB 中重新触发 Modbus_Comm_Load 指令,方法如下:

1. 插入"Pull or plug of modules" 中断 OB83。

分布式 IO 站点中插出、拔入模块时,操作系统都会调用一次 OB83。通过 OB83 接口区的输入变量 “Event_Class” 判断故障的模块和类型:事件类型16#39表示模块被拔出,事件类型16#38表示模块被插入。

CM PtP 模块被重新插入的时候,需要在中断 OB83 中调用 Modbus_Comm_Load 指令对通信模块进行重新组态,如图 18 所示。

图 18. OB83 中再次调用 Modbus_Comm_Load 指令

注意:

① OB83 中调用 Modbus_Comm_Load 指令的背景数据块需要与 OB1 中调用的 Modbus_Comm_Load 指令的背景数据块相同。

② CM PtP 模块的硬件标识符需要在"PLC 变量"--->"系统常数"中查询,参考图 12 所示。

2. 插入"Rack or Station failure" 中断 OB86。

分布式 IO 站点故障和恢复时,操作系统都会调用一次 OB86。通过 OB86 接口区的输入变量 “#Event_Class” 判断故障的模块和类型:事件类型 16#39 表示站点故障,事件类型 16#38 表示站点恢复。

CM PtP 模块所在的 IO 站点恢复时,需要在中断 OB86 中调用 Modbus_Comm_Load 指令对通信模块进行重新组态,如图 19 所示。

图 19. OB86 中调用 Modbus_Comm_Load 指令

注意:

① OB86 中调用 Modbus_Comm_Load 指令的背景数据块需要与 OB1 中调用的 Modbus_Comm_Load 指令的背景数据块相同。

② 分布式 IO 站点的硬件标识符需要在"PLC 变量"--->"系统常数"中查询,参考图 12 所示。

6. CM 1241 RS422/485 如何与 CM PtP 连接?

对于 CM1241 RS422/485 模块,RS485 模式接线是 3+ 8-,而对于 CM PtP,RS485 模式接线是 14+ 12-,所以本例中连接是将 CM1241 的 3 和 CM PtP 的 14 连接,CM1241 的 8 和 CM PtP 的 12 连接,如图 20 所示。

图 20. 连接示意