在西门子 S7-1200 PLC 上实现 Modbus TCP 通信,使其作为从站(Slave)将内部数据(如 Profinet I/O 数据或 DB 块、M 存储区中的变量)映射到 Modbus 保持寄存器(Holding Registers, 功能码 03)供 Modbus 主站(Master)读取,可以通过以下步骤实现:
核心原理:
使用西门子官方提供的免费库指令 MB_SERVER,将 S7-1200 配置为一个 Modbus TCP 服务器(从站)。该库允许你将 PLC 的 DB 块(数据块)或 M 存储区的一部分映射为 Modbus 保持寄存器区域。PLC 程序负责将需要输出的 Profinet/内部数据复制或映射到这个指定的 DB 块/M 存储区中。
所需条件:
- 硬件: S7-1200 CPU(固件版本 V4.0 或更高版本通常内置 Modbus TCP 服务器库支持,早期版本需确认兼容性)。
- 软件:
- TIA Portal(STEP 7 Basic/Professional)相应版本。
- Modbus TCP 通信库:
MB_SERVER(西门子官方提供的免费库指令)。通常可在 TIA Portal 的“全局库”中找到,或在西门子官方网站下载后导入。
- 网络: 以太网连接,S7-1200 和 Modbus TCP 主站设备位于同一网络中,IP 地址配置正确,网络通畅(防火墙需允许端口 502 的 TCP 连接)。
实现步骤:
安装/加载 MB_SERVER 库:
- 打开你的 TIA Portal 项目。
- 如果库尚未安装:
- 访问西门子工业在线支持网站,搜索“MODBUS TCP for S7-1200/1500”或类似关键词,下载官方
MB_SERVER 库文件(通常是 .library 格式)。
- 在 TIA Portal 中,转到“项目视图”->“库”选项卡。
- 右键点击“全局库”或“项目库”->“类型为全局库打开”->“库”菜单->“打开全局库”。
- 浏览并选择下载的
.library 文件进行安装。
- 库安装后,在项目树“程序块”->“添加新块”->选择“库”,你应该能找到
MODBUS TCP 文件夹,里面包含 MB_SERVER 功能块。
配置 PLC 硬件和网络:
- 在“设备视图”中,双击你的 S7-1200 CPU 模块。
- 在“属性”->“常规”->“PROFINET接口[X1]”->“以太网地址”下,为 PLC 分配一个固定的 IP 地址、子网掩码。确保此 IP 与 Modbus 主站在同一子网内。
- (可选但推荐)在“属性”->“常规”->“PROFINET接口[X1]”->“高级选项”->“操作模式”下,确保“连接资源”足够(Modbus TCP 连接会占用连接资源)。
创建 Modbus 映射数据区:
- 决定使用 DB 块(推荐) 或 M 存储区 作为 Modbus 保持寄存器的映射区域。
- 推荐使用 DB 块(优化或非优化均可):
- 或使用 M 存储区: 计划一片连续的 M 存储区(如 MW100 到 MW199,对应 100 个字 = 100 个寄存器)。确保该区域在程序中不被其他功能意外覆盖。
编写 PLC 程序 - 数据映射:
- 在
OB1(主循环组织块)或合适的循环中断块中编写逻辑。
- 将需要输出的 Profinet 数据(或任何内部数据)复制或映射到步骤3创建的映射数据区(DB 块数组变量或 M 存储区)。
示例代码片段(假设使用 DB 块 DB_Modbus_Map,优化访问,数组变量名为 HoldingRegs ):
// 假设你的Profinet输入数据在ID区,需要将ID100开始的10个字映射到Modbus寄存器的前10个
"DB_Modbus_Map".HoldingRegs[0] := "ID100"; // Modbus 寄存器 40001
"DB_Modbus_Map".HoldingRegs[1] := "ID102"; // Modbus 寄存器 40002
... // 以此类推
"DB_Modbus_Map".HoldingRegs[9] := "ID118"; // Modbus 寄存器 40010
// 映射其他内部变量(例如 DB 块中的温度值)
"DB_Modbus_Map".HoldingRegs[10] := "DB_ProcessData".Temperature; // Modbus 寄存器 40011
"DB_Modbus_Map".HoldingRegs[11] := "DB_ProcessData".Pressure; // Modbus 寄存器 40012
- 如果使用 M 存储区(如 MW100 开始):
MW100 := ID100; // Modbus 寄存器 40001 (地址0)
MW102 := ID102; // Modbus 寄存器 40002 (地址1) - 注意:MW地址是字地址,每次+2
... // 以此类推
- 关键: 确保数据复制逻辑在
OB1 的每次扫描中都执行(或在你选择的循环块中),以保证 Modbus 主站读取到的是最新数据。数据类型转换(如 Real 转 Word)也需要在这里处理。
编写 PLC 程序 - 调用 MB_SERVER:
- 在
OB1 中调用 MB_SERVER 功能块。
- 背景数据块 (Instance DB): 在调用时,系统会提示你为
MB_SERVER 创建一个背景数据块(如 DB_MB_Server)。为其命名并创建。
- 连接参数:
REQ: 常设为 TRUE (上升沿触发一次初始化,之后保持 TRUE 维持连接)。
DISCONNECT: 设为 FALSE (保持连接)。
MB_HOLD_REG: 指向步骤3创建的映射数据区。
- 如果使用 DB 块:
P#DBx.DBX y.z WORD n (其中 x 是 DB 号,y 是字节偏移量,z 是位偏移量通常为0,n 是字数/寄存器数)。
- 优化 DB 块例子:
P#DB2.DBX0.0 WORD 100 (假设 DB_Modbus_Map 是 DB2,数组从字节0开始,共100个字)。
- 非优化 DB 块例子: 需要根据变量的偏移地址计算。
- 如果使用 M 存储区:
P#M y.z WORD n (其中 y 是起始字节地址)。
- 例子:
P#M100.0 WORD 100 (从 MW100 开始,共100个字)。
CONNECT: 指向一个连接参数结构体。 需要在全局数据块或 M 存储区中定义。
- 右键点击
CONNECT 引脚 -> “复杂数据类型” -> “新建”。
- 选择数据类型
TCON_IP_v4 (或兼容类型)。
- 在新建的 DB/M 变量中配置连接参数:
InterfaceID: 16#00000001 (通常表示 CPU 的第一个集成 PN 接口)。
ID: 任意唯一标识符(范围 1~4095),用于区分不同连接。
ConnectionType: 16#0B (表示 TCP 连接)。
ActiveEstablished: FALSE (从站模式)。
RemoteAddress: 设为 0.0.0.0 (接受来自任何主站的连接)。
LocalPort: 502 (Modbus TCP 标准端口)。
RemotePort: 0 (不关心主站端口)。
MB_HOLD_REG_START (可选): Modbus 保持寄存器的起始地址(在 Modbus 协议中的偏移量)。通常设为 0,对应 Modbus 地址 40001。如果需要映射到 40011 开始,则设为 10。
NDR, ERROR, STATUS: 用于监控连接状态和错误代码。将它们连接到临时变量或 M 存储区以便监控调试。
下载程序并测试:
- 编译项目无误后,将硬件配置和程序下载到 S7-1200 PLC。
- 确保 PLC 处于 RUN 模式。
- 使用 Modbus TCP 主站设备/软件测试:
- 在 Modbus 主站配置中,指定 S7-1200 的 IP 地址和端口(通常 502)。
- 指定要读取的 Modbus 保持寄存器范围(功能码 03)。
- 起始地址:如果
MB_HOLD_REG_START=0,则 Modbus 地址 40001 对应映射数据区的第一个字(HoldingRegs[0] 或 MW100)。读取地址 0(或 1,取决于主站软件约定,注意 Modbus 地址偏移为 1)。
- 读取数量:不要超过你在映射区定义的字数。
- 验证读取到的数据是否与你程序中写入映射数据区的值一致。
关键注意事项:
- 数据类型与对齐: Modbus 保持寄存器是 16 位无符号整数 (
Word)。如果原始数据是其他类型(如 Real, DInt),必须在 PLC 程序中进行转换(如使用 MOVE 指令移到 Word 数组,或处理高低字节)后再放入映射区。确保数据在 DB 块/M 存储区中是按 Word 边界对齐的。
- 映射一致性: PLC 程序必须持续地将需要输出的数据更新到 Modbus 映射数据区。Modbus 主站读取的是映射区中的数据,而不是原始 Profinet 输入存储区(I 区)或 DB 块变量的实时快照(除非你直接映射 I 区/I 地址到 Modbus 区,但通常不推荐)。
- 大小端序 (Endianness): S7-1200 内部数据存储是大端序 (Big-Endian)。大多数 Modbus 协议也使用大端序,所以对于
Word 类型数据通常没有问题。但如果传输 DWord 或 Real (拆分为两个 Word),需要确认 Modbus 主站期望的字节顺序是否与西门子一致(通常一致)。如果不一致,需要在 PLC 或主站端进行字节交换。
- 内存范围: 确保映射数据区(DB 块或 M 存储区)足够大以容纳所有需要输出的寄存器。避免访问越界。
- 连接资源: S7-1200 CPU 有有限的开放式通信连接资源。每个
MB_SERVER 实例会占用一个连接。确保 CPU 有足够资源支持所需数量的并行 Modbus TCP 连接。
- 端口冲突: 确保端口 502 没有被 PLC 上的其他服务(如 OPC UA 服务器、其他 S7 通信等)占用。
- 防火墙: 检查 PLC 所在网络的所有防火墙(包括 Windows 防火墙、路由器/交换机 ACL、工业防火墙),确保允许 TCP 端口 502 的入站连接。
- 错误诊断: 监控
MB_SERVER 的 ERROR 和 STATUS 输出,它们提供非常有价值的连接错误信息(如连接建立失败、请求格式错误等)。可以在 PLC 的在线诊断缓冲区查看更详细的信息。使用网络抓包工具(如 Wireshark)是诊断通信问题的终极利器。
总结流程图:
Profinet/内部数据 (I, Q, M, DB...)
|
V
PLC 程序 (OB1) -> 数据转换/复制 (如果需要)
|
V
映射数据区 (DB 块数组 / M 存储区) <-- MB_SERVER.MB_HOLD_REG 指向这里
|
V
MB_SERVER 指令 (在 OB1 中调用)
|
|
| --- CONNECT 参数 (TCON_IP_v4: IP, Port 502, Passive)
|
V
S7-1200 以太网接口 (Port 502)
|
V
Modbus TCP/IP 网络
|
V
Modbus 主站设备 (读取功能码 03, 指定寄存器地址和数量)
按照以上步骤操作,你应该能够成功地将 S7-1200 配置为 Modbus TCP 从站,并将指定的内部数据(包括 Profinet I/O 数据)通过 Modbus 保持寄存器提供给 Modbus 主站访问。务必注意数据类型转换、数据更新逻辑和网络配置细节。