如何与OPC进行良好的沟通?

时间:2014-10-01 08:10:46

标签: multithreading delphi opc

我有一个使用OPC的线程的应用程序。该线程与OPC Factory Server建立连接并接收自动化通知。

OPC:v 3.40.2808.0

Langage:Pascal,IDE:Delphi XE 2

与服务器的连接很好并且通知正在进行中。但有时,服务并不完美,我的申请没有收到所有通知。

我不确定问题是来自我的代码,但有一点解释:

GestOPC = class(TThread)
    contructor Create(suspendu:boolean);
    destructor Destroy;override;
    procedure C******; // Called by connexion
    private
        procedure Execute;override;
        procedure CallGestOPCMainLabelAtt(const s : string);// IU Calling 
        procedure Call****;
        procedure Call****;
        procedure Call****;
    public
        sCallIHM :string;
        ***: boolean;
        ***: LongInt;
        ThreadListNotif: TThreadList,
        ServeurIF : OPCServer;
        OPCDataCallBack:IOPCDataCallBack;
        Buffer_notif : ^TNotif;
        procedure connexion;
    end;

TOPCDataCallback = class ( TInterfacedObject, IOPCDataCallback)
public 
    function OnDataChange(.....)HResult;stdcall;
    function OnReadComplete(.....)HResult;stdcall;
    function OnWriteComplete(.....)HResult;stdcall;
    function OnCancelComplete(.....)HResult;stdcall;
end;

OPC的线程的OnDataChange:这是接收通知的事件

function TOPCDataCallback.OnDataChange ( dwTransid : DWORD; hgroup:OPCHANDLE; hrMasterquality: HResult;
hrMastererror : HResult;dwCount : DWORD;phClientItems:POPCHANDLEARRAY;pvValues: POleVariantArray;
pwQualities:PWordArray; pftTimeStamps : PFileTimeArray; pErrors :PResultList ): HResult;

var 
ClientItems :POPCHANDLEARRAY;
Values: POleVariantArray;
Qualities : PWordArray;
i,iCountBadItem:integer;

Begin
    if not bClosing then ///It's to not do anything if the app is closing.
    begin
        //Initialisation 
        iCountBadItem := 0; //this is for count during debbugging all notification unreadable
        Result := s_OK;
        ClientItems := POPCHANDLEARRAY (phClientItems);  
        Values := POleVariantArray(pvValues); 
        for i := 0 to dwCount -1 do 
        begin 
            if Qualities[i] = OPC_QUALITY_GOOD then 
            begin
                new(ClientOPC.Buffer_notif); 
                ClientOPC.Buffer_notif^.groupe_handle.indice_type1 := hGroup;
                ClientOPC.Buffer_notif^.item_client := ClientItems[i];
                ClientOPC.Buffer_notif^.valeur_item := Value[i];
                ClientOPC.ThreadListNotif.Add(ClientOPC.Buffer_Notif);
                      //This list is used in another Thread with LockList for use the notification.
            end
            else 
                iCountBadItem := iCountBadItem+1;
         end;
      end;

我的程序执行OPC线程是空的,以确保我有一个良好的接收:

procedure GestOPC.Execute; 
begin
    NameThreadForDebugging('GestOPC');
    while (not Terminated) do 
    begin 
        sleep(100);
    end;
end;

我的主题是由我的主表单的FormCreate事件创建的:

     ClientOPC := GestOPC.Create(false);
     ClientOPC.FreeOnTerminate := false;

连接是通过ButtonClick'事件:

启动的
     ClientOPC.Connexion;

函数连接开始于创建接收器TOPCDataCallBack,与Ofs建立连接,在数据库上进行SQL调用,并完成对我的接口的动态修改(OPC在线程上的原因是不冻结我的连接期间的界面)。

对于我的IU Calling我使用这个结构:

sCallIHM := "Ceci est un exemple de mon travail ;) ";
Queue( 
    procedure 
        begin 
        CallGestOPCMainLabelAtt( sCallIHM );
        end ) ;

如何升级才能收到我的所有信息?

感谢您阅读=)

1 个答案:

答案 0 :(得分:4)

此代码完全误解了如何使用TThread。您的Execute方法什么都不做,因此就应用程序设计而言,没有线程。所有GestOPC函数都只是在调用它们的任何线程上执行。由于您使用的是Queuedocumentation explicitly states 警告:请勿在主线程中调用队列。 ,这是一个明显的错误。

当然,在这里调用Queue可能不是错误。您还没有告诉我们关于您的OPC库的任何信息,当然某些 OPC库会在工作线程上引发事件。如果是这种情况,你可以通过运气避免错误 - 如果不是这种情况那么你就会有设计错误。只有您可以阅读库文档,确定是哪种情况。

这个应用程序的设计都是错误的。建议您暂时忘记TThread,将TThread变成普通班级,摆脱无用的Execute方法,摆脱对Queue的调用(和Synchronize,如果你有的话),看看会发生什么。然后花一些时间来了解TThread如何工作以及如何编写正确的多线程代码 - 特别是如果你不知道自己在做什么,首先让你的代码单线程运行,然后工作是必不可少的在线程模型上。这有助于分离由线程问题和代码本身引起的错误引起的错误。

此外,OPC服务器中丢失的数据也可能来自时间混叠。 OPC服务器以某种轮询速率对现场设备进行采样,轮询速率因系统和标签而异。该轮询速率可以是10-100ms或更多。如果现场设备中的值变​​化快于此速率,则OPC服务器可能会错过更改,因此许多基于事件的客户端不会引发更改通知。因此,如果必须确保观察它们,确保以某种方式锁定或排队快速更改的硬件状态至关重要。调试时,您应该确定这不是错过更改通知的来源。