PLC通讯实现-C#实现西门子PLC串口通讯W95_S7(四)
背景
本人近十年的工作都与工业软件相关、其中工控系统开发过程中有一个必要环节就是跟各大厂商的PLC进行通讯,而对于从互联网行业跨入工业互联网行业的从业人员来说要实现各型号PLC通讯还是需要一个过程的,本人在此对主流型号PLC通讯实现进行总结以便大家参考。
抽象设计
首先我们要进行一下抽象设计,先设计一个抽象类(接口也可以,此处因为还有其他业务使用了抽象类)BaseEquip,对PLC的常规操作进行定义,即Open、Read、Write、Close,业务代码调用BaseEquip进行PLC的读写,然后在实现各型号的Equip类,对Open、Read、Write、Close进行实现,根据配置在业务代码中对BaseEquip进行实例化,这样后期更改PLC型号后,只需修改配置即可,不用修改业务代码。
西门子串口通讯实现W95_S7
实现语言C#
抽象基类BaseEquip
public class BaseEquip
{
/// <summary>
/// 打开设备
/// </summary>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Open();
/// <summary>
/// 读取信息
/// </summary>
/// <param name="block">数据块</param>
/// <param name="start">起始地址</param>
/// <param name="len">长度</param>
/// <param name="buff">读取返回信息</param>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Read(string block, int start, int len, out object[] buff);
/// <summary>
/// 写入信息
/// </summary>
/// <param name="block">数据块</param>
/// <param name="start">起始地址</param>
/// <param name="buff">要写入的数据</param>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Write(int block, int start, object[] buff);
/// <summary>
/// 关闭设备
/// </summary>
public abstract void Close();
}
设备实现类Equip实现
using System;
using Mesnac.Equips;
using Mesnac.Equips.BaseInfo;
using System.Runtime.InteropServices;
namespace Mesnac.Equip.Siemens.S7.Default
{
/// <summary>
/// 西门子S7-300PLC串口通讯设备类
/// </summary>
public class Equip : BaseEquip
{
private bool _isOpen = false; //是否打开连接
private IntPtr equipHandle = new IntPtr(Marshal.SizeOf(typeof(int)));
private IntPtr structToIntPtr<T>(T s)
{
int nSizeOfT = Marshal.SizeOf(typeof(T));
int nSizeOfIntPtr = Marshal.SizeOf(typeof(IntPtr));
IntPtr Result = new IntPtr();
Result = Marshal.AllocHGlobal(nSizeOfT);
Marshal.StructureToPtr(s, (IntPtr)((UInt32)Result), true);
return Result;
}
private T IntPtrTostruct<T>(IntPtr p)
{
return (T)Marshal.PtrToStructure(p, typeof(T));
}
private int Swap(int a)
{
return (a >> 8 & 0xFF) + (a << 8 & 0xFF00);
}
public override bool Open()
{
lock (this)
{
if (this._isOpen == true)
{
return true;
}
this.State = false;
//W95_S7.PLCConnParam adressType = new W95_S7.PLCConnParam();
byte c1 = 1;
byte[,] p3 = {
{
2, 0, 2, 0 }, {
3, 0, 2, 0 }, {
0, 0, 0, 0 } };
int Result = W95_S7.load_tool(c1, "S7ONLINE", p3);
if ((Result != 0) && (Result != 39)) // 39已经初始化
{
Console.WriteLine("PLC连接失败:" + this.GetErrInfo(Result));
this.State = false;
return this.State;
}
else
{
this.State = true;
this._isOpen = true;
}
return this.State;
}
}
/// <summary>
/// PLC数据读取方法
/// </summary>
/// <param name="block">要读取的块号</param>
/// <param name="start">要读取的起始字</param>
/// <param name="len">要读取的长度,最大255,超过255则不读取</param>
/// <param name="buff"></param>
/// <returns></returns>
public override bool Read(string block, int start, int len, out object[] buff)
{
lock (this)
{
buff = new object[len];
try
{
if (len > 256)
{
for (int i = 0; i < len; i++)
{
buff[i] = 0;
}
base.State = false;
return