C#OPC的应用(三)
在上文成功的建立和OPCServer的连接之后,就可以和Server进行互操作..
主要的操作有:读,写以及捕捉数据的变化..
捕捉数据的变化是被动操作..服务器会将变化的数据发送到客户端..客户端只需要在连接Server时候,生成的theGrp_DataChanged事件中,写代码就可以..
捕捉数据变化 void theGrp_DataChanged(object sender, DataChangeEventArgs e) { lock (_dtPoint) { foreach (OPCItemState s in e.sts) { if (HRESULTS.Succeeded(s.Error)) { int handClent = s.HandleClient; for (int i = 0; i < Count; i++) { if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent) { _dtPoint.Rows[i]["PV"] = s.DataValue; break; } } } } } }
根据HandleClient来判断是哪一个数据项发生变化..降变化的数据保存下来,供系统调用..
数据的读写操作....
theGrp_ReadCompleted和theGrp_WriteCompleted 这个两个方法,是获取操作结果的方法..
在theGrp_ReadCompleted中可以,获取到最近一次读取的数据项的值..
代码如下:
获取读取数据结果lock (_dtPoint) { foreach (OPCItemState s in e.sts) { if (HRESULTS.Succeeded(s.Error)) { int handClent = s.HandleClient; for (int i = 0; i < Count; i++) { if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent) { _dtPoint.Rows[i]["PV"] = s.DataValue; break; } } } } }
将读取到的数据更新到数据表中..
读取数据代码:
读取最新数据int[] readSer = new int[dtPoint.Rows.Count]; for (int i = 0; i < dtPoint.Rows.Count; i++) { readSer[i] = Convert.ToInt32(dtPoint.Rows[i]["ServerHandel"]); } int cancelID; int[] arrErr; int transactionID = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm")); theGrp.Read(readSer, transactionID, out cancelID, out arrErr);
其中,readSer数组保存的是服务器端句柄..transactionID 是一个标致,在返回读取结果的时候,会用到,可以判断是不是上次读取的结果..
写入数据的代码如下:
写入数据int[] handle = new int[1]; for (int i = 0; i < this.Count; i++) { if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName) { handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]); break; } } object[] itemValues = new object[1]; itemValues[0] = (object)value; int[] ax; bool re = this.theGrp.Write(handle, itemValues, out ax);
最后,因为项目的需要,自己写了两个写入的方法..1个单值写入,1个一次多值写入..写出来,只是为了方便大家的使用,代码并没有什么含金量,如下:
写入数据(自定义方法)/// <summary> /// 写入数值(一次写入多个) /// </summary> /// <param name="pointName"></param> /// <param name="value"></param> /// <returns></returns> public bool pvWrite(string[] pointName, string[] value) { int[] handle = new int[pointName.Length]; for (int i = 0; i < handle.Length; i++) { for (int j = 0; j < Count; j++) { if (dtPoint.Rows[j]["PointName"].ToString() == pointName[i]) { handle[i] = Convert.ToInt32(dtPoint.Rows[j]["ServerHandel"]); break; } } } int[] ax; bool re = this.theGrp.Write(handle, (object[])value, out ax); return re; } /// <summary> /// 写入数值(单值写入) /// </summary> /// <param name="pointName"></param> /// <param name="value"></param> /// <returns></returns> public bool pvWrite(string pointName, string value) { int[] handle = new int[1]; for (int i = 0; i < this.Count; i++) { if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName) { handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]); break; } } object[] itemValues = new object[1]; itemValues[0] = (object)value; int[] ax; bool re = this.theGrp.Write(handle, itemValues, out ax); return re; }
因为theGrp_WriteCompleted 方法,项目中没有使用到..所以,就没有添加代码,只是留了个空方法..
至此,OPCServer和c#客户端的通讯已经介绍完毕,基本满足简单应用,更深层的需要可能还需要继续努力..
奉献上完整代码:
写入数据(自定义方法)public OPCItemResult[] rItem//服务器返回项 { get { return _rItem; } set { _rItem = value; } } public OPCItemDef[] itemDefs//客户端项属性 { set { _itemDefs = value; } get { return _itemDefs; } } public int[] handlesSrv { get { return _handlesSrv; } set { _handlesSrv = value; } } private static int[] _handlesSrv;//服务器端句柄 private static bool isConnect = false; private static OPCItemResult[] _rItem = null; private static OPCItemDef[] _itemDefs = null; public bool IsConnect { get { return isConnect; } set { isConnect = value; } } public int Count { set { _Count = value; } get { return _Count; } } private static DataTable _dtPoint = null; public DataTable dtPoint { get { return _dtPoint; } set { _dtPoint = value; } } private static OpcServer _theSrv = null; public OpcServer theSrv { set { _theSrv = value; } get { return _theSrv; } } private static OpcGroup _theGrp = null; public OpcGroup theGrp { set { _theGrp = value; } get { return _theGrp; } } void theGrp_DataChanged(object sender, DataChangeEventArgs e) { lock (_dtPoint) { foreach (OPCItemState s in e.sts) { if (HRESULTS.Succeeded(s.Error)) { int handClent = s.HandleClient; for (int i = 0; i < Count; i++) { if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent) { _dtPoint.Rows[i]["PV"] = s.DataValue; break; } } } } } } void theGrp_ReadCompleted(object sender, ReadCompleteEventArgs e) { lock (_dtPoint) { foreach (OPCItemState s in e.sts) { if (HRESULTS.Succeeded(s.Error)) { int handClent = s.HandleClient; for (int i = 0; i < Count; i++) { if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent) { _dtPoint.Rows[i]["PV"] = s.DataValue; break; } } } } } } public bool Connect(string serverName, string serverAdress) { theSrv = new OpcServer(); theSrv.Connect(serverName, serverAdress); Thread.Sleep(500); _dtPoint = dal.SelPoint(); Count = _dtPoint.Rows.Count; theGrp = theSrv.AddGroup("OPCGroup", false, 900); itemDefs = new OPCItemDef[Count]; for (int i = 0; i < Count; i++) { itemDefs[i] = new OPCItemDef(_dtPoint.Rows[i]["PointName"].ToString() + ".PV", true, Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]), VarEnum.VT_EMPTY); } theGrp.AddItems(itemDefs, out _rItem); if (rItem == null) return false; bool res = true; for (int i = 0; i < Count; i++) { if (HRESULTS.Failed(rItem[i].Error)) { res = false; //如果符合,则修改 break; } } if (!res) { //this.lblErr.Text = "OPC服务器:添加组错误!"; theGrp.Remove(true); theSrv.Disconnect(); return false; } handlesSrv = new int[Count]; for (int i = 0; i < Count; i++) { handlesSrv[i] = rItem[i].HandleServer; _dtPoint.Rows[i]["ServerHandel"] = (object)handlesSrv[i]; } theGrp.SetEnable(true); theGrp.Active = true; theGrp.DataChanged += new DataChangeEventHandler(theGrp_DataChanged); return true; } /// <summary> /// 写入数值(一次写入多个) /// </summary> /// <param name="pointName"></param> /// <param name="value"></param> /// <returns></returns> public bool pvWrite(string[] pointName, string[] value) { int[] handle = new int[pointName.Length]; for (int i = 0; i < handle.Length; i++) { for (int j = 0; j < Count; j++) { if (dtPoint.Rows[j]["PointName"].ToString() == pointName[i]) { handle[i] = Convert.ToInt32(dtPoint.Rows[j]["ServerHandel"]); break; } } } int[] ax; bool re = this.theGrp.Write(handle, (object[])value, out ax); return re; } /// <summary> /// 写入数值(单值写入) /// </summary> /// <param name="pointName"></param> /// <param name="value"></param> /// <returns></returns> public bool pvWrite(string pointName, string value) { int[] handle = new int[1]; for (int i = 0; i < this.Count; i++) { if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName) { handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]); break; } } object[] itemValues = new object[1]; itemValues[0] = (object)value; int[] ax; bool re = this.theGrp.Write(handle, itemValues, out ax); return re; }
数据库中Point创建的SQL语句
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Point]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Point]
GO
CREATE TABLE [dbo].[Point] (
[PointId] [int] NOT NULL ,
[PointName] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[PointDesc] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[ClientHandel] [int] NULL ,
[ServerHandel] [int] NULL ,
[PV] [char] (10) COLLATE Chinese_PRC_CI_AS NULL ,
[isUse] [int] NULL
) ON [PRIMARY]
GO
到此,该系列结束..还包括很多应用没有提到,包括OPCServer的浏览等..以后,如果用到这方面的东西,再继续补充...