前言
在工业自动化领域,西门子PLC(可编程逻辑控制器)因其卓越的性能和可靠性而被广泛应用。然而,高效的PLC通信往往是实现系统最佳性能的关键所在。无论是数据采集、设备监控还是复杂的工业控制应用,良好的通信策略都能显著提升系统的整体效率。
西门子PLC提供了丰富的通信功能和多种协议支持,但许多工程师在实际操作中仍然面临各种挑战。从配置复杂的网络设置到处理不同设备之间的兼容性问题,每一个环节都可能成为效率提升的瓶颈。
本文将深入探讨一些关键的技术要点和实用技巧,帮助你在西门子PLC通信方面取得突破。通过掌握这些关键点,你不仅能够简化通信配置流程,还能大幅提升系统的响应速度和稳定性,最终实现工作效率的翻倍增长。
接下来会通过S7NetPlus通信库的源码来分析。
项目源码
连接过程
西门子PLC的S7协议基于TCP/IP实现,但其连接过程不仅仅是简单的TCP连接。
具体来说,在完成标准的TCP三次握手之后,还需要进行两次额外的握手步骤:
第一次握手:用于确认双方的连接状态,确保通信双方都准备好开始数据传输。
第二次握手:用于设置连接参数,确保后续的数据交换能够顺利进行。
详细步骤如下:
TCP三次握手:
客户端发送SYN(同步序列编号)到服务器。
服务器回应SYN-ACK(同步序列编号确认)。
客户端再发送ACK(确认),完成TCP连接建立。 S7协议的两次握手:
第一次握手:客户端向PLC发送连接请求,PLC确认收到并准备就绪。
第二次握手:客户端和PLC交换必要的连接参数,配置通信细节。
通过这两步额外的握手过程,S7协议确保了连接的可靠性和稳定性,为后续高效的数据传输奠定了基础。
PDUSize
任何通信协议都有一次性读取数据的限制。
例如,Modbus 一次性最多可以读取 125 或 127 个寄存器,而三菱 PLC 一次性最多可以读取 960 个字。这种读取限制主要由 PDU(Protocol Data Unit,协议数据单元)大小 决定。
西门子 PLC 的 PDU Size
对于西门子 PLC 来说,不同型号的 PDU Size 不同:
S7-200 Smart / S7-1200 / S7-300:通常是 240 字节。
S7-400:通常是 480 字节。
S7-1500:通常是 960 字节。
这些值是由硬件特性决定的,因此在选择和配置 PLC 时需要特别注意。
如何获取 PDU Size?
幸运的是,在与西门子 PLC 建立连接的过程中,可以通过第二次握手来获取 PDU Size。具体来说,在第二次握手过程中,PLC 会返回其支持的最大 PDU Size。这意味着你不需要手动查找或计算,只需正确解析握手响应即可获得该信息。
总结
PDU Size 是决定一次性能传输多少数据的关键参数。
不同型号的西门子 PLC 具有不同的 PDU Size。
在建立连接时的第二次握手过程中,PLC 会自动返回其最大 PDU Size。
我们可以看到,它是由第二次握手返回报文的最后两个字节表示的。
如果不看源码,我们也可以在建立PLC连接之后,通过PLC通信对象的MaxPDUSize属性获取该值。
我们连接不同型号的PLC的输出结果不同,结果如下:
但是MaxPDUSize并不是一次性可以读取的字节数,是报文的长度,实际读取的字节数,需要在此基础上减去包头的18个字节,因此S7-200Smart/S7-1200/S7-300一次可以读取222个字节,S7-400一般是462个字节,S7-1500一般是942个字节。
底层分包
刚刚我们提到S7-200Smart一次性只能读取222个字节,但是实际我们在使用S7NetPlus通信库的时候,读取数量却可以超过这个值。
比如我们读取V区从0开始的1000个字节。
我们可以看到是能读取到的,这是什么原因呢?我们来看下ReadBytes底层的代码:
我们可以看到,这个是通信库底层做了分包处理,比如读取1000个字节,会分成222-222-222-222-112五次去读,然后将结果拼到一起返回,虽然可以读取,但是耗时仍然会是单次通信周期的五倍。
通信速率
西门子S7的通信速度跟PLC程序大小,PLC通信负载设置以及PLC型号都有一定关系,我们可以测试一下。
从结果来看,大概在2-10ms之间,不同PLC会有一定区别。
S7通信协议并不是最快的,如果我们想要更快的通信效率,可以采用开放式TCP通信。
地址不连续
如果我们的下位机地址不连续,我们可能需要分很多组来读取。
S7协议具有这样的优势:S7协议支持一次性读取多个不连续的地址区间。
比如我们想同时读取I区从0开始的10个字节,Q区从0开始的10个字节,M区从0开始的10个字节以及DB1从0开始的10个字节,我们可以这样编写代码:
读取结果如下所示:
List< DataItem>的最大数量是19。由于这种方式,每个Item的参数会消耗一定的报文,因此所有Item的Count之和要比222/462/942更少一些,因为总报文长度仍然受PUDSize的限制。
具体数量是每多一个Item,读取字节数要减少4,对于案例中的4个Item,最多只能读取222-4*(4-1)=210个字节。
ReadClass
通信库底层有一个ReadClass方法,这个方法可以直接读取一些连续的变量。DB1中有很多变量,我们想要读取全部或者部分变量的值,可以使用ReadClass方法:
ReadClass方法的原型如下:
首先,我们需要准备好一个类,这个类必须与DB块变量的类型结构一样,并且顺序也要保持一致:
cs
public class PlcData
{
public bool InPump1State { get; set; }
public bool InPump2State { get; set; }
public bool CirclePump1State { get; set; }
public bool CirclePump2State { get; set; }
public bool ValveInState { get; set; }
public bool ValveOutState { get; set; }
public bool SysRunState { get; set; }
public bool SysAlarmState { get; set; }
public byte[] SpareState { get; set; } = new byte[2];
public float PressureIn { get; set; }
public float PressureOut { get; set; }
public float TempIn1 { get; set; }
public float TempIn2 { get; set; }
public float TempOut { get; set; }
public float PressureTank1 { get; set; }
public float PressureTank2 { get; set; }
public float LevelTank1 { get; set; }
public float LevelTank2 { get; set; }
public float PressureTankOut { get; set; }
}
然后直接调用ReadClass方法即可,填入DB号为1,起始地址为0:
cs
PlcData plcData =siemens.ReadClass<PlcData>( 1, 0);
我们可以看到,可以直接读到所有变量的值,意味着ReadClass方法中不仅包含了读取,也包含了数据解析的过程。
与ReadClass类似的还有一个ReadStruct方法用来读取结构体,大家可以自己研究一下。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
作者:上位机付工
出处:mp.weixin.qq.com/s/aLXlaBlTxW-sUrM9oHcXzA
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!