西门子S7-200 PLC通过MODBUS RTU协议实现主从通讯完整指南
1. 项目概述与核心价值
最近在整理一个老项目的技术文档,又看到了当年用两台西门子S7-200 PLC通过MODBUS RTU协议“手拉手”通讯的案例。这个场景在小型自动化系统、分布式IO控制或者老旧设备改造里太常见了。很多朋友一听到“通讯”就觉得头大,又是协议又是地址,还要接线调参数,感觉门槛不低。其实,只要你手里有两台S7-200(或者S7-200 SMART),一根屏蔽双绞线,再花上半小时理解清楚逻辑,自己动手完全能搞定。这个方案的核心价值在于,它用最低的成本和最简单的配置,实现了两台独立PLC之间的数据交换,比如一台控制主流程,另一台负责采集远程的温湿度或开关量信号,然后汇总给主站,省去了昂贵的通讯模块和复杂的网络配置。
简单来说,这就是一个典型的“一主一从”通讯架构。一台PLC作为主站(Master),主动发起请求;另一台作为从站(Slave),被动响应。它们通过最经典的RS-485物理接口,采用MODBUS RTU这种高效、可靠的串行通讯协议来传递数据。对于S7-200而言,其本体集成的PPI口(也就是那个九针D型口)本身就支持RS-485信号,所以我们连额外的通讯模块都不需要,直接连线就能干。接下来,我会从硬件接线、软件配置、程序编写到调试排错,把整个流程掰开揉碎了讲清楚,保证你看完就能上手实操。
2. 硬件连接与电气准备
硬件是通讯的基础,线接错了或者干扰没处理好,软件调出花来也没用。这一部分咱们把物理层的事情彻底弄明白。
2.1 RS-485接线原理与实操
S7-200的通讯口是标准的RS-485接口,遵循两线制半双工模式。所谓“两线”,就是指数据线A(正)和B(负)。在S7-200的九针口上,对应的是3号脚(B-或D-)和8号脚(A+或D+)。这里有个关键点:西门子的标注有时会让初学者困惑,记住一个原则——“A对A,B对B”。即从站PLC的A+(8脚)接到主站PLC的A+(8脚),从站的B-(3脚)接到主站的B-(3脚)。这就是最简单的直连方式。
注意:务必使用屏蔽双绞线,并且将屏蔽层在PLC端单点接地。这是抗干扰的黄金法则。工业现场电磁环境复杂,普通的平行线就是天线,会把各种干扰信号引入通讯,导致数据错乱甚至端口损坏。双绞线可以抵消大部分共模干扰,屏蔽层则负责引流。
除了数据线,还需要连接信号地(参考电位)。S7-200的5号脚是逻辑地(M),虽然理论上在短距离、共地良好的情况下可以不接,但为了系统的长期稳定,我强烈建议你把两台PLC的5号脚也连接起来。这能确保双方有一个共同的参考电位,避免因电位差导致信号误判。
接线清单与步骤:
- 准备材料:一段足够长的屏蔽双绞线(如RVSP 2×0.75mm²)、两个九针D型插头(孔座,焊线式或螺丝压接式均可)、热缩管、剥线钳。
- 制作线缆:剥开线缆,你会看到两组双绞线(通常为红白一对,蓝白一对)和一个裸露的屏蔽网。我们只用其中一对双绞线。
- 将其中一根芯线(例如红色)两端都焊接到D型头的第8脚(A+)。
- 将与之双绞的另一根芯线(例如白色)两端都焊接到D型头的第3脚(B-)。
- 将屏蔽网拧成一股,两端分别焊接到D型头的金属外壳或专用的屏蔽层压接片上。注意,屏蔽层只能在控制柜一侧做可靠接地,另一端悬空(用绝缘胶带包好),避免形成地环路。
- 连接PLC:将做好的两个插头分别插入两台S7-200的PORT0或PORT1口。
- 检查与固定:确保接线牢固,无虚焊或毛刺短路。用扎带固定好线缆,避免接头受力。
2.2 终端电阻与偏置电阻的应用场景
如果你的通讯距离超过50米,或者现场干扰特别严重,那么终端电阻和偏置电阻就需要考虑了。这不是必选项,但却是解决疑难杂症的“特效药”。
- 终端电阻:RS-485总线在高速信号传输时,会在电缆末端产生信号反射,造成波形畸变。在总线的最远端两个节点的A+与B-之间并联一个120欧姆的电阻,可以吸收反射信号,匹配电缆的特性阻抗。对于只有两个节点的系统,你可以在两台PLC的通讯口上各并联一个120欧姆电阻,或者只在其中一台上加。我个人的习惯是,距离超过100米就加上,有备无患。电阻的功率1/4瓦就够了。
- 偏置电阻:也叫上拉/下拉电阻。当总线处于空闲状态(没有设备发送数据)时,A和B两线的电压差可能处于一个模糊区间,导致接收器误判为有数据。为了将空闲状态稳定在逻辑“1”(即A-B > +200mV),我们通常在A+线上拉一个电阻到+5V(上拉),在B-线下拉一个电阻到GND(下拉)。典型值在560欧姆到1k欧姆之间。S7-200的一些型号内部可能已有处理,但外接偏置电阻是增强总线稳定性的有效手段,尤其在节点数少、距离长时。
实操中,对于两台PLC的短距离通讯,你可以先不加这些电阻,如果通讯不稳定再加也不迟。但了解其原理,能让你在出问题时多一个排查方向。
3. 软件配置与主从站设定
硬件连好了,相当于修好了路。接下来要制定交通规则,也就是在STEP 7-Micro/WIN软件里告诉PLC,谁是交警(主站),谁是司机(从站),以及车辆如何识别彼此。
3.1 从站PLC的配置
从站的配置相对简单,核心是启用MODBUS从站协议并设置从站地址。
- 新建项目与设置PLC类型:打开STEP 7-Micro/WIN,新建项目,根据你实际的CPU型号(如CPU 224 CN)进行选择。
- 调用MODBUS从站指令库:西门子提供了标准的MODBUS指令库,需要先添加。在指令树中,找到“库”(Libraries),右键选择“添加/删除库”(Add/Remove Libraries)。在弹出的对话框中,找到并添加“MBUS_CTRL”和“MBUS_SLAVE”这两个库。如果你的软件里没有,可能需要从西门子官网下载对应版本的库文件。
- 编写从站初始化程序:在主程序(OB1)中,我们需要调用两个关键子程序。
- MBUS_CTRL:用于初始化并监控MODBUS通讯。这个指令只需要在程序开始时执行一次,通常放在第一个扫描周期。其关键参数如下:
Mode: 设置为1,表示启用MODBUS协议。Baud: 设置波特率,必须与主站一致。常用9600、19200、38400等。波特率越高速度越快,但抗干扰能力越差,距离也越短。初次调试建议用9600。Parity: 奇偶校验。0-无校验;1-奇校验;2-偶校验。必须与主站一致。通常选择无校验(0)或偶校验(2)。Port: 通讯端口号。0表示PORT0,1表示PORT1。根据你的实际接线端口选择。Timeout: 超时时间(毫秒)。主站等待从站响应的最长时间,一般设为1000(1秒)即可。Done/Error: 输出参数,用于指示指令执行状态和错误代码。
- MBUS_SLAVE:这是从站协议服务程序,必须每个扫描周期都被调用,用于处理来自主站的请求。它的核心参数是
Slave,即从站地址。设置一个在MODBUS网络中唯一的地址,范围1-247。例如,设为2。其他参数如HoldStart(保持寄存器起始地址映射到PLC的V区地址)等,用于定义数据交换区,我们稍后详细解释。
- MBUS_CTRL:用于初始化并监控MODBUS通讯。这个指令只需要在程序开始时执行一次,通常放在第一个扫描周期。其关键参数如下:
从站程序段示例(梯形图):
这段程序的意思是:上电后初始化端口0为MODBUS,波特率9600,无校验。然后每个周期都以地址2响应MODBUS请求,并指定了不同的V存储区映射给MODBUS的四种数据类型。
3.2 主站PLC的配置与编程逻辑
主站PLC需要主动发起读写请求。我们使用MBUS_MSG指令库来实现。主站程序的设计核心是分时轮询,即同一时刻只能有一条MBUS_MSG指令被激活。
- 添加主站指令库:同样需要添加库,主站主要用到“MBUS_CTRL”(端口初始化,与从站相同)和“MBUS_MSG”(消息发送)。
- 编写主站程序结构:
- 初始化:同样使用
MBUS_CTRL初始化通讯端口,参数(波特率、校验等)必须与从站严格一致。 - 组织轮询:这是编程的关键。你需要规划好要读写从站的哪些数据。例如,你想读取从站地址2的10个保持寄存器(对应从站V区的一段数据),然后向从站写入2个线圈状态。
- 你不能同时执行这两个请求。标准的做法是使用一个状态机或者顺序控制继电器(S)来管理。例如:
- 状态1:激活第一条
MBUS_MSG(读命令),等待其完成(Done位上升沿)。 - 状态1完成后,复位第一条指令的使能,进入状态2:激活第二条
MBUS_MSG(写命令),等待完成。 - 状态2完成后,回到状态1,如此循环。同时,要检查每条指令的
Error输出,以便在通讯失败时进行错误处理或重试。
- 状态1:激活第一条
- 初始化:同样使用
主站轮询程序逻辑详解:
假设我们要从地址为2的从站,读取其保持寄存器起始地址为40001(MODBUS地址格式,对应从站HoldStart映射的V区)开始的5个字(10个字节),放到主站的VB1000开始的位置;同时,将主站QB0的状态(8个位)写入到从站的线圈地址00001开始的8个位。
我们需要两条MBUS_MSG指令。
- 读指令参数:
First:使能位,由我们的状态机控制。Slave:从站地址,填2。RW:读写操作,0=读,1=写。这里填0。Addr:MODBUS寄存器地址。注意,这里要填MODBUS协议地址,而不是PLC的V区地址。对于保持寄存器(4xxxx类型),通常填入十进制地址。例如,从站映射时,&VB2000对应保持寄存器40001。那么我们要读40001开始的5个字,Addr就填40001(有些库要求填0,即偏移量,需看库说明,西门子库通常填实际MODBUS地址)。Count:要读的数据数量(字数或位数)。读5个字,填5。DataPtr:主站中存放读取结果的数据区指针。例如,&VB1000。
- 写指令参数:
RW:填1(写)。Addr:线圈地址(0xxxx类型)。写入00001开始的8个位,填00001(或填0,根据库要求)。Count:填8(位)。DataPtr:主站中存储了要写入数据的数据区指针。例如,&QB0(注意,QB0是字节,但写入线圈时,指令会自动处理位与字节的映射)。
实操心得:
MBUS_MSG指令的Done位非常重要。必须在上一条指令的Done位为1之后,才能复位其First使能,并激活下一条指令的First。否则会引起多条指令同时激活,导致通讯混乱。通常用Done位的上升沿来触发状态转移。
4. 数据地址映射与换算详解
这是MODBUS通讯中最容易出错的地方。MODBUS协议有自己的地址编码规则,而S7-200有自己的存储区(V区、I区、Q区等)。我们需要一座“桥梁”把它们对应起来,这座桥梁就是在调用MBUS_SLAVE和MBUS_MSG时设置的参数。
4.1 MODBUS协议地址类型回顾
MODBUS定义了四种基本数据类型,用不同的地址范围表示:
- 线圈(Coils):可读可写的位数据。地址范围:000001 - 065536。对应功能码01(读)、05(写单个)、15(写多个)。
- 离散输入(Discrete Inputs):只读的位数据。地址范围:100001 - 165536。对应功能码02。
- 输入寄存器(Input Registers):只读的字(16位)数据。地址范围:300001 - 365536。对应功能码04。
- 保持寄存器(Holding Registers):可读可写的字数据。地址范围:400001 - 465536。对应功能码03(读)、06(写单个)、16(写多个)。
4.2 S7-200中库指令的映射方法
西门子的MBUS_SLAVE指令通过参数将MODBUS地址映射到S7-200的V存储区。
查看之前的从站调用示例:
CALL MBUS_SLAVE, ..., 2, &VB2000, 100, &VB3000, 50, &VB4000, 100, &VB5000, 50, ...
这四个指针参数依次是:
&VB2000, 100:映射线圈(0xxxx)。将MODBUS线圈地址00001映射到从站PLC的VB2000开始的位区域。数量100表示映射100个位。注意,VB2000是一个字节,可以存8个位。100个位需要13个字节(VB2000-VB2012)。主站读写线圈00001-00100,就相当于在读写从站V2000.0 - V2012.3这些位。&VB3000, 50:映射离散输入(1xxxx)。将MODBUS离散输入地址10001映射到从站PLC的VB3000开始的位区域,共50个位。&VB4000, 100:映射输入寄存器(3xxxx)。将MODBUS输入寄存器地址30001映射到从站PLC的VW4000开始的字区域。注意,&VB4000是字节地址,但映射的是字(Word),所以VW4000对应30001,VW4002对应30002,以此类推。数量100表示100个字(200个字节)。&VB5000, 50:映射保持寄存器(4xxxx)。将MODBUS保持寄存器地址40001映射到从站PLC的VW5000开始的字区域。这是最常用的一种映射,因为可读可写。主站读写保持寄存器40001-40050,就相当于在读写从站的VW5000-VW5098。
换算示例: 主站想读取从站(地址2)的保持寄存器40010的值。
- 从站配置中,保持寄存器起始于
&VB5000,对应40001。 - 40010相对于40001的偏移量是9(40010 - 40001 = 9)。注意,MODBUS地址是1-based(从1开始),而PLC地址是0-based。
- 在从站PLC中,VW5000对应40001,那么40010就对应
VW5000 + (9 * 2) = VW5018。因为每个字占2个字节。 - 所以,主站读取40010,就是从站的VW5018这个字;主站写入40010,就是修改从站的VW5018。
注意事项:务必为映射区预留足够的、未被程序其他部分使用的V存储区。如果映射区和你程序中的其他变量地址重叠,会造成数据被意外覆盖,引发难以排查的错误。建议在数据块中为MODBUS通讯专门划分一段连续的V区。
5. 程序编写与调试全流程
理论清楚了,我们动手写一个完整的、可运行的例子。假设场景是:主站(地址1)每隔2秒读取从站(地址2)的一个模拟量值(假设已存入从站VW100),并控制从站的一个输出点(Q0.0)。
5.1 从站PLC完整程序示例
- 定义数据块(可选但推荐):在“数据块”中,为MODBUS映射区预留空间。例如:TEXT// MODBUS 映射区VB2000 到 VB2099 // 线圈映射区,100字节足够VB3000 到 VB3049 // 离散输入映射区,50字节VW4000 到 VW4098 // 输入寄存器映射区,100个字VW5000 到 VW5098 // 保持寄存器映射区,50个字// 用户程序变量VW100 // 存放模拟量值,例如AIW0转换后的结果
- 编写主程序(OB1):TEXT// 网络1:上电初始化MODBUS端口LD SM0.1CALL MBUS_CTRL, 1, 9600, 2, 0, 1000, M0.0, VB900 // 模式1,9600bps,偶校验,端口0,超时1秒。错误码存VB900。// 网络2:每个扫描周期执行从站服务LD SM0.0= L60.0 // 一个临时位,用于连接输入参数,库要求CALL MBUS_SLAVE, L60.0, 2, &VB2000, 100, &VB3000, 50, &VB4000, 100, &VB5000, 50, VB901 // 从站地址2,映射参数如前所述。状态字节VB901。// 网络3:将本地的模拟量值(例如VW100)复制到映射给主站读的保持寄存器区// 假设我们想让主站读取VW100,我们把它放到保持寄存器区的第一个字,即VW5000。LD SM0.0MOVW VW100, VW5000 // 将VW100的值传送到VW5000// 网络4:将主站写入的线圈状态(控制Q0.0)应用到实际输出// 线圈起始地址VB2000,第一个字节VB2000的bit0对应线圈00001。我们用它控制Q0.0。LD SM0.0= Q0.0, V2000.0 // 将V2000.0的状态直接赋值给Q0.0
5.2 主站PLC完整程序示例
主站程序需要实现轮询。我们使用一个简单的顺序控制继电器(S)来实现。
- 定义变量:在符号表中定义。
S_MODBUS(S0.0):MODBUS轮询状态步。Read_Done(M0.1):读指令完成标志。Write_Done(M0.2):写指令完成标志。Error_Code(VB800):存储MBUS_MSG错误码。AI_Value(VW1000):存放从从站读回的模拟量值。
- 编写主程序(OB1):程序逻辑解读:主站上电后进入S0.0步,立即触发一次读指令。读完成后(约几十毫秒),立刻进入S0.1步触发写指令。写完成后,启动一个2秒的定时器,2秒后再回到S0.0步,开始下一个轮询周期。这样,读和写是连续快速执行的,而整个轮询周期受T37控制为2秒。读指令在S0.0步内还受SM0.5控制,可以实现更频繁的读取(每秒一次),而写操作保持2秒一次。你可以根据实际需求调整这个逻辑。TEXT// 网络1:上电初始化MODBUS端口,复位状态步LD SM0.1CALL MBUS_CTRL, 1, 9600, 2, 0, 1000, M0.0, VB900 // 参数与从站一致S S0.0, 1 // 启动第一步// 网络2:状态步S0.0 - 读取从站保持寄存器40001(从站的VW5000,即其VW100的值)LD S0.0CALL MBUS_MSG, M10.0, 2, 0, 40001, 1, &VB1000, M0.1, VB800// M10.0是脉冲触发,见下文控制逻辑。从站地址2,读操作,地址40001,读1个字,存到主站VW1000。// 网络3:状态步S0.1 - 写入从站线圈00001(控制从站的Q0.0)LD S0.1CALL MBUS_MSG, M10.1, 2, 1, 1, 1, &QB0, M0.2, VB801// 写操作,线圈地址1(即00001),写1个位,数据源是主站的QB0(假设我们用I0.0的状态控制QB0的Bit0,从而远程控制从站Q0.0)。// 网络4:状态转移逻辑(核心)// 步S0.0激活时,用SM0.5(1Hz时钟脉冲)的上升沿触发读指令的First(M10.0),实现周期读取。LD S0.0EU // 检测S0.0的上升沿(首次进入)O LD // 或逻辑A SM0.5 // 与1秒时钟脉冲EU // 取上升沿= M10.0 // 触发读指令// 当读指令完成(M0.1)且无错误时,转移到下一步(写)LD S0.0A M0.1 // 读完成AN M0.0 // 且MBUS_CTRL无错误(假设M0.0是MBUS_CTRL的Done位,错误时置位)S S0.1, 1R S0.0, 1// 复位读指令的First,避免重复触发(库指令要求First是脉冲)LD M0.1R M10.0, 1// 当写指令完成(M0.2)且无错误时,转移回第一步,并加入一个2秒的延时(T37)控制轮询周期LD S0.1A M0.2AN M0.0AN T37 // 确保定时器未在计时TON T37, 200 // 启动2秒定时器LD T37 // 定时时间到S S0.0, 1R S0.1, 1R M10.1, 1 // 复位写指令的FirstR T37, 1 // 复位定时器
5.3 下载、监控与在线调试
- 分别下载程序:用编程电缆分别连接两台PLC,将编写好的主站程序和从站程序下载到对应的PLC中。下载前务必确认PLC类型和地址设置正确。
- 设置PLC地址:在系统块中,设置两台PLC的站地址(不是MODBUS地址)。例如,主站设为2,从站设为3。这用于STEP 7-Micro/WIN的编程连接,与MODBUS地址无关。MODBUS从站地址是在程序里用
MBUS_SLAVE指令设定的(本例中从站是2)。 - 在线监控:
- 分别连接到两台PLC,进入“程序状态”监控。
- 在主站PLC,观察触发
MBUS_MSG的First位(M10.0, M10.1)是否按预期脉冲触发。 - 观察
Done位(M0.1, M0.2)是否在指令执行后置位。 - 最关键的是看
Error字节(VB800, VB801)。如果为0,表示通讯成功。如果有错误代码,记下来去查手册。 - 在从站PLC,监控映射区数据(如VW5000)是否随着本地VW100的变化而变化,以及V2000.0是否随着主站写线圈操作而变化。
- 使用数据块强制与状态表:
- 可以在从站PLC的状态表中,强制改变VW100的值,然后在主站PLC的状态表中观察VW1000是否跟随变化。
- 可以在主站PLC的状态表中,强制改变QB0的值(例如将QB0设为1),观察从站PLC的Q0.0是否立即点亮。
6. 深度排查:常见错误代码与解决方法
调试不通是常态,别慌。绝大部分问题都体现在MBUS_CTRL和MBUS_MSG的Error输出字节上。下面我把常见的错误码和排查思路列成表格,方便你快速定位。
| 错误代码 (VBxxx) | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
MBUS_CTRL 错误 |
||
| 1 | 波特率/校验位设置与其他站冲突 | 检查主、从站MBUS_CTRL指令的Baud和Parity参数是否完全一致。 |
| 2 | 通讯端口号Port设置错误 |
确认PLC型号支持所选端口(如CPU 224有两个口),且接线与此端口对应。 |
| 3 | 超时时间Timeout设置过短 |
对于长距离或多从站,适当增加超时时间(如2000ms)。 |
| 4 | 模式Mode设置错误 |
确保主从站都设置为1(MODBUS协议)。PPI模式是0。 |
| 6 | 硬件故障或初始化失败 | 检查PLC通讯口是否损坏,重启PLC。检查是否有其他设备(如触摸屏)占用了该端口。 |
MBUS_MSG 错误 |
||
| 1 | 从站响应超时 | 1. 检查从站地址:Slave参数是否正确。2. 检查物理连接:A/B线是否接反、断路、短路。用万用表测A-B间电压,发送数据时应有明显波动。 3. 检查从站程序: MBUS_SLAVE指令是否每个周期都被调用?从站地址参数是否正确?4. 检查终端/偏置电阻:长距离通讯尝试增加120Ω终端电阻。 |
| 2 | 从站响应校验错误(CRC错误) | 1. 确认波特率和校验位:这是最常见原因,必须主从站一致。 2. 检查电气干扰:确保使用屏蔽双绞线,屏蔽层单端接地。远离动力线。 3. 尝试降低波特率(如从38400降到9600)。 |
| 3 | 从站响应“例外响应”(功能码错误) | 1. 检查功能码:RW参数(0读/1写)是否与操作匹配?2. 检查MODBUS地址: Addr参数是否正确?例如,试图写一个只读的输入寄存器(3xxxx)会报错。3. 检查数据数量: Count参数是否超出从站映射区范围? |
| 4 | 从站无响应(与错误1类似) | 除了错误1的排查项,还需检查主站MBUS_CTRL是否已成功初始化(Done位为1)。 |
| 5 | 主站忙,多条MBUS_MSG同时激活 |
这是主站编程最易犯的错误。确保同一时间只有一条MBUS_MSG指令的First使能位为1。用状态步或严格的顺序逻辑控制。 |
| 6 | MBUS_MSG指令参数错误 |
检查DataPtr指针地址是否有效(如&VB1000)。检查Count是否为0或过大。 |
| 7 | 从站响应长度不符 | 检查请求的Count与从站实际能提供的数据量是否匹配。 |
高级排查工具——MODBUS调试软件: 如果以上步骤都检查无误仍不通,可以借助电脑上的MODBUS调试软件(如ModScan32做主站,ModSim32做从站)来辅助定位。
- 将电脑通过USB转485适配器接入总线。
- 运行ModSim32,模拟一个从站,设置与你的S7-200从站相同的地址、波特率、校验。
- 在ModScan32中,设置主站参数,去读写模拟从站。如果能通,说明主站程序和硬件接线没问题,问题出在真实的S7-200从站上(程序或PLC本身)。
- 反之,用ModScan32去读写真实的S7-200从站。如果能通,说明问题出在主站程序上。 这个方法能迅速将问题隔离到“主站侧”或“从站侧”。
7. 性能优化与高级应用思考
当基本通讯实现后,可以考虑如何让它更可靠、更高效。
7.1 通讯效率与可靠性提升
- 优化轮询逻辑:前面的例子是顺序轮询。如果从站数据多,可以分块轮询,非关键数据降低轮询频率。使用多个定时器或计数器来组织不同的轮询任务。
- 增加通讯故障处理:不要只检查
Error代码,要设计重试机制和故障报警。例如,连续3次通讯失败,则置位一个“通讯故障”报警位,并尝试初始化端口(重新调用MBUS_CTRL)。TEXT// 网络:错误计数与复位LD M0.1 // 读完成A M0.0 // 但有错误(假设M0.0是MBUS_CTRL的错误标志,实际应看Error字节)EUINCW VW810 // 错误计数器加1LDW>= VW810, 3 // 错误达到3次= M10.2 // 触发报警CALL MBUS_CTRL, ... // 尝试重新初始化端口MOVW 0, VW810 // 复位错误计数器 - 数据一致性处理:对于多个字组成的32位浮点数或长整数,主站在读取时,从站可能正在更新该数据,导致读到“一半新一半旧”的值。解决方法是在从站程序里,将需要同步的数据复制到一个专门的“通讯映射区”。主站只从这个稳定的映射区读取。从站在更新完所有相关数据后,再用一条指令整体复制到映射区。
7.2 扩展应用:一主多从与网络拓扑
两台PLC通讯只是起点。MODBUS RTU支持一主多从(最多247个从站),这是其强大之处。
- 总线型拓扑:所有从站并联在A、B两根总线上。必须注意:
- 每个从站必须有唯一的地址。
- 总线两端(最远的两端)的从站A、B之间需要并联120Ω终端电阻。
- 从站数量多、距离远时,可能需要增加RS-485中继器来增强信号。
- 主站程序调整:主站程序需要轮询多个从站地址。可以创建一个从站地址表,用一个指针循环遍历。逻辑还是分时复用,同一时间只与一个从站通讯。
- 从站程序:每个从站的程序结构几乎一样,只需修改
MBUS_SLAVE指令中的Slave地址参数为各自唯一的地址。
最后,我个人在多年调试中最大的体会是:耐心和细致大于一切。MODBUS RTU通讯本身不复杂,但任何一个细节的疏忽(如波特率差一位、线接反、地址设错、映射区重叠)都会导致失败。准备好万用表、做好文档记录(接线图、参数表、地址映射表),按照“硬件->从站配置->主站编程->分段调试”的步骤一步步来,你一定能让这两台老伙计顺畅地“对话”。当状态表里看到数据如你所愿地跳动时,那种成就感,就是工控人最简单的快乐。