找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7166|回复: 1
打印 上一主题 下一主题
收起左侧

运用VC#编程通过MPI方式与西门子S7系列PLC通讯

[复制链接]
跳转到指定楼层
楼主
ID:104287 发表于 2016-1-31 02:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
运用VC#编程通过MPI方式与西门子S7系列PL;大家只要找到西门子的ProDave中的动态连接库;由于W95_S7.DLL是用C语言编写的,很多函;一、C#中调用DLL库的方法;1、在名称空间之前使用:;usingSystem.Runtime.Inte;2、导入每一个库函数,均要在函数声明之前使用属性;[DllImport("w95_s7.;譬如

运用VC#编程通过MPI方式与西门子S7系列PLC通讯 西门子S7300/400系列的PLC没有公开通讯协议,但西门子公司提供的ProDave软件公开了一系列库函数,使用计算机高级语言调用这些函数,可实现以MPI的方式与PLC通讯。当今的高级语言VC#有着非常高效的开发手段,在把基础类库、标准模块都编好的情况下,开发监控界面的速度比WinCC慢不了多少,但灵活性却是WInCC无法比的。

大家只要找到西门子的ProDave中的动态连接库:W95_S7.DLL,并把它注册到你的计算机即可(当然,你若有一套完整的ProDave安装程序,安装即可自动注册),然后在C#这边编程调用,下面来讲解如何在C#中调用动态库。

由于W95_S7.DLL是用C语言编写的,很多函数接口不适用于C#,因此我们可以创建一个C#类库,把这些函数进行封装,每次开发监控界面调用此类库即可。

一、 C#中调用DLL库的方法

1、 在名称空间之前使用:

using System.Runtime.InteropServices; //用于调用动态库的接口,一定要引用

2、 导入每一个库函数,均要在函数声明之前使用属性字段:

[DllImport("w95_s7.dll")]

譬如与PLC建立连接的库函数load_tool(),应使用如下的方式进行声明:

[DllImport("w95_s7.dll")]

private extern static int load_tool(byte nr,string device,byte[,] adr_table);

二、 ProDave中的重要库函数介绍

1、 与PLC建立通讯连接的库函数:load_tool()

该函数必须在其他所有函数调用之前被调用,在C中的声明为:int load_tool(int nr,char* device,char* adr_table);由于C#在安全模式下不容许使用指针,因此我们把它转换成C#模式:

private extern static int load_tool(byte nr,string device,byte[,] adr_table);

参数 nr: 指定连接号1-4,一般设为1

device: 设备名称,西门子的示例是设为"s7online",测试时,若改成其他名称好像连不上。

adr_table: 一个二维数组,指定一系列连接参数,依次为:MPI地址、保留为0、CPU槽号、CPU机架号。在一个MPI网络中若有多个CPU时,可指定一个以上的连接列。最后一列的参数的MPI地址应制定为0,以标志参数列结束。 e.g.一个MPI网中有两个CPU,他们的MPI地址分别为2和3,槽号均为2,机架号均为0,则可按如下方式调用: byte[,]

bt={{2,0,2,0},{3,0,2,0},{0,0,0,0}};

int err=load_tool(1, "s7online",bt);

注:ProDave中的所有库函数均返回整数数据,为0表示调用该函数成功,为其他十进制数时,可以查找西门子文档,看是什么错误。

可以看出,上面的函数不利于我们使用,我们可对他进行封装:

<1>、在类之前声明用于传递参数列表的结构:

#region 定义与外部联系的结构变量

///

/// 定义MPI链接参数

///

public struct ConnectionInfo{

///

/// 定义CPU的MPI地址

///

public byte Addres;

///

/// 定义CPU的机架号

///

public byte Rack;

///

/// 定义CPU的槽号

///

public byte Slot;

}

#endregion

<2>、编写实现上述功能的公有方法:

#region 与动态库函数相对应的公开函数

///

/// 建立连接,同一个连接只容许调用一次

///

/// 连接号1-4

/// 指定链接参数

/// 返回10进制错误号,0表示没有错误

public static int Open(byte cnnNo,ConnectionInfo[] cnnInfo){ int err;

//传递参数不正确

if(cnnInfo.Length<=0){

return -1;

}

byte[,] btr=new byte[cnnInfo.Length+1,4];

//转换链接表

for(int i=0;i<CNNINFO.LENGTH;I++){

btr[i,0]=cnnInfo[i].Addres;

btr[i,1]=0;

btr[i,2]=cnnInfo[i].Slot;

btr[i,3]=cnnInfo[i].Rack;

}

btr[cnnInfo.Length,0]=0;

btr[cnnInfo.Length,1]=0;

btr[cnnInfo.Length,2]=0;

btr[cnnInfo.Length,3]=0;

//调用初始化函数

err=load_tool(cnnNo,"s7online",btr);

return err;

}

#endregion

这样,我们需要打开连接时,可以使用如下方式:

ConnectionInfo[] cnn=new ConnectionInfo[2];

Cnn[0] .Addres=2;

Cnn[0].Slot=2;

Cnn[0].Rack=0;

Cnn[1] .Addres=3;

Cnn[1].Slot=2;

Cnn[1].Rack=0;

int err=Open(1,Cnn);

2、 断开连接的unload_tool()函数

该函数与load_tool()正好相反,用于断开与PLC的连接,一般在退出组态软件之前调用,该函数没有参数,C#声明方式如下:

private extern static int unload_tool();

3、 激活某一个连接的函数new_ss()

该函数用于设定与MPI网中的哪一个CPU通讯,其参数与load_tool中的参数adr_table所传递的连接参数顺序对应,譬如针对上例:new_ss(1)则激活第一个连接,即与MPI地址为2的PLC通讯,类似的new_ss(2)则激活与MPI地址为3的PLC通讯。若激活的连接在MPI网中没有,则返回错误号517。 C#声明方式如下:

private extern static int new_ss(byte no);

4、 读取PLC中的M字节的函数在C#中声明方式如下:

private extern static int m_field_read (short no,short anzahl,ref long buffer);

参数 no : 指定M字节号,譬如要读取MB10的值,则指定no等于10

Anzahl :指定读取的字节数,譬如需要读取MB10至MB14之间的值,则可指定为5

Buffer : 返回获取的值,这是一个十进制的值,如果需要获取某一个M位的状态,需要把它转换成二进制,后面有介绍。

5、 向PLC中的M字节写入值在C#中声明方式如下:

private extern static int m_field_write(short no,short anzahl,ref

long buffer);

参数 no和anzahl与m_field_read的一样,而buffer指定的是向PLC中写入的值。

例如:向MB15中写入值3,即将m15.0和m15.1强制为1,可调用函数如下: int err= m_field_write(15,1,3);

三、 ProDave中的其他一些函数的C#声明方式如下:

///

/// 读取Output值

///

/// 指定QB号

/// 指定有多少个QB字节需要读出

/// 返回读出的值

///

[DllImport("w95_s7.dll")]

private extern static int a_field_read (int no,int anzahl,ref long buffer);

///

/// 向Output写入值

///

/// 指定QB号

/// 指定有多少个QB字节需要写入

/// 指定写入值

///

[DllImport("w95_s7.dll")]

private extern static int a_field_write (int no,int anzahl,ref long buffer);

///

/// 获取PLC的运行状态

///

/// 返回0或者1,0表示Run;1表示Stop或者Restart

///

[DllImport("w95_s7.dll")]

private extern static int ag_zustand (ref byte buffer);

///

/// 测试指定的DB块是否存在

///

/// 返回一系列块的存在状态,=0不存在,!=0存在

///

[DllImport("w95_s7.dll")]

private extern static int db_buch (ushort[] buffer);

///

/// 从DB中读取数据

///

/// 指定DB块号

/// 指定读取的起始字序号,=0表示DBW0,=1表示DBW2

/// 指定读取的对象有多少个字

/// 返回值

///

[DllImport("w95_s7.dll")]

private extern static int db_read(int dbno, int dwno, ref int anzahl, ref long buffer);

///

/// 向DB中写入数据

///

/// 指定DB块号

/// 指定写入的起始字序号,=0表示DBW0,=1表示DBW2

/// 指定写入的对象有多少个字

/// 写入值

///

[DllImport("w95_s7.dll")]

private extern static int db_write(int dbno, int dwno, ref int anzahl, ref long buffer);

///

/// 读取Input的值

///

/// 指定IB号

/// 指定有多少个IB字节需要读出

/// 读取返回的值

///

[DllImport("w95_s7.dll")]

private extern static int e_field_read (int no,int anzahl,ref long buffer);

///

/// 获取MB变量的位状态值

///

/// 指定M字节号

/// 指定位号,范围为0-7

/// 返回值,>0表示该位为1,=0表示该位为0

///

[DllImport("w95_s7.dll")]

private extern static int mb_bittest(short mbno,short bitno,ref short retwert);

///

/// 复位MB变量的位状态

///

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:199676 发表于 2017-5-11 19:32 | 只看该作者
有更新更简单的解决办法,这个可下载源代码:
http://blog.sina.com.cn/s/blog_16d7d3ecb0102x1z5.html
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表