Event-driven reading of PLC variables
Requirements:
- Delphi 5.0 or higher;
- TwinCAT 2.9 or higher;
- The TcAdsDll.dll type library has to be imported (TcAdsDll_TLB.pas unit). Depending on the Delphi version, manual adjustments may be required in order to ensure error-free compilation.
In the FormCreate event function a connection to the server in the local system is established via CoTcClient.Create. The Connect method is then used to establish a connection to the first PLC runtime system (port 801) on the local computer (netid = '0.0.0.0.0.0'). When the Start button is pressed, a connection to the PLC variables is established via the AddDeviceNotification method. If a PLC variable changes, the server calls the DeviceNotification function of the _ITcAdsSyncEvents interface. In order to be able to send events to the client, this interface must be implemented in the client. In addition, the server has to be informed about their existence. This is achieved by calling the InterfaceConnect procedure. The connections are canceled via the DelDeviceNotification method by pressing the Stop button.

The Delphi program
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, TcAdsDll_TLB, OleServer, ComObj,activex, Math;
type
TForm1 = class( TForm, IUnknown, _ITcAdsSyncEvents )
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
TcClient : ITcClient;
TcAdsSync : ITcAdsSync;
dwCookie : integer;
hInteger, hDouble : integer;
serverAddr : AmsNetId;
function DeviceNotification(var pTime: TimeStamp; hNotification: Integer; cbLen: Integer; var pData: Byte): HResult; stdcall;
end;
type
PINT = ^Smallint;
PLREAL= ^Double;
var
Form1: TForm1;
implementation
{$R *.DFM}
/////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
begin
serverAddr.b[0] := 0;
serverAddr.b[1] := 0;
serverAddr.b[2] := 0;
serverAddr.b[3] := 0;
serverAddr.b[4] := 0;
serverAddr.b[5] := 0;
Button1.Enabled := True;
Button2.Enabled := False;
try
TcClient := CoTcClient.Create();
try
OleCheck(TcClient.Connect( serverAddr, 801,TcAdsSync));
InterfaceConnect(TcAdsSync ,IID__ITcAdsSyncEvents,self as IUnknown, dwCookie);
except
ShowMessage('TcClient.Connect() failed!');
end;
except
ShowMessage('CoTcClient.Create() failed!');
end;
end;
/////////////////////////////////////////////////////////////////////////
procedure TForm1.FormDestroy(Sender: TObject);
begin
if hInteger <> 0 then
OleCheck(TcAdsSync.DelDeviceNotification(hInteger));
if hDouble <> 0 then
OleCheck(TcAdsSync.DelDeviceNotification(hDouble));
InterfaceDisconnect(TcAdsSync,IID__ITcAdsSyncEvents, dwCookie);
end;
/////////////////////////////////////////////////////////////////////////
procedure TForm1.Button1Click(Sender: TObject);
begin
hInteger := 0;
hDouble := 0;
try
OleCheck(TcAdsSync.AddDeviceNotification($4020, 2, sizeof(Smallint), ADSTRANS_SERVERONCHA, 0, 1000000, hInteger ));
OleCheck(TcAdsSync.AddDeviceNotification($4020, 12, sizeof(Double), ADSTRANS_SERVERONCHA, 0, 1000000, hDouble ));
Button1.Enabled := False;
Button2.Enabled := True;
except
ShowMessage('TcAdsSync.AddDeviceNotification() failed!');
end;
end;
/////////////////////////////////////////////////////////////////////////
procedure TForm1.Button2Click(Sender: TObject);
begin
try
OleCheck(TcAdsSync.DelDeviceNotification(hInteger));
OleCheck(TcAdsSync.DelDeviceNotification(hDouble));
Button1.Enabled := True;
Button2.Enabled := False;
except
ShowMessage('TcAdsSync.DelDeviceNotification() failed!');
end;
hInteger := 0;
hDouble := 0;
end;
/////////////////////////////////////////////////////////////////////////
function TForm1.DeviceNotification(var pTime: TimeStamp; hNotification: Integer; cbLen: Integer; var pData: Byte): HResult; stdcall;
var
SystemTime, LocalTime : _SYSTEMTIME;
TimeZoneInformation : _TIME_ZONE_INFORMATION;
stamp : TDateTime;
begin
FileTimeToSystemTime(_FILETIME(pTime), SystemTime);
GetTimeZoneInformation(TimeZoneInformation);
SystemTimeToTzSpecificLocalTime(@TimeZoneInformation, SystemTime, LocalTime);
stamp := SystemTimeToDateTime(LocalTime);
if hNotification = hInteger then
Label1.Caption := Format( 'PLCIntVar, %s %s, hNot:%d, cbLen:%d, data:%d',[DateToStr(stamp), TimeToStr(stamp), hNotification, cbLen, PINT(Addr(pData))^] )
else
Label2.Caption := Format( 'PLCLRealVar, %s %s, hNot:%d, cbLen:%d, data:%f',[DateToStr(stamp), TimeToStr(stamp), hNotification, cbLen, PLREAL(Addr(pData))^] );
Result := S_OK;
end;
initialization
IsMultiThread := True;
end.
PLC program
PROGRAM MAIN
VAR
PLCBoolVar AT %MX0.0 : BOOL := TRUE;
PLCIntVar AT %MB2 : INT := 75;
PLCDIntVar AT %MB4 : DINT := 43234532;
PLCRealVar AT %MB8 : REAL := 3.1415;
PLCLRealVar AT %MB12 : LREAL := 3.141592654;
END_VAR
PLCLRealVar := PLCLRealVar +1;
PLCIntVar :=PLCIntVar +1;
Language / IDE | Unpack sample program |
---|---|
Delphi XE2 | |
Delphi 5 or higher (classic) |