多台S7-1200 PLC走ModbusTCP通讯实战:从组网到联调踩坑全记录
2026/9/21 20:20:16 网站建设 项目流程

简介:西门子 S7-1200 系列 PLC 的 ModbusTCP 多机通信是工业自动化项目中常见的工程需求。压缩包提供了一套可直接参考的实操项目,适合自动化工程师、PLC 编程初学者及现场调试人员,用于解决多台 1200 PLC 之间通过以太网进行数据交换、寄存器读写和网络配置等实际问题,帮助快速搭建可用的多 PLC 通信链路。包内共 55 个文件,大小约 2.08MB,以 TIA Portal 项目工程文件为主,包含 XML 配置、AP14 工程、PNG/ICO/BMP 图标资源,以及 GSD、DB、PLF 等辅助文件;XML 多用于保存标签与转换日志,AP14 为完整工程文件,图标资源便于模块识别,可直接导入 TIA Portal 查看组态和程序结构。内容涵盖 MBTCP_SERVER 与 MBTCP_CLIENT 功能块调用、服务器与客户端角色分配、IP 地址规划、循环读写任务编写等关键实操点,并给出错误诊断思路;其中 ModbusTCP_S71500_V14 项目可帮助对照 S7-1500 系列 ModbusTCP 实现差异。目前已有 7746 人浏览学习,是快速掌握分布式控制系统通信开发的实用参考资料。 上个月刚把一个三台S7-1200联动的项目交付掉,趁着流程还记得清楚,把多台1200PLC走ModbusTCP通讯的一些实际做法整理出来。之所以想写这个,是因为网上关于“西门子1200PLC ModbusTCP通讯实例”的教程,大多数停留在单主站读单从站,一旦设备变成三台、五台,还要配组态王、触摸屏、第三方变频器,很多人就乱了。这篇文章按实际项目推进的顺序走一遍,从方案选型、硬件组网、指令调用到联调踩坑都覆盖到,适合手里有多台1200要互相交换数据、或者要给上位机/MES开放数据接口的工程师参考。

1. 多台1200互联,为什么我最终选了ModbusTCP

1.1 看着最顺的S7通信,在混合现场反而别扭

S7-1200之间交换数据,第一反应一定是S7通信或者PUT/GET。这个方案在西门子自家设备之间没有任何问题,博途里配置也不复杂,通信块就那么几个,填上伙伴IP和DB地址就能跑。但真正让我放弃的原因是现场不只有西门子:中控室有组态王要读数据,MES系统要用标准接口采集产量,角落里还躺着两台施耐德ATV930变频器等着PLC去控制。这些第三方系统对S7协议基本是绝缘的,要么专门装驱动,要么加OPC网关中转,等于为了PLC之间的通信,又给自己造出一堆对接工作。尤其组态王这类组态软件,读S7协议虽然也有驱动,但版本兼容性问题能折腾一整天,读ModbusTCP就完全没有这些破事。

1.2 ModbusTCP能用一个协议通吃整个现场

ModbusTCP的好处太直接了:协议公开、报文结构透明、几乎所有上位机组态软件和第三方设备都原生支持。PLC和PLC之间用它交换数据,PLC和组态王之间也用它,PLC和变频器之间还是它,一套协议解决全部通信需求,不需要为每种设备准备一套驱动。很多人觉得1200用ModbusTCP效率不如S7高,这个说法本身没错,但要分场合:做过程数据交换、状态采集、命令下发,几十个字几百毫秒甚至秒级的刷新,ModbusTCP绰绰有余。只有那种需要硬实时周期同步的场合,比如轴同步、飞剪定长,才需要考虑PROFINET IO之类的实时方案,普通的数据采集项目真用不上那么高的实时性。

1.3 一主多从,是我用过最稳的结构

多个1200组网,我通常的做法是选一台做数据汇集中枢,其余PLC全部做ModbusTCP从站。中枢PLC用MB_CLIENT按顺序轮询每台从站,把数据读回后写入本地数据块;上位机、组态王、触摸屏只需要跟中枢PLC这一个点打交道,不需要分别去连每台从站。这样设计有两个理由:第一,连接资源有限,如果每台上位机和每台PLC都互相建连接,资源很快就会耗尽;第二,轮询关系清晰,出问题的时候只盯着一台主站的程序排查就行,不用在几台PLC之间来回翻。真要说这个架构的缺点,就是主站PLC承担了所有数据转发,但1200做主站应付几台从站的周期轮询完全没压力,我实际跑下来CPU扫描周期几乎没有影响。

2. 网络硬件与IP规划:配错了后面全白搭

2.1 两台直连,三台以上老老实实上交换机

设备数量决定网络拓扑,这步看着基础,但真有人在这里栽过。两台1200之间点对点通信,网线直连没问题,现在的PLC网口基本都是自适应,交叉线直通线都认;但到了三台以上就必须用交换机了。我常用的做法是现场放一台工业交换机,把所有PLC、触摸屏、上位机都接到交换机上,星型结构最好排查问题。普通办公交换机能用吗?能用,但现场环境粉尘大、温度高,普通交换机容易出隐性故障,长期跑项目还是建议工业级,至少是导轨式安装那种。有同行问过PoE交换机连1200会不会有问题,1200本身不带受电功能,插在PoE口上不会烧,交换机会尝试供电但测不到受电设备,通常会停止供电。稳妥起见,给PLC用的端口最好在交换机里手动关掉PoE,或者直接接非PoE口,省得个别交换机在兼容性测试上闹脾气。

2.2 IP规划要留余量,连接预算也要提前算

多台1200组网,IP地址我习惯按角色分段分配,方便一眼看出哪台是什么设备:

设备角色IP地址示例说明
主站PLC192.168.0.10数据汇集中枢,ModbusTCP客户端
从站PLC 1192.168.0.21ModbusTCP服务器
从站PLC 2192.168.0.22ModbusTCP服务器
从站PLC 3192.168.0.23ModbusTCP服务器
触摸屏192.168.0.30同时作为ModbusTCP客户端直读主站
上位机192.168.0.50组态王作为ModbusTCP客户端

这张表里隐藏了一个关键点:所有设备必须保持同一网段,子网掩码默认。出现跨网段的情况,要么改路由,要么加三层交换机做转发,ModbusTCP走IP层虽然能通,但现场排查难度会明显上升,非必要不搞。另外一定要提前算连接资源的账。1200 CPU的连接资源是有限的,编程器在线会占一个,触摸屏占一个,S7通信占一个,开放式通信再占一个,每个MB_CLIENT实例、每个允许外部连接的MB_SERVER实例都要消耗资源。所以在设计阶段就给每台从站只保留1路给主站轮询,触摸屏和上位机统一去读主站,不直连每台从站,这样资源预算才够用。

3. 从站侧MB_SERVER:先把数据装进“透明箱子”

3.1 指令入口和背景DB

ModbusTCP从站功能在博途里的入口是:指令列表 -> 通信 -> 开放式通信 -> 其他 -> MODBUS TCP,里面有两个块:MB_CLIENT和MB_SERVER。从站侧拖MB_SERVER出来,系统会提示创建背景DB,直接默认生成就行。需要注意的是,MB_SERVER的REQ引脚是输出不是输入,很多人第一次用会误接,把REQ当成启动信号去触发它,结果各种奇怪现象。REQ输出只是告诉程序“现在有客户端在请求”,正常操作不用去碰它,DONE、ERROR、STATUS这几个输出才需要接到程序里做状态判断。

3.2 CONNECT结构体:地址和端口都在里面

MB_SERVER的CONNECT引脚需要关联一个连接描述结构体,类型选TCON_IP_v4。结构体里几个关键字段:InterfaceId固定填64,对应CPU的PROFINET网口;ID是这个连接在本CPU里的编号,必须和程序里其他连接的ID错开;LocalPort填502,这是ModbusTCP的默认端口,如果你在别的设备上占用了502,这里也要跟着改;RemotePort对服务器来说不用指定,客户端那边填了就行。IP地址字段,服务器侧可以填0.0.0.0表示监听所有来源的客户端请求,也可以指定只有某台主站能连,后者安全一点。我在实际项目里除非有明确的网络安全要求,否则都用0.0.0.0,省得到时候加设备还得回来改服务器配置。

3.3 保持寄存器数据区:必须配“取消优化的块访问”

MB_SERVER的MB_HOLD_REG引脚,需要关联一个数据块或者数组,这个区域就是客户端能读写的“透明箱子”。实操中最容易卡住的地方来了:博途默认创建的数据块是“优化的块访问”,这种DB无法直接传给MB_HOLD_REG。必须在DB属性里取消勾选“优化的块访问”,创建时把它建成“标准-与S7-300/400兼容”的模式。取消优化后,DB里的变量才有绝对地址,指令才能通过指针访问这个区域。如果建完DB才发现不能用模块访问,直接在DB属性里改掉,然后重新编译,变量地址就会变成类似DB1.DBW0的形式。

数据区规划,我建议直接在从站里建一个长度足够的Word数组,比如Array[0..249] of Word,然后按地址段划分用途:

地址范围用途读写方向
0-49设备运行状态、报警标志从站只写,主站只读
50-99主站下发的命令和参数从站只读,主站写
100-249工艺数据、产量、温度等双向

这样规划的好处是以后加设备、加数据点时,不用动已有的地址映射,上位机那边的变量表也相对固定,不会出现改一个地址牵一发动全身的情况。

4. 主站侧MB_CLIENT:轮询逻辑才是稳定关键

4.1 引脚参数一个个说清楚

主站侧的核心是MB_CLIENT。引脚不算多,但每个都得对上。REQ是上升沿触发,请求开始;DISCONNECT默认给FALSE,表示保持连接,如果给TRUE就会主动断开;CONNECT结构体里IP填从站地址,RemotePort填502,ID按连接资源编号;DATA_PTR是本地数据缓冲区指针,收发共用;DATA_LEN是缓冲区字节长度,不是Word数;MB_MODE选择功能,0是读、1是写、2是读写;MB_DATA_ADDR是从站的寄存器起始地址,注意是从0开始算;MB_DATA_LEN是本次要读写的寄存器数,单位由功能码决定;MB_DATA_PTR指向本地存数据的地址。这组参数里最容易搞混的是DATA_LEN和MB_DATA_LEN:前者是缓冲区总字节数,后者是本次通信要读写的寄存器数量,一个字节一个Word,经常有人写成一样的,结果通信长度对不上,从站响应不是报错就是数据截断。

4.2 一次实例对应一个从站,轮询用DONE串联

很多人在一个OB1里放一块MB_CLIENT,然后用定时器反复触发REQ,想着一个块就能轮询所有从站。实际这么做有两个问题:第一,MB_CLIENT的CONNECT结构体在一次通信过程中不能随意更换IP,换来换去会导致连接反复建立和断开,数据还没读到,时间全耗在握手上了;第二,REQ如果一直为TRUE,指令会认为你要持续请求,容易造成请求堆积,严重的时候连接会被看门狗断开。我推荐的做法是:每个从站配一个独立的MB_CLIENT实例,每个实例的CONNECT里写死对应从站的IP。轮询顺序用前一个实例的DONE或ERROR输出去触发下一个实例的REQ,比如第一个实例的DONE置位后,把它的REQ复位,同时置位第二个实例的REQ;第二个完成后再置位第三个;最后一个完成后再回到第一个,形成一个轮询循环。这样每个实例的连接一直保持,不会频繁断开,轮询周期也稳定。如果整个系统对刷新周期有要求,可以在OB30之类的循环中断里以固定周期触发轮询,但依然要保证一个REQ上升沿只发一次请求,等DONE或ERROR回来后再发下一次,绝对不能每个扫描周期都去拉REQ。

4.3 单次最多读125个寄存器,大数据量要拆包

Modbus协议本身规定了读保持寄存器的单次上限是125个字,写保持寄存器的上限是123个字。很多项目里一上来就想着一次把几百个Word全部搬过来,结果通信长度填了130、140,指令直接报错或者对方根本不响应。遇到超过125个字的区域,必须拆成多个请求,每次带不同的MB_DATA_ADDR起始地址和MB_DATA_LEN长度,在轮询状态机里排队执行。我实际做数据采集时,习惯把工艺数据按120个字一批来划分,每批拆成一个读请求,轮询周期控制在几百毫秒内,完全够用。拆包还有个额外的好处:单个请求的数据量小,出错的概率也低,就算某个请求超时了,不会影响整片数据的读取。

5. 联调阶段最容易踩的坑:从“读不上来”到“跑半年不断连”

5.1 组态王读1200读不上来,九成是地址偏移

现场最常见的报障就是“组态王连不上1200”或者“连上了但数据全是0”。ModbusTCP在组态王里配置时,寄存器地址通常是以40001开始的“4区地址”,这个40001对应Modbus协议里的保持寄存器地址0,也就是S7-1200的MB_HOLD_REG数据区第一个字。很多人会把组态王地址填成40000,或者把起始偏移算错一格,导致读出来的数据整体错位。排查方法很简单:组态王地址填40001,PLC侧MB_SERVER的保持寄存器数组第一个元素,两个变量对一眼,能通就是一对一的对应关系,读出来的数值不对再往数据类型和字节序那边查。

5.2 连接只在启动时通一下,过几分钟就断

这个现象我遇到过好多次,表现是设备重启后上位机或者主站能通信一两分钟,然后彻底断开,再重启又重复,还有同行描述成“只有每次重启的时候才能连上一分钟”。后来查下来,常见根因就这么几个:第一,MB_CLIENT的REQ没有用一个上升沿去控制,而是每个扫描周期都在触发,请求堆积导致系统侧把连接断掉;第二,DISCONNECT引脚在某些逻辑里被置了TRUE,程序跑完一段后把连接主动掐了,而且没有再复位;第三,从站侧MB_SERVER的CONNECT结构体ID和主站侧某个连接的ID撞了,系统资源冲突。逐个排查时,先看程序里REQ和DISCONNECT的控制逻辑,再看所有连接的ID是否有重复,这两个点占这类故障的绝大多数。

5.3 三层排查链路:ping、telnet、抓包

多台设备联调,我有一套固定的排查顺序。第一层是物理链路和网络配置,先ping从站IP,确认网络层通不通;第二层是端口层,在电脑上telnet 192.168.0.21 502,能通说明TCP端口正常;第三层是协议层,用Wireshark抓包,过滤条件填tcp.port == 502,重点看三件事:TCP握手是否成功、Modbus报文里的功能码是不是自己预期的03读保持寄存器、寄存器地址和数量是否和配置一致。如果握手成功但对方不回Modbus响应,问题基本出在PLC侧数据映射或指令配置;如果TCP握手都失败,那就回头查IP、端口和防火墙。当然还要会看MB_CLIENT和MB_SERVER的STATUS输出。STATUS返回非0的时候,博途指令的帮助里自带一套错误码表,搜索“STATUS error codes”就能查到对应解释,比自己瞎猜快得多。

6. 几个现场经验,送给第一次做多PLC通信的你

6.1 地址映射表要提前定好,最好形成文档

多台PLC之间通信,最容易乱的不是程序,是数据定义。A从站的D100对应温度,B从站的D100也对应温度,这还算好的;就怕A从站D100是温度,B从站D100是转速,没个统一文档,联调的时候就是一场灾难。我现在的习惯是开工前先做一张全局地址映射表,每台设备占用哪些寄存器区间、每个地址对应的信号名称、数据类型、读写方向全部列清楚,PLC程序、上位机变量表都按这张表来,谁改谁申请,改完必须写备注。表一旦定了,现场调试的沟通成本能降一半。

6.2 字节序问题:数据读上来了,但数值不对

Modbus使用大端字节序,西门子PLC本身也是高字节在前,理论上不用折腾。但很多上位机组态软件、第三方设备默认按小端处理,结果读上来的Int、Real经常高低字节颠倒,数值奇奇怪怪。遇到这种情况,可以在PLC侧把目标数据复制一份到交换区,在交换区里对每个字做字节交换,把换好序的数据放进保持寄存器区给上位机读;也可以在组态软件里勾选字节交换选项,看哪个方便用哪个。这里有个原则要记住:先搞清楚是数据是谁的字节序问题,再决定在PLC里换还是在上位机里换,千万别两边都换,换完等于白换,数据又倒回去了。

6.3 与变频器、仪表共用一个ModbusTCP网络

这个网络里如果还挂着ATV930之类的变频器,记住一个原则:变频器本身也是ModbusTCP从站,1200主站可以用MB_CLIENT去轮询它,只要按照变频器手册里的寄存器映射表填MB_DATA_ADDR就行,地址不是自己随意定义的。这样一来,一套主站程序就能把PLC从站、变频器、智能仪表全部统一管理,现场看起来设备杂,但通讯架构其实很干净。这也是为什么我对ModbusTCP这个方案越来越依赖,跨品牌跨设备的场景它确实最省心。

最后分享一个我在交付前必做的小动作:所有从站PLC和主站PLC,我都会在程序里加一个专门的心跳字,从站每500毫秒把自己的心跳值加1,主站轮询时检查这个心跳值是否在推进。如果连续几次读回的心跳值都不变,就认为该从站通信异常,上位机立即弹提示。这个机制成本极低,但对多设备项目的稳定性判断特别有用,通信卡没卡、断没断,一眼就能看出来。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询