Synchronous access to PLC variables
Requirements:
- Delphi 5.0 or higher;
- TcAdsDLL.DLL;
- TcAdsDEF.pas and TcAdsAPI.pas, contained in the file delphi_adsdll_api_units.zip, if you want to compile the source code yourself;
The task
Synchronous read and write access to a PLC variable is required from the Windows application. The variable is of type integer (16 bits), and is located at offset 520 in the flags area of the PLC's first runtime system.

The PLC program
The PLC variable is initialized with the value 7 when the PLC starts.
PROGRAM MAIN
VAR
VARINT16 AT%MB520 :INT:=7;
END_VAR
Delphi 5 program
The declarations for the TcAdsDLL functions used are located in the Pascal units TcAdsDEF.pas and TcAdsAPI.pas. They were linked in the project via a Uses clause.
unit DelphiAdsDLLSample1Unit;
interface
uses
TcAdsDEF, TcAdsAPI, Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls;
The sample application
The DLL function AdsPortOpen is called in the FormCreate event function. This function returns an open port number when successful, otherwise it returns a zero. If any errors do occur, they are reported to the user through a message box. The port must be closed again when closing the application. The DLL function AdsPortClose is called in the FormDestroy event function.
If the Ads port is opened successfully, a further DLL function is called: AdsGetLocalAddress. This returns the AMS address of the local TwinCAT PC. The AMS address is needed for write/read access to the PLC variables.
var
Form1 : TForm1;
ClientPort : longint;
LocalAddr : TAmsAddr;
IndexGroup : Integer;
IndexOffset : Integer;
varHandle : Integer;
Result : longint;
varValue : Smallint;
const varName: AnsiString = 'MAIN.VARINT16'; //Symbol name
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ClientPort:= AdsPortOpen();
if ClientPort > 0 then {OK}
begin
Result:=AdsGetLocalAddress( @LocalAddr );
if Result = 0 Then {OK}
begin
AdsState.Panels.Items[5].Text:= Format('%d.%d.%d.%d.%d.%d',[
LocalAddr.netId.b[0], LocalAddr.netId.b[1], LocalAddr.netId.b[2],
LocalAddr.netId.b[3], LocalAddr.netId.b[4], LocalAddr.netId.b[5]]);
AdsState.Panels.Items[1].Text:=IntToStr( ClientPort );
LocalAddr.port := 801; //Set the Ads port number for read/write/readwrite
IndexGroup := $00004020; {memory range}
IndexOffset := 520; {byte offset of the PLC variable}
end
else {error}
begin
AdsState.Panels.Items[3].Text:=IntToStr( Result );
MessageBox(NULL,'AdsGetLocalAddress()', 'Error!', MB_OK)
end;
end
else {error}
MessageBox( NULL,'AdsPortOpen()', 'Error!', MB_OK );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
AdsPortClose();
end;
When the AdsSyncRead button is clicked, the value of the PLC variable is read synchronously via its allocated address, and displayed on the form. This involves the DLL function AdsSyncReadReq being called in the OnSyncReadButtonClick event function. The IndexGroup and IndexOffset parameters are defined as global variables. There values are, correspondingly, set when the application starts.
procedure TForm1.OnSyncReadButtonClick(Sender:
TObject);
begin
Result := AdsSyncReadReq( @LocalAddr,
IndexGroup, IndexOffset, sizeof(varValue), @varValue );
ReadLabel.Caption := Format( 'Result:
%d, Value: %d', [Result, varValue]);
end;
Write access to the variable is implemented in a similar way. In the event function OnSyncWriteButtonClick the DLL function AdsSyncWriteReq is called, and the value of the PLC variable set to 200.
procedure
TForm1.OnSyncWriteButtonClick(Sender: TObject);
begin
varValue := 200;
Result := AdsSyncWriteReq( @LocalAddr,
IndexGroup, IndexOffset, sizeof(varValue), @varValue );
WriteLabel.Caption := Format( 'Result:
%d', [Result]);
end;
Simultaneous read and write access to PLC variables can be implemented with the aid of the DLL function AdsSyncReadWriteReq. The value of the variable is read in the sample by means of a handle. The variable's handle is first requested by the AdsSyncReadWriteReq function. With this handle, the value of the variable can be read with the function AdsSyncReadReq. The handle must always be released by means of the AdsSyncWriteReq function.
procedure
TForm1.OnGetValueByHandleClick(Sender: TObject);
begin
{get handle}
Result := AdsSyncReadWriteReq( @LocalAddr,
ADSIGRP_SYM_HNDBYNAME, 0, sizeof(varHandle), @varHandle,
Length(varName) + 1, @varName[1] );
GetHandleLabel.Caption := Format('Get
handle result: %d, Handle: 0x%x', [Result, varHandle] );
{get value}
Result := AdsSyncReadReq( @LocalAddr,
ADSIGRP_SYM_VALBYHND, varHandle, sizeof(varValue), @varValue
);
GetValueLabel.Caption := Format( 'Get
value result: %d, Value: %d', [Result, varValue] );
{release handle}
Result := AdsSyncWriteReq( @LocalAddr,
ADSIGRP_RELEASE_SYMHND, 0, sizeof(varHandle), @varHandle );
ReleaseHandleLabel.Caption := Format(
'Release handle result: %d', [Result] );
end;
If the values of several PLC variables are to be read frequently, the necessary handles can be requested when the application starts in the FormCreate event function. They can then only be released in the FormDestroy event function when the application is closed.
Language / IDE | Unpack sample program |
---|---|
Delphi XE2 | |
Delphi 5 or higher (classic) |