欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#开发OPC客户端

程序员文章站 2022-06-13 17:34:30
第一个随笔,使用了OPEN Live Write,作为客户端.最近使用c#开发一个小软件,主要功能是OPC客户端.以后会开发各类别的协议,作为,协议的转发栈.因为我本人是搞自动化的,所以搞自动化小伙伴像我这样喜欢编程的可能有,但是一般是逻辑思维强,但是底子相对还是弱的.1,C# 开发OPC的准备工作... ......

第一个随笔,使用了open live write,作为客户端.最近使用c#开发一个小软件,主要功能是opc客户端.以后会开发各类别的协议,作为,协议的转发栈.

因为我本人是搞自动化的,所以搞自动化小伙伴像我这样喜欢编程的可能有,但是一般是逻辑思维强,但是底子相对还是弱的.

1,c# 开发opc的准备工作

            软件:vs2019;

            dll:c:\program files (x86)\common files\matrikonopc\common\opcdaauto.dll

            并且将其拷贝到c:\windows\syswow64中,并且使用dll注册.(记得注册必须在这个文件夹中)

            然后在,vs2019的引用添加引用

2, 查看opc手册,不过是英文的vb版本的,以上资料可以在我的百度网盘里面下载.或者私信我.

3, 如何查询 opc服务器数量和连接服务器

 private void btgetlist_click(object sender, eventargs e)
        {
            kepserver = new opcserver();

            messagebox.show(environment.machinename);

            object serverlist = kepserver.getopcservers();



            //枚举网络所有opc服务器并写入combobox控件



            foreach (string turn in (array)serverlist)



            {



                cmbservername.items.add(turn);



            }
        }
4,连接服务器(可以去下载一个matrikonopcsimulation)
 private void form1_load(object sender, eventargs e)
        {
            kepserver = new opcserver();
            kepserver.connect("matrikon.opc.simulation.1");
            if (kepserver.serverstate == (int)opcserverstate.opcrunning)



            {


                tsslserverstate.text = "已连接到-" + kepserver.servername + "   ";
                opcbrowser = kepserver.createbrowser();

            }
            treenode root = treeview1.nodes.add(kepserver.servername);
            root.tag = kepserver;
            opcbrowser.movetoroot();
            showintreeview(opcbrowser,root);
        }

其中主要函数说明:

其同时支持ip或者计算机名的方式

本地计算机第二个参数.第一个参数是服务器名称.

5,对于opcbrower 对象.

          从上面可以看到opcbrowser 来自 opcserver.createbrower(),其主要用来查看服务器相关信息.

         其本身是一个集合(collection),但是,这个时候,其items=0;

        showbranchs():该函数用于将当前节点的名称集合写入到collection中.

        showleafs():该函数用于将当前节点的tags 写入到collection中.

        showleafs(true):将显示该节点下面所有的itemsid--------------很重要,在添加item时可以用到.

private void showintreeview(opcbrowser brower,treenode node)
        {
            treenode childnode = null;
            brower.showbranches();
            int branchcount = brower.count;
            list<string> lst = null;
            if (brower.count>0)
                //回溯的添加branch
            {
                lst = new list<string>();
                foreach (string t in brower)
                    lst.add(t);

                foreach (string branch in lst)
                {
                     childnode = new treenode(branch);
                     childnode.tag = brower.getitemid(branch);
                     node.nodes.add(childnode);
                     brower.movedown(branch);
                     showintreeview(brower, childnode);
                     brower.moveup();

                 }
            }

            brower.showleafs();
            int leafscount = brower.count;
            foreach (string leaf in brower)
            {
                childnode = new treenode(brower.getitemid(leaf));
                childnode.tag = brower.getitemid(leaf);
                node.nodes.add(childnode);


            }


        }

这样就可以把服务器的信息读取到树里面了.

brower对象主要作用就是可以知道服务器里面的信息了.

6,group对象及item对象.

首先:需要创建group对象:

 private void button3_click(object sender, eventargs e)
        {
            kepgroups = kepserver.opcgroups;
            kepgroups.defaultgroupisactive = true;
            kepgroups.defaultgroupupdaterate = 200;
            kepgroups.defaultgroupdeadband = 0;
            kepgroup = kepgroups.add("mxb");
            kepgroup.issubscribed = true;
            kepgroup.datachange += new diopcgroupevent_datachangeeventhandler( datachangehandlerfunc);
            kepitems = kepgroup.opcitems;
            //
            kepitem = kepitems.additem("random.arrayofreal8", 1);
            textbox1.text = kepitem.serverhandle + ":" + kepitem.requesteddatatype;





        }

说明:

如果该参数是issubscribed=true;则其支持订阅功能:也就是当改组中的参数有改变的时候,其会触发datachange事件.

其中:itemid是一个关键的参数,可以通过 opcbrower.showleafs(true)查看.

additem(string itemid,int clienthandle):其中client handle是客户端自行填写的.

一个item 有一个serverhandle,由服务器提供,itemid:由服务器提供;clienthandle:由客户端提供.

事件处理函数

 private void datachangehandlerfunc(int transactionid, int numitems, ref array clienthandles, ref array itemvalues, ref array qualities, ref array timestamps)
        {
            //
                for(int i = 1;i<=numitems;i++)
            {
                if((int)clienthandles.getvalue(i) == kepitem.clienthandle)
                {

                    dynamic t = itemvalues.getvalue(i);
                    object[] ary;
                    ary = array.convertall<double, object>(t, new converter<double, object>((x) =>x));
                    listbox1.items.clear();
                    listbox1.items.addrange(ary);


                                    }
            }

         }

使用该函数可以快速定位数据变更的item.注意:所有的array都是1开头的,所以不能直接转换成int[]或者double[];需要编写一个转换

的函数,转换成object[].另外,需要注意到 clienthandles虽然是一个int数组,但是是无法直接转换到int[]的,因为首先,其起始index=1.

其他还有一些异步写入啊,什么的,可以参考手册.