经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件图像 » Visual Studio » 查看文章
C#.Net平台与OPC服务器通讯
来源:cnblogs  作者:Ndolls工作室  时间:2018/10/18 9:05:43  对本文有异议

最近,我们Ndolls工作室承接了山大某个自动化控制项目,主要做了一套工控信息化系统,其中有一个功能模块是将系统管理的一部分数据参数发送至OPC服务器,由OPC服务器接收数据后执行相应工控操作。第一次接触OPC的项目,有点头大,与大家分享一点经验,希望对大家有所帮助。

一、开发调试环境

1、系统环境:win7 64位

2、开发工具:Microsoft Visual Studio 2010(.Net4.0)

3、OPC组件:Interop.OPCAutomation.dll

下载地址:http://www.ndolls.net/doc/OPCAutomation.zip

4、OPC Server仿真软件:ICONICS Simulator OPC Server 3.12

下载地址(需要登陆后下载):http://www.ndolls.net/doc/ICONICSSimulatorOPCServer3.12.zip

二、注意事项

1、Interop.OPCAutomation.dll需要在系统进行注册,可以直接运行如下命令:

regsvr32 Interop.OPCAutomation.dll存放路径

如因为win7系统权限问题无法注册成功,请使用如下命令:

runas /user:administrator regsvr32 Interop.OPCAutomation.dll存放路径

2、请将项目设置成X86模式,不然Interop.OPCAutomation.dll会调用失败。

3、使用仿真软件ICONICS Simulator OPC Server需要开启Distributed Transaction Coordinator服务。

4、在调用Interop.OPCAutomation.dll过程中,如遇到返回错误码,可参考以下地址进行分析解决:

https://www.cnblogs.com/heroius/p/7401026.html

5、Interop.OPCAutomation.dll中文文档可从以下地址下载:

http://www.ndolls.net/doc/OPC_API.pdf

三、Demo界面以及代码分析(下载地址:http://www.ndolls.net/doc/OPCManage.zip)

Demo主要实现了向OPC服务器指定的分组和标签定向发送数据。

下图为demo的winform界面

下图为仿真软件界面

下面贴上代码,请注意首先需要添加引用using OPCAutomation

  1. #region 变量
  2. //OPCServer的IP
  3. private String strHostIP;
  4. //OPCServer的主机名
  5. private String strHostName;
  6. //是否和OPCServer建立连接
  7. private Boolean opc_connected;
  8. //建立的OPCServer对象
  9. private OPCServer myServer;
  10. //OPCServer节点浏览器
  11. private OPCBrowser myOPCBrowser;
  12. //分组集合
  13. private OPCGroups myGroups;
  14. //分组实例
  15. private OPCGroup myGroup;
  16. //分组的TAG节点
  17. private OPCItems myItems;
  18. //服务端句柄
  19. int itmHandleServer = 0;
  20. //要写入的叶子节点
  21. private OPCItem[] myItemArray;
  22. #endregion
  23. #region 触发事件
  24. /// <summary>
  25. /// 每当项数据有变化时执行的事件
  26. /// </summary>
  27. /// <param name="TransactionID">处理ID</param>
  28. /// <param name="NumItems">项个数</param>
  29. /// <param name="ClientHandles">项客户端句柄</param>
  30. /// <param name="ItemValues">TAG值</param>
  31. /// <param name="Qualities">品质</param>
  32. /// <param name="TimeStamps">时间戳</param>
  33. void myGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
  34. {
  35. for (int i = 1; i <= NumItems; i++)
  36. {
  37. txtValue.Text = ItemValues.GetValue(i).ToString();
  38. }
  39. //为方便测试,显示到状态栏输出
  40. lblState.Text = "TransactionID:" + TransactionID.ToString() + "--" + "NumItems:" + NumItems.ToString();
  41. }
  42. /// <summary>
  43. /// 写入TAG值时执行的事件
  44. /// </summary>
  45. /// <param name="TransactionID">处理ID</param>
  46. /// <param name="NumItems">项个数</param>
  47. /// <param name="ClientHandles">项客户端句柄</param>
  48. /// <param name="Errors">服务器返回的错误信息</param>
  49. void myGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
  50. {
  51. //为方便测试,显示到状态栏输出
  52. for (int i = 1; i <= NumItems; i++)
  53. {
  54. lblState.Text = "TransactionID:" + TransactionID.ToString() + "--" + "ClientHandle:" + ClientHandles.GetValue(i).ToString() + "--" + "ErrorValue: " + Errors.GetValue(i).ToString();
  55. }
  56. }
  57. #endregion
  58. #region 按钮事件
  59. /// <summary>
  60. /// 连接服务器
  61. /// </summary>
  62. /// <param name="sender"></param>
  63. /// <param name="e"></param>
  64. private void btnConIP_Click(object sender, EventArgs e)
  65. {
  66. //根据输入获取OPC服务器IP地址
  67. strHostIP = txtIP.Text;
  68. //通过IP来获取OPC服务器主机名
  69. IPHostEntry ipHostEntry = Dns.GetHostEntry(strHostIP);
  70. strHostName = ipHostEntry.HostName.ToString();
  71. try
  72. {
  73. //实例化OPC服务
  74. myServer = new OPCServer();
  75. //获取OPCServer列表
  76. object serverList = myServer.GetOPCServers(strHostName);
  77. //将OPCServer展示到ComboBox
  78. foreach (string turn in (Array)serverList)
  79. {
  80. cmbServer.Items.Add(turn);
  81. }
  82. cmbServer.SelectedIndex = 0;
  83. //开启OPC连接按钮
  84. btnOPC.Enabled = true;
  85. }
  86. catch (Exception err)
  87. {
  88. MessageBox.Show("枚举OPC服务出错:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  89. }
  90. }
  91. /// <summary>
  92. /// 连接OPC服务器
  93. /// </summary>
  94. /// <param name="sender"></param>
  95. /// <param name="e"></param>
  96. private void btnOPC_Click(object sender, EventArgs e)
  97. {
  98. try
  99. {
  100. //根据选择的OPCServer进行连接
  101. myServer.Connect(cmbServer.Text, strHostIP);
  102. //根据连接成功与否输出状态信息
  103. if (myServer.ServerState == (int)OPCServerState.OPCRunning)
  104. {
  105. lblState.Text = "已连接到:" + myServer.ServerName;
  106. //显示服务器信息
  107. lblState.Text += "----开始时间:" + myServer.StartTime.ToString();
  108. lblState.Text += "----版本:" + myServer.MajorVersion.ToString() + "." + myServer.MinorVersion.ToString() + "." + myServer.BuildNumber.ToString();
  109. }
  110. else
  111. {
  112. lblState.Text = "状态:" + myServer.ServerState.ToString();
  113. }
  114. //已连接标记
  115. opc_connected = true;
  116. //开启获取标签按钮
  117. btnGetGrps.Enabled = true;
  118. MessageBox.Show("链接OPC成功");
  119. }
  120. catch (Exception err)
  121. {
  122. MessageBox.Show("初始化出错:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  123. }
  124. }
  125. /// <summary>
  126. /// 获取OPC服务器所有分组和标签
  127. /// </summary>
  128. /// <param name="sender"></param>
  129. /// <param name="e"></param>
  130. private void btnGetGrps_Click(object sender, EventArgs e)
  131. {
  132. //实例化Tag浏览器
  133. myOPCBrowser = myServer.CreateBrowser();
  134. //展开分组
  135. myOPCBrowser.ShowBranches();
  136. //展开标签
  137. myOPCBrowser.ShowLeafs(true);
  138. //将所有分支和叶子节点显示到ListBox
  139. lstItems.Items.Clear();
  140. foreach (object turn in myOPCBrowser)
  141. {
  142. lstItems.Items.Add(turn.ToString());
  143. }
  144. //开启定位标签按钮
  145. btnSetItem.Enabled = true;
  146. }
  147. /// <summary>
  148. /// 根据列表中选中的当前标签,定位到需要发送数据的标签
  149. /// </summary>
  150. /// <param name="sender"></param>
  151. /// <param name="e"></param>
  152. private void btnSetItem_Click(object sender, EventArgs e)
  153. {
  154. try
  155. {
  156. /**
  157. * 需要注意,不同的OPC服务器的标签格式也是不同的
  158. * 测试时,使用的是ICONICS Simulator OPC Server,标签格式如:Textual.Memory
  159. * 生产环境时,使用的是SimaticNet_V13Sp1,标签格式如:S7:[S7_Connection_1]MReal120
  160. * **/
  161. //根据ListBox选中的标签,处理得到分组名称
  162. string groupName = lstItems.Text;
  163. //实例化组
  164. myGroups = myServer.OPCGroups;
  165. myGroup = myGroups.Add(groupName);
  166. //设置缺省的组属性
  167. myServer.OPCGroups.DefaultGroupIsActive = true;
  168. myServer.OPCGroups.DefaultGroupDeadband = 0;
  169. myGroup.UpdateRate = 250;
  170. myGroup.IsActive = true;
  171. myGroup.IsSubscribed = true;
  172. //定位需要发送数据的目标项
  173. myItems = myGroup.OPCItems;
  174. //实例化组内标签
  175. myItemArray = new OPCItem[1];
  176. //填充项目组
  177. myItemArray[0] = myItems.AddItem(lstItems.Text, 1);
  178. //获取服务端句柄
  179. itmHandleServer = myItemArray[0].ServerHandle;
  180. //监听组内数据变化
  181. myGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(myGroup_DataChange);
  182. myGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(myGroup_AsyncWriteComplete);
  183. //开启发送参数按钮
  184. btnWrite.Enabled = true;
  185. }
  186. catch (Exception err)
  187. {
  188. MessageBox.Show("创建组出现错误:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  189. }
  190. }
  191. /// <summary>
  192. /// 写入值
  193. /// </summary>
  194. /// <param name="sender"></param>
  195. /// <param name="e"></param>
  196. private void btnWrite_Click(object sender, EventArgs e)
  197. {
  198. //获取之前定位的标签
  199. OPCItem bItem = myItems.GetOPCItem(itmHandleServer);
  200. //根据用户界面输入生成数据对象
  201. int[] temp = new int[2] { 0, bItem.ServerHandle };
  202. Array serverHandles = (Array)temp;
  203. object[] valueTemp = new object[2] { "", txtMyValue.Text };
  204. Array values = (Array)valueTemp;
  205. Array Errors;
  206. int cancelID;
  207. //异步写入到OPC服务器
  208. myGroup.AsyncWrite(1, ref serverHandles, ref values, out Errors, 2009, out cancelID);
  209. //回收资源
  210. GC.Collect();
  211. }
  212. /// <summary>
  213. /// 关闭窗体时,关闭链接
  214. /// </summary>
  215. /// <param name="sender"></param>
  216. /// <param name="e"></param>
  217. private void OPCManage_FormClosing(object sender, FormClosingEventArgs e)
  218. {
  219. if (!opc_connected)
  220. {
  221. return;
  222. }
  223. if (myGroup != null)
  224. {
  225. myGroup.DataChange -= new DIOPCGroupEvent_DataChangeEventHandler(myGroup_DataChange);
  226. }
  227. if (myServer != null)
  228. {
  229. myServer.Disconnect();
  230. }
  231. opc_connected = false;
  232. }
  233. #endregion

四、生产环境

真实的生产环境中,工控终端采用西门子数控系统(SINUMERIK 808),OPC服务器采用SimaticNet_V13Sp1。由工控人员预先在OPC服务的S7:[S7_Connection_1]M分组下,创建MReal120—MReal140共6个寄存节点,用于接收软件写入的工艺参数。本系统用户根据需要从我们的软件中检索工艺参数,并定向写入到OPC服务器的S7:[S7_Connection_1]M节点下,由数控人员控制数控系统从OPC服务器获取到最新参数进行生产。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号