基于Libnodave的上位机与西门子S7200PPI通讯
摘要
关键词
LIBNODAVE; 上位机; S7200 PLC; PPI
正文
中图分类号: 文献标志码:A
Communication between PC and Siemens S7200 according to PPI based on Libnodave
XU Shi-ya 1,WU Jian-Yong1,YANG Jian2*
(1..Nanjing Iron and Steel Co., Ltd., Nanjing 110819, Nanjing; 2. School of Information Science and Engineering, Northeastern University, Shenyang 110819, Liao Ning. Corresponding author: YANG Jian,
Abstract:This paper proposes a communication method based on LIBNODAVE for PC-side host computer and Siemens S7200PLC. The specific implementation of PPI communication between the upper computer monitoring software based on VB.net and S7-200 series PLC is given. Analysis and test results show that this communication method is feasible, low-cost, and scalable.
Key words:LIBNODAVE; PC; S7200 PLC; PPI
西门子PLC在工业领域具有广泛的应用,其S7200系列主要应用于小型控制系统中,有时需要通过上位机进行监控,以监视过程运行状态、调节设定及进行其它操作。S7200PLC监控可采用的方式通常包括西门子WinCC、PRODAVE、第三方组态软件如组态王、OPC Server等。通讯接口形式为PPI或工业以太网等。但这些通讯方式通常需要安装具有较高授权费用的软件, 甚至需要配装相应硬件。因此,本文提出一种基于LIBNODAVE的开源免费的通讯方案。
本文首先对LIBNODAVE 进行了简要介绍,然后结合C#语言给出基于LIBNODAVE的西门子S7200上位机的开发方法。
1 LIBNODAVE概述
LIBNODAVE 是德国人Thomas Hergenhahn 开发的一款可与西门子S7-200/300/400 系列PLC 进行通讯的开源、免费的函数库, 遵循GNU 库公用许可证版本2 及以上。它可运行在Windows、Linux 及Unix 操作系统上。其开发工作始于2002年,目前版本为2014 年发布的LIBNODAVE-0.8.5.1, 可从Sourceforge网站上下载到最新的版本。LIBNODAVE 提供了与西门子S7-200、300 和400 系列PLC 以及与上述西门子PLC 兼容的PLC 产品(如艾莫迅PLC)的进行数据交换。它可以访问通过PLC 程序能访问的存储区域:位存储区、数据块、输入/输出映像区、定时器和计数器等。另外,LIBNODAVE 还可以读取PLC 程序中的功能块。支持的西门子通讯硬件设备有MPI 适配器、TS 适配器、IBH/MHJ-NetLink、CP243/343/443 以及内建了以太网支持的PLC。目前,LIBNODAVE 已经可以结合C、C++、C#、VB.NET、VB、Pascal、Delphi、Perl 来使用,LIBNODAVE 的软件包里提供了相应的测试例子,但是功能并不完善。此外,LIBNODAVE 还有一个不足是开发文档不够完整,并且比较分散,有些地方需要结合源码来理解。虽然LIBNODAVE 版本还没达到1.0,但是其当前的功能已足够满足一般的应用了, 而且可以进一步通过Tk、Qt 等跨平台GUI 软件将LIBNODAVE 的上位机功能拓展到嵌入式系统中去,从而进一步降低成本和扩大它的应用范围。
2 基于LIBNODAVE的建立上位机与S7200的PPI通讯连接
在.net下建立与西门子S7200PLC的通讯,首先最好进行一定的封装,本文采用C#语言,封装的类为PLCItem。主要参数设置及连接相关函数定义如下:
功能 | 主要代码 |
引用 | using System.Runtime.InteropServices;//DllImport调用非托管DLL函数需要该引用支持 |
数据项定义 | private libnodave.daveOSserialType fds; private libnodave.daveInterface di; public libnodave.daveConnection dc; static int localPPI = 0; static int plcPPI = 2; private int _errorCode; private bool _connected; |
连接PLC | public bool ConnectPLC(string portnum, string baud, int parity) { if (_connected) disconnectPLC(); fds.rfd = libnodave.setPort(portnum, baud, parity ); fds.wfd=fds.rfd; if (fds.rfd > 0) { di = new libnodave.daveInterface(fds, "IF1", localPPI, libnodave.daveProtoPPI, libnodave.daveSpeed187k); di.setTimeout(1000000); dc = new libnodave.daveConnection(di, plcPPI, 0, 0); if (0 == dc.connectPLC()) { _connected = true; return true; } } return false; } |
断开PLC | public void disconnectPLC() { if (dc != null) { dc.disconnectPLC(); } libnodave.closePort(fds.rfd); _connected = false; } |
3 读写数据的核心函数方法
读数据 | public int ReadBytes(AreaType area, int db, int address, int numBytes, byte[] buf) { if (area !=AreaType.daveDB) db = 0; return dc.readBytes((int)area, db, address, numBytes, buf); } |
写数据 | [DllImport("libnodave.dll"/*, PreserveSig=false */ )] public static extern void davePut8At(byte[] b, int pos, int v); [DllImport("libnodave.dll"/*, PreserveSig=false */ )] public static extern void davePut16At(byte[] b, int pos, int v); [DllImport("libnodave.dll"/*, PreserveSig=false */ )] public static extern void davePut32At(byte[] b, int pos, int v); [DllImport("libnodave.dll"/*, PreserveSig=false */ )] public static extern void davePutFloatAt(byte[] b, int pos, float v);
public bool WriteBytes(AreaType area, int db, int address, int numBytes, byte[] buf) { if (area != AreaType.daveDB) db = 0; _errorCode = dc.writeBytes((int)area, db, address, numBytes , buf); return 0 == _errorCode; } |
相关数据区常量定义 | public enum AreaType : int { daveSysInfo = 0x3, // System info of 200 family daveSysFlags = 0x5, // System flags of 200 family daveAnaIn = 0x6, // analog inputs of 200 family daveAnaOut = 0x7, // analog outputs of 200 family daveP = 0x80, // direct peripheral access daveInputs = 0x81, // Output daveOutputs = 0x82, // Input daveFlags = 0x83, // M memory daveDB = 0x84, // data blocks daveDI = 0x85, // instance data blocks daveLocal = 0x86, // not tested daveV = 0x87, // don't know what it is daveCounter = 28, // S7 counters daveTimer = 29, // S7 timers daveCounter200 = 30, // IEC counters (200 family) daveTimer200 = 31, // IEC timers (200 family) } |
4 上位机编程范例
连接PLC: if (plc1.ConnectPLC("COM3", "9600", 'E')) { MessageBox.Show("PLC连接成功!"); }//串口号根据实际情况设置 else MessageBox.Show("PLC连接失败!"); |
断开PLC连接:if (plc1.connected) plc1.disconnectPLC(); |
读取MB5,MW6,MD8,MD14,数据类型分别为Byte,Int, Dint, Real: byte[] buf=new byte[11]; plc1.ReadBytes(AreaType.daveFlags, 0, 5, 11,buf); byte MB5 = (byte)plc1.dc.getS8(); short MW6 = (short) plc1.dc.getS16(); int MD8 = plc1.dc.getS32(); float MD14 = plc1.dc.getFloatAt(9); 读位数据: bool M5_3 = 0!=(MB5 & (1 << 3)); //获取M5.3 |
写入MB5,MW6,MD8,MD14: byte[] buf = new byte[11]; byte MB5 = 8; short MW6 =2; int MD8 = 3; float MD14 =4; PLCItem.davePut8At(buf, 0, MB5); PLCItem.davePut16At(buf, 1, MW6); PLCItem.davePut32At(buf, 3, MD8); PLCItem.davePutFloatAt(buf,9, MD14); plc1.WriteBytes(AreaType.daveFlags, 0, 5, 20, buf); 写位数据: MB5 |= (byte)((MB5_3 ? 1 : 0) << 3);//设置M5.3 |
5 结论
本文提出一种基于Libnodave的上位机与西门子S7200PLC进行PPI通讯的开源、免费方案。该方案适用于使用西门子S7200或兼容S7200的其他PLC的场合,主要用于相应硬件的低成本、灵活度高的监控软件的开发。
参考文献
[1] 孙书欢, 孔祥成, 吴雪婷. 西门子PLC设备开源驱动库libnodave的研究与改进[J]. 核电子学与探测技术, 2013(07):64-68.
[2] 周广颖, 张金金, 闫隆. 基于LIBNODAVE的上位机与西门子PLC的通信[J]. 微计算机信息, 2010(31):36-38.
[3] 魏立新, 冯曦, 王洪庆, et al. LIBNODAVE在PLC上位机监控软件中的运用[J]. 仪表技术与传感器, 2014(07):86-88.
...