1,虚拟机...系统Win10...里面安装了VS.
2,本机...系统Win10...里面安装了博图15.
3,转换软件:NetToPLCSIM.
4,本机和虚拟机连接同一个路由器.注意:
5,设置虚拟机为桥接模式,并且选择连接了路由器的网卡.
6,网卡设置自动获取IP地址,并且禁止,启用,让网卡获取IP地址.
正常情况,两台机器能够互相ping 成功!,则基本准备,网络配置完毕.否则,检查防火墙.我没遇到,就没弄.
然后打开博图,必须要进行get/put打勾!
2,GET/PUT 打勾
3,模拟的时候,先点击模拟,但是不要下载PLC.
4,打开Nettoplcsim软件:(其中有 stop server start server 默认即可),注意,一定要先打开这个软件.
5,打开添加对接画面:点击PLCSIM IP.注意,如果先模拟再添加就不会显示.
6,打开PLC模拟器,并下载PLC 点击 PLCSIM IP:这个很关键,必须它自己跳出来的.选择PLC.
7,选择 NET IP ADDR:
8,ok注意 rack和slot选择
9,在虚拟机的VS里面测试通讯
internal static void TestS7() { Plc plc = new Plc(CpuType.S71200, "192.168.3.62", 0, 1); try { log("begin open plc"); plc.Open();//一个PLC异步函数,注意,异步函数的异常只能通过 log("plc is open!"); } catch(Exception e) { log(e.Message); } }
结果:
10,尝试读取写入byte[]数组:
RecipePLC 数据类型具有:(配方)
一个字符串: string[20] 占用了22个字节.Index0是其大小,应该是22,index1 是实际字符长度.应该是0.现在
一个step数组:step是一个plc数据类型. 其为30个step元素.
每个step含有:
OK,我们先来完成如何读取写入这个结构:
10.1首先在vs中架构一个PLCSTRING类,因为 string这个类不好投射.
public class PlcString:IPlcParse { private readonly byte[] bytes; public PlcString() : this(256) { } public PlcString(int len ) { bytes = new byte[len]; bytes[0] = len <= 0xfe ? (byte)len : (byte)0xfe; } public void SetString(string str) { int len = bytes.Length; if (str != string.Empty) { byte[] str_bytes = ASCIIEncoding.ASCII.GetBytes(str); bytes[1] = (byte)str_bytes.Length; str_bytes.CopyTo(bytes, 2); } else { bytes[1] = 0; } } public string GetString() { if (bytes[1] != 0) { byte[] strs = new byte[(int)bytes[1]]; Buffer.BlockCopy(bytes, 2, strs, 0, (int)bytes[1]); return ASCIIEncoding.ASCII.GetString(strs); } else { return string.Empty; } } public static explicit operator String(PlcString obj) { return obj.GetString(); } public object FromBytes(byte[] bytes, ref double numBytes) { numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; Buffer.BlockCopy(bytes, (int)numBytes, this.bytes, 0, this.bytes.Length); numBytes += this.bytes.Length; return this; } public int GetSize() { return bytes.Length; } public void ToBytes(byte[] bytes, ref double numBytes) { numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Floor(numBytes / 2.0)) > 0) numBytes++; Buffer.BlockCopy(this.bytes, 0,bytes, (int)numBytes, this.bytes.Length); numBytes += this.bytes.Length; } public void Display() { foreach (var x in bytes) Console.Write(" {0:X2}", x); Console.WriteLine(); } }
这个类实现了如下的接口:
public interface IPlcParse { void ToBytes(byte[] bytes, ref double numBytes); object FromBytes(byte[] bytes, ref double numBytes); int GetSize(); }
https://gitee.com/mao_qin_bin/s7netplus
算了,太多了,大家到这个地方下载吧. 注意版权.是我的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
在原有的S7的基础上更改的实现.(git下来之后,我们再开始下一步)
下面我们来实现VS中的step步:
public class Recipe_Step { public short element1; public short element2; public short element3; public short element4; public short element5; public short element6; public double element7; public double element8; public double element9; public double element10; public double element11; public double element12; public double element13; public bool element14; public bool element15; public short element16; }
1,int--投射成short
2,real-投射成double
3,注意大小是64个字节.我们来计算下我们的类的大小.
public static void demo5() { PlcClassHelper.DisplayObject(new Recipe_Step()); }
结果:
Recipe_Step : ConsoleApp1.PlcClass.Recipe_Step Size:44 Class of Recipe_Step Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Boolean : False Size:2 Boolean : False Size:2 Int16 : 0 Size:2
OK.
然后再测试下Recipe1:
public class Recipe { public static Recipe StaticInstance=new Recipe(); public PlcString Recipe_Name = new PlcString(20, ""); public Recipe_Step[] Recipe_Steps = new Recipe_Step[30]; private Recipe() { for(var i = 0; i < Recipe_Steps.Length; i++) { Recipe_Steps[i] = new Recipe_Step(); } } }
这是PLC数据块(非优化)编译好的
这是我测试的:
Recipe : ConsoleApp1.PlcClass.Recipe Size:1342 Class of Recipe PlcString : String = Bytes = : 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Size:22 Array of ConsoleApp1.PlcClass.Recipe_Step[] : Recipe_Step : ConsoleApp1.PlcClass.Recipe_Step Size:44 Class of Recipe_Step Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Int16 : 0 Size:2 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Double : 0 Size:4 Boolean : False Size:2 Boolean : False Size:2 Int16 : 0 Size:2 Recipe_Step : ConsoleApp1.PlcClass.Recipe_Step Size:44
完全正确.下面设定下一些数据并且从PLC的读取:
10.5 设置PLC数据
10.6 从PLC读取数据:
完全一致:
10.7 将数据写入PLC:
public static void demo6() { Recipe curRecipe = Recipe.StaticInstance;//引用配方 Recipe.Initial(); short t = 0; foreach(var step in curRecipe.Recipe_Steps) { step.element1 = t++; step.element16 = t++; } Plc plc = new Plc(CpuType.S71200, "192.168.3.62", 0, 1); try { plc.Open(); plc.WriteBytes(DataType.DataBlock, 1, 0, PlcClass.ToBytes(curRecipe)); PlcClassHelper.DisplayObject(curRecipe); } catch (PlcException e) { Console.WriteLine("Exception'Message is {0},Exception's Errcode is {1}", e.Message, e.ErrorCode.ToString()); } finally { plc.Close(); } }
上面的Initial是将staticInstance实列给初始化了.
查看结果: PLC
查看结果:VS