ADS Summenkommando: Das Holen und Freigeben von mehreren Variable-Handles mit einem ADS-Kommando.
Voraussetzungen:
- TwinCAT v2.11 Build >= 1550;
- Delphi 6.0 + Update Pack 2 oder höher;
- TcAdsDLL.DLL;
- TcAdsDEF.pas und TcAdsAPI.pas, enthalten in der Datei delphi_adsdll_api_units.zip, falls Sie den Quelltext selber übersetzen möchten;
Aufgabenstellung
Beim Start der einfachen Windows-Applikation sollen Handles für 15 SPS-Variablen mit einem Summenkommando geholt werden. Mit diesen Handles kann z. B. auf die Variablen lesend zugegriffen werden. Beim Beenden der Applikation sollen die Handles mit einem Summenkommando freigegeben werden.
In Delphi ist es möglich offene Arrayparameter an Funktionen zu übergeben. D.h. die Anzahl der Arrayelemente in so einem Funktionsparameter ist nicht festgelegt. In der TcAdsApi.pas-Datei wurden drei neue Funktionen implementiert: AdsSyncSumReadReq, AdsSyncSumWriteReq und AdsSyncSumReadWriteReq. Diese Funktionen benutzen die Funktionalität der offenen Arrayparameter und vereinfachen die Benutzung des Summenkomandos unter Delphi. Das Beispielprojekt nutzt diese neuen Wrapper-Funktionen.
Das SPS-Programm
Die SPS-Variablen wurden als globale Variablen deklariert. Bei einer gestarteten SPS werden Wertänderungen der Variablen im einfachen MAIN-Programm simuliert.
VAR_GLOBAL
nBits : BYTE;
wBits : WORD;
dwBits : DWORD;
f32AxPos : REAL;
f64AxPos : LREAL;
bEnable : BOOL;
sValue : STRING := 'INIT';
ui8Num : USINT;
ui16Num : UINT;
ui32Num : UDINT;
i8Num : SINT;
i16Num : INT;
i32Num : DINT;
aui32 : ARRAY[0..9] OF DWORD;
out8Bit AT%QX0.1 : BOOL;
END_VAR
Delphi 6 Programm
Die Deklarationen der benutzten TcAdsDLL-Funktionen befinden sich in den Pascal-Units TcAdsDEF.pas und TcAdsAPI.pas. Diese wurden über eine Uses-Klausel in das Projekt eingebunden.
unit Unit1;
interface
uses
TcAdsDEF, TcAdsAPI, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Math;
Beim Programmstart wird der Kommunikationsport geöffnet und beim Beenden geschlossen.
type TAdsHandleInfo = packed record // packed = 1 byte alignment
name : AnsiString;// symbol name
handle : Longword; // symbol handle
data : Array Of Byte;// data bytes (resize the dynamic array to size of the plc variables)
end;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure CreateHandleList();
procedure ReleaseHandleList();
procedure ReadListByHandle();
procedure Button1Click(Sender: TObject);
private
infos : Array of TAdsHandleInfo;
client : Longint;
amsAddr : TAmsAddr;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Handles holen
implementation
{$R *.dfm}
////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
var adsErr : Longint;
begin
client := AdsPortOpen(); // open ads port
if client <> 0 then
begin
adsErr := AdsGetLocalAddress( @amsAddr );
if adsErr = 0 then
begin
amsAddr.port := AMSPORT_R0_PLC_RTS1; // set port to 801 (first PLC run time system)
CreateHandleList();
end
else
ShowMessageFmt('AdsGetLocalAddress() error: %d [0x%X]', [adsErr, adsErr]);
end
else
ShowMessage('AdsPortOpen() failed!');
end;
////////////////////////////////////////////////////////////////////////////
procedure TForm1.CreateHandleList();
var igList, ioList, writeLenList, readLenList, retLenList : Array of Longword;
writePtrList, readPtrList : Array of Pointer;
resList : Array of Longint;
i, adsErr : Longint;
nInfos : Longword;
begin
nInfos := 15;
SetLength(infos, nInfos);
infos[0].name := '.nBits';
SetLength( infos[0].data, 1);//BYTE
infos[1].name := '.wBits';
SetLength( infos[1].data, 2);//WORD
infos[2].name := '.dwBits';
SetLength( infos[2].data, 4);//DWORD
infos[3].name := '.f32AxPos';
SetLength( infos[3].data, 4);//REAL
infos[4].name := '.f64AxPos';
SetLength( infos[4].data, 8);//LREAL
infos[5].name := '.bEnable';
SetLength( infos[5].data, 1);//BOOL
infos[6].name := '.sValue';
SetLength( infos[6].data, 81);//STRING(80) + 1 byte null delimiter
infos[7].name := '.ui8Num';
SetLength( infos[7].data, 1);//USINT
infos[8].name := '.ui16Num';
SetLength( infos[8].data, 2);//UINT
infos[9].name := '.ui32Num';
SetLength( infos[9].data, 4);//UDINT
infos[10].name := '.i8Num';
SetLength( infos[10].data, 1);//SINT
infos[11].name := '.i16Num';
SetLength( infos[11].data, 2);//INT
infos[12].name := '.i32Num';
SetLength( infos[12].data, 4);//DINT
infos[13].name := '.aui32';
SetLength( infos[13].data, 40);//ARRARY[..9] OF DWORD
infos[14].name := '.out8Bit';
SetLength( infos[14].data, 1);// 1 Byte
SetLength(igList, nInfos);
SetLength(ioList, nInfos);
SetLength(readLenList, nInfos);
SetLength(readPtrList, nInfos);
SetLength(writeLenList, nInfos);
SetLength(writePtrList, nInfos);
SetLength(resList, nInfos);
SetLength(retLenList, nInfos);
for i:=Low(infos) to High(infos) do
begin
igList[i] := ADSIGRP_SYM_HNDBYNAME;
ioList[i] := $0000000;
readLenList[i] := SizeOf(infos[i].handle);
readPtrList[i] := @infos[i].handle;
writeLenList[i] := Length(infos[i].name) + 1;
writePtrList[i] := @infos[i].name[1];
resList[i] := 0;
retLenList[i] := 0;
end;
adsErr := AdsSyncSumReadWriteReq( @amsAddr, igList, ioList,
readLenList, readPtrList,
writeLenList, writePtrList,
resList,retLenList );
// parse received data
if adsErr = 0 then
begin
for i:=Low(resList) to High(resList) do
begin
if resList[i] <> 0 then
ShowMessageFmt('AdsSyncSumReadWriteReq(ADSIGRP_SYM_HNDBYNAME) error:%d [0x%X], handle:0x%X', [resList[i], resList[i], infos[i].handle]);
ListBox1.Items.Add(Format('CREATE name: %s, result:%d [0x%X], handle:0x%X', [infos[i].name, resList[i], resList[i], infos[i].handle] )); end;
end
else
ShowMessageFmt('AdsSyncSumReadWriteReq() error:%d [0x%X]', [adsErr, adsErr]);
end;
Handles freigeben
////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if client <> 0 then
begin
ReleaseHandleList();
AdsPortClose();// close ads port
end;
end;
////////////////////////////////////////////////////////////////////////////
procedure TForm1.ReleaseHandleList();
var igList, ioList, lenList : Array of Longword;
srcList : Array of Pointer;
resList : Array of Longint;
i, adsErr : Longint;
begin
SetLength(igList, Length(infos));
SetLength(ioList, Length(infos));
SetLength(lenList, Length(infos));
SetLength(srcList, Length(infos));
SetLength(resList, Length(infos));
for i:= Low(infos) to High(infos) do
begin
igList[i] := ADSIGRP_RELEASE_SYMHND;
ioList[i] := $00000000;
lenList[i] := SizeOf(infos[i].handle);
srcList[i] := @infos[i].handle;
resList[i] := 0;
end;
adsErr := AdsSyncSumWriteReq( @amsAddr,
igList,
ioList,
lenList,
srcList,
resList );
if adsErr = 0 then
begin
for i:= Low(resList) to High(resList) do
begin
if resList[i] = 0 then // release successfull
infos[i].handle := 0// set to null
else
ShowMessageFmt('AdsSyncSumWriteReq(ADSIGRP_RELEASE_SYMHND) error: %d [0x%X], handle:0x%X', [resList[i], resList[i], infos[i].handle]);
ListBox1.Items.Add(Format('RELEASE name: %s, result:%d [0x%X], handle:0x%X', [infos[i].name, resList[i], resList[i], infos[i].handle] ));
end;
end
else
ShowMessageFmt('AdsSyncSumWriteReq() error: %d [0x%X]', [adsErr, adsErr]);
end;
Werte lesen "by name"
////////////////////////////////////////////////////////////////////////////
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Clear();
ReadListByHandle();
end;
////////////////////////////////////////////////////////////////////////////
procedure TForm1.ReadListByHandle();
var igList, ioList, lenList : Array of Longword;
destList : Array of Pointer;
resList : Array of Longint;
i, adsErr : Longint;
b : Longint;
sValue : String;
cbValue : Longint;
begin
SetLength(igList, Length(infos));
SetLength(ioList, Length(infos));
SetLength(lenList, Length(infos));
SetLength(destList, Length(infos));
SetLength(resList, Length(infos));
for i:= Low(infos) to High(infos) do
begin
igList[i] := ADSIGRP_SYM_VALBYHND;
ioList[i] := infos[i].handle;
lenList[i] := Length(infos[i].data){ * SizeOf(infos[i].data[0])};
destList[i] := @infos[i].data[0];
resList[i] := 0;
end;
adsErr := AdsSyncSumReadReq( @amsAddr,
igList,
ioList,
lenList,
destList,
resList );
if adsErr = 0 then
begin
for i:= Low(resList) to High(resList) do
begin
if resList[i] = 0 then
begin
//TODO: save read data...
//Convert data to hex string and show it on the form
sValue := '';
cbValue := Length(infos[i].data){ * SizeOf(infos[i].data[0])};
if cbValue > 0 then
for b:= 0 to (cbValue - 1) do
sValue := sValue + IntToHex( infos[i].data[b], 2 ) + ' ' ;
ListBox1.Items.Add(Format('READ name: %s, value:%s', [infos[i].name, sValue] ));
end
else
ShowMessageFmt('AdsSyncSumReadReq(ADSIGRP_SYM_VALBYHND) error: %d [0x%X], handle:0x%X', [resList[i], resList[i], infos[i].handle]);
end;
end
else
ShowMessageFmt('AdsSyncSumReadReq() error: %d [0x%X]', [adsErr, adsErr]);
end;
end.
Sprache / IDE | Beispielprogram auspacken |
---|---|
Delphi XE2 | |
Delphi 6 oder höher (classic) |