Synchron/Asynchron/Connected auf SPS-Variablen zugreifen

Systemvoraussetzungen:

Aufgabe

Das Beispielprogramm zeigt, wie Methoden und Events des AdsOcx in einer Delphi-Anwendung benutzt werden können. Dabei werden die unterschiedlichsten Zugriffsarten (Synchron/Asynchron/Connected) auf die SPS-Variablen vorgestellt. In dem SPS-Programm wurde eine Integer-Variable auf der Adresse 100 im Merkerbereich der Prozessdaten der SPS definiert. Auf die SPS-Variable soll über die unterschiedlichsten Zugriffsarten schreibend oder lesend aus der Delphi-Applikation zugegriffen werden.

Beschreibung

Auf die SPS-Variablen ist über das AdsOcx ein Synchroner-, Asynchroner- oder Connected-Zugriff möglich. Bei einem synchronen Zugriff wird die Applikation so lange angehalten, bis die angeforderten Daten vorliegen. Bei einem asynchronen Zugriff wird eine Anforderung (Request) an die SPS gesendet und die Ausführung der Windows-Applikation fortgesetzt. In der Windows-Applikation wird dann eine Callback-Funktion aufgerufen, wenn die angeforderten Daten vorliegen. Bei dem Connected-Zugriff kann in der Windows-Applikation eine Event-Funktion aufgerufen werden, wenn sich der Wert der SPS-Variablen geändert hat.

Delphi 5 Programm

In der Event-Funktion OnFormCreate wird über die Methode AdsCreateVarHandle ein Handle für den Sysmbolnamen der SPS-Variablen angefordert. Das Handle wird dann in der Beispielapplikation für den schreibenden oder lesenden Zugriff auf die SPS-Variable benutzt. In der Event-Funktion OnDestroy wird das Handle beim Beenden der Applikation mit der Methode AdsDeleteVarHandle freigegeben.

 

var
  Form1         : TForm1;
  varName       :WideString;    {PLC variable symbol name}
  varValue      :Smallint;      {PLC variable value}
  varHandle     :integer;       {PLC variable handle}
  hConnect      :integer;       {PLC variable connection handle}
  adsResult     :integer;       {Ads result}

implementation

{$R *.DFM}

procedure TForm1.OnFormCreate(Sender: TObject);
begin
     AdsOcx1.AdsAmsServerNetId := AdsOcx1.AdsAmsClientNetId;    {Sets PLC server network adress}
     AdsOcx1.AdsAmsServerPort := 801;               {Sets the PLC run time system}
     varName := 'MAIN.VARINT16';
     varValue := 0;
     varHandle := 0;
     hConnect := 0;
     adsResult := AdsOcx1.AdsCreateVarHandle( varName, varHandle ); {creates variable handle}

     if adsResult = 0 then
    LabelVarHandle.Font.Color := clBlue
     else
    LabelVarHandle.Font.Color := clRed;

     LabelVarHandle.Caption := Format( 'AdsCreateVarHandle adsResult:%d   varName:%s   Handle:%d',[adsResult, varName, varHandle] );
end;

procedure TForm1.OnFormDestroy(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsDeleteVarHandle( varHandle );
end; 

Synchroner Zugriff

Bei einem Mausklick auf einen der Buttons in der Gruppe SYNCHRONOUS wird der Wert der SPS-Variablen synchron gelesen bzw. geschrieben und als Text auf der Form ausgegeben. Es kann auf zweifache Weise auf die SPS-Variable zugegriffen werden: Über den Variablen-Namen oder über die Variablen-Adresse.

Zugriff über die Variablen-Adresse

procedure TForm1.OnSyncReadByAddrClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsSyncReadIntegerReq( $00004020, 100, 2, varValue );
     LabelSyncRetData.Caption:=Format( 'adsResult:%d   Value:%d',[adsResult, varValue] );
end;

procedure TForm1.OnSyncWriteByAddrClick(Sender: TObject);
begin
     varValue := 100;
     adsResult := AdsOcx1.AdsSyncWriteIntegerReq( $00004020, 100, 2, varValue );
     LabelSyncRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end;

Zugriff über den Variablen-Namen

Bei einem Zugriff über den Variablen-Namen wird das entsprechende Handle der SPS-Variablen als Parameter in der Methode AdsSyncReadIntegerVarReq bzw. AdsSyncWriteIntegerVarReq benutzt. Das Handle der SPS-Variablen wurde in der OnCreate Event-Funktion beim Applikationsstart angefordert.

procedure TForm1.OnSyncReadByNameClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsSyncReadIntegerVarReq( varHandle, 2, varValue );
     LabelSyncRetData.Caption:=Format( 'adsResult:%d   Value:%d', [adsResult, varValue] );
end;

procedure TForm1.OnSyncWriteByNameClick(Sender: TObject);
begin
     varValue := 200;
     adsResult := AdsOcx1.AdsSyncWriteIntegerVarReq( varHandle, 2, varValue );
     LabelSyncRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end; 

Asynchroner Zugriff

Über die Methoden AdsReadIntegerReq und AdsWriteIntegerReq kann auf die SPS-Variable asynchron zugegriffen werden. 

procedure TForm1.OnAsyncReadByAddrClick(Sender: TObject);
var  varInvokeId       :integer;
begin
     varInvokeId := 33;
     adsResult := AdsOcx1.AdsReadIntegerReq( varInvokeId, $00004020, 100, 2 );
     LabelAsyncRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end;

procedure TForm1.OnAsyncWriteByAddrClick(Sender: TObject);
var  varInvokeId       :integer;
begin
     varInvokeId := 44;
     varValue := 300;
     adsResult := AdsOcx1.AdsWriteIntegerReq( varInvokeId, $00004020, 100, 2, varValue );
     LabelAsyncRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end; 

Die Ausführung der Delphi-Applikation wird nach einem asynchronen Zugriff fortgesetzt und beim Vorliegen der Rückgabeparameter eine Event-Funktion in der Windows-Applikation aufgerufen. In unserem Beispiel wird beim Lesen der SPS-Variablen die Event-Funktion AdsReadIntegerConf und beim Schreiben der SPS-Variablen die Event-Funktion AdsWriteConf aufgerufen.

procedure TForm1.AdsOcx1AdsReadIntegerConf(Sender: TObject; nInvokeId,
  nResult, cbLength: Integer; var pData: Smallint);
begin
     LabelAsyncEventData.Caption :=Format('nInvokeId:%d   nResult:%d   cbLength:%d  pData:%d',
              [nInvokeId, nResult, cbLength, pData]);
end;

procedure TForm1.AdsOcx1AdsWriteConf(Sender: TObject; nInvokeId,
  nResult: Integer);
begin
     LabelAsyncEventData.Caption :=Format('nInvokeId:%d   nResult:%d', [nInvokeId, nResult]);
end;

Connected Zugriff

Bei dem Connected-Zugriff wird eine "Verbindung" zu der SPS-Variablen aufgebaut. In Abhängigkeit von den Parametern (ADSTRANS_SERVERCYCLE oder ADSTRANS_SERVERONCHA) werden die Event-Funktionen zyklisch, oder bei einer Änderung der SPS-Variablen aufgerufen.

In der Beispielapplikation wird bei einem Mausklick auf den Button Connected read by address die Methode AdsReadIntegerConnect aufgerufen und bei einem Mausklick auf den Button Connected read by variable name die Methode AdsReadIntegerVarConnect aufgerufen.  

procedure TForm1.OnConReadByAddrClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsReadIntegerConnect( $00004020, 100, 2, ADSTRANS_SERVERCYCLE, 220, varValue );
     LabelConRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end;

procedure TForm1.OnConReadByNameClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsReadIntegerVarConnect( varName, 2, ADSTRANS_SERVERCYCLE, 220, varValue );
     LabelConRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end; 

Bei Erfolg wird in der Delphi-Applikation die Event-Funktion AdsReadConnectUpdate aufgerufen, unabhängig davon welche der beiden Methoden für den Verbindungsaufbau benutzt wurde. 

procedure TForm1.AdsOcx1AdsReadConnectUpdate(Sender: TObject; nIndexGroup,
  nIndexOffset: Integer);
begin
     LabelConEventData.Caption := Format('nIndexGroup:%d  nIndexOffset:%d   Value:%d',
              [nIndexGroup, nIndexOffset, varValue]);
end;

Über die Methode AdsReadIntegerDisconnect kann die Verbindung zu der SPS-Variablen abgebaut werden.

procedure TForm1.OnDisconnectReadClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsReadIntegerDisconnect( varValue );
     LabelConRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end; 

ConnectEx-Methoden (Connected-Zugriff mit einem Benutzer-Handle)

Mit der Hilfe der ConnectEx-Methoden kann ähnlich wie bei den Connect-Methoden ein Connected-Zugriff zu den SPS-Variablen aufgebaut werden. Die ConnectEx-Methoden haben den Vorteil, dass bei dem Verbindungs-Aufbau ein benutzerdefiniertes Handle als Parameter in der Connect-Methode übergeben werden kann. Dieses Handle kann dann in der Event-Funktion ausgewertet und dazu benutzt werden, um die SPS-Variablen zu identifizieren, für die die Event-Funktion aufgerufen wurde. 

Bei einem Mausklick auf den Button ConnectEx wird in der OnConnectExClick-Routine die Methode AdsReadVarConnectEx2 aufgerufen.

procedure TForm1.OnConectExClick(Sender: TObject);
var  hUser :integer;
begin
     {disconnect old connection}
     if hConnect <> 0 then
     begin
    adsResult := AdsOcx1.AdsDisconnectEx( hConnect );
    if adsResult = 0 then
        hConnect := 0;
     end;

     hUser := 7;    {create user handle}

     adsResult := AdsOcx1.AdsReadVarConnectEx2( varName, ADSTRANS_SERVERCYCLE, 220, hConnect, hUser );
     LabelConExRetData.Caption:=Format( 'adsResult:%d   hConnect:%d', [adsResult, hConnect] );
end;

 

Wurde die Verbindung erfolgreich aufgebaut, dann werden in der Event-Funktion AdsReadConnectUpdateEx2 die Parameter als Text auf der Form ausgegeben.

procedure TForm1.AdsOcx1AdsReadConnectUpdateEx2(Sender: TObject;
  dateTime: TDateTime; nMs, hConnect: Integer; var data,
  hUser: OleVariant);
begin
     LabelConExEventData.Caption :=Format('Date/Time:%s   nMs:%d   hConnect:%d   data:%d   hUser:%d',
                [ TimeToStr(dateTime), nMs, hConnect, integer(data), integer(hUser)]);
end;

 

Bei einem Mausklick auf den Button DisconnectEx wird die Methode AdsDisconnectEx aufgerufen und die Verbindung  zu der SPS-Variablen abgebaut.

procedure TForm1.OnDisconnectExClick(Sender: TObject);
begin
     adsResult := AdsOcx1.AdsDisconnectEx( hConnect );
     if adsResult = 0 then
     hConnect := 0;

     LabelConExRetData.Caption:=Format( 'adsResult:%d', [adsResult] );
end;

Bemerkung:

Bei der Einbindug des ADS-OCX in Delphi-Applikationen wurde festgestellt, dass von der Entwicklungsumgebung von Delphi fehlerhafte Prototypen (genauer: fehlerhafte Parameterübergabe bei den OleVariant-Typen) der Event-Funktion AdsReadConnectUpdateEx generiert wurde.  Aus diesem Grund wurde das ADS-OCX um eine neue Methode AdsReadVarConnectEx2 und eine dazugehörende Event-Funktion AdsReadConnectUpdateEx2 ergänzt. In der neuen Event-Funktion werden die OleVariant-Parameter per Referenz statt per Wert übergeben.

Other

procedure TForm1.Exit1Click(Sender: TObject);
begin
    Close();
end;

procedure TForm1.Properties1Click(Sender: TObject);
begin
    AdsOcx1.BrowseProperties();
end;

procedure TForm1.About1Click(Sender: TObject);
begin
    AdsOcx1.AboutBox();
end;

Initialization
    IsMultiThread := True;// Setting this system variable makes Delphi's memory manager thread-safe 

SPS Programm

PROGRAM MAIN
VAR
    VARINT16    AT%MB100:INT;
END_VAR

Sprache / IDE

Beispielprogramm auspacken

Delphi XE2

Sample01.exe

Delphi 5 oder höher (classic)