Hinweise zur Dokumentation

Diese Beschreibung wendet sich ausschließlich an ausgebildetes Fachpersonal der Steuerungs- und Automatisierungstechnik, das mit den geltenden nationalen Normen vertraut ist.
Zur Installation und Inbetriebnahme der Komponenten ist die Beachtung der Dokumentation und der nachfolgenden Hinweise und Erklärungen unbedingt notwendig.
Das Fachpersonal ist verpflichtet, für jede Installation und Inbetriebnahme die zu dem Zeitpunkt veröffentlichte Dokumentation zu verwenden.

Das Fachpersonal hat sicherzustellen, dass die Anwendung bzw. der Einsatz der beschriebenen Produkte alle Sicherheitsanforderungen, einschließlich sämtlicher anwendbaren Gesetze, Vorschriften, Bestimmungen und Normen erfüllt.

Disclaimer

Diese Dokumentation wurde sorgfältig erstellt. Die beschriebenen Produkte werden jedoch ständig weiter entwickelt.
Wir behalten uns das Recht vor, die Dokumentation jederzeit und ohne Ankündigung zu überarbeiten und zu ändern.
Aus den Angaben, Abbildungen und Beschreibungen in dieser Dokumentation können keine Ansprüche auf Änderung bereits gelieferter Produkte geltend gemacht werden.

Marken

Beckhoff®, TwinCAT®, EtherCAT®, EtherCAT G®, EtherCAT G10®, EtherCAT P®, Safety over EtherCAT®, TwinSAFE®, XFC®, XTS® und XPlanar® sind eingetragene und lizenzierte Marken der Beckhoff Automation GmbH.
Die Verwendung anderer in dieser Dokumentation enthaltenen Marken oder Kennzeichen durch Dritte kann zu einer Verletzung von Rechten der Inhaber der entsprechenden Bezeichnungen führen.

Patente

Die EtherCAT Technologie ist patentrechtlich geschützt, insbesondere durch folgende Anmeldungen und Patente:
EP1590927, EP1789857, EP1456722, EP2137893, DE102015105702
mit den entsprechenden Anmeldungen und Eintragungen in verschiedenen anderen Ländern.

EtherCAT® ist eine eingetragene Marke und patentierte Technologie lizenziert durch die Beckhoff Automation GmbH, Deutschland.

Copyright

© Beckhoff Automation GmbH & Co. KG, Deutschland.
Weitergabe sowie Vervielfältigung dieses Dokuments, Verwertung und Mitteilung seines Inhalts sind verboten, soweit nicht ausdrücklich gestattet.
Zuwiderhandlungen verpflichten zu Schadenersatz. Alle Rechte für den Fall der Patent-, Gebrauchsmuster- oder Geschmacksmustereintragung vorbehalten.


Übersicht

Integration in Visual Basic

Beschreibung
Visual Basic 6.0 Variablenlängen

TwinCAT ADS-OCX

Beschreibung
Einbinden der ADS-OCX-Komponente in Visual Basic 6.0
Manuelle Installation der ADS-OCX-Komponente
Beschreibung | Quelltexte
Beispiel 1: Zugriff auf ein Array in der SPS | ADS-OCX Sample01.exe
Beispiel 2: Übertragen von Strukturen an die SPS | ADS-OCX Sample02.exe
Beispiel 3: Ereignisgesteuertes Lesen | ADS-OCX Sample03.exe
Beispiel 4: SPS-Variablendeklaration auslesen | ADS-OCX Sample04.exe
Beispiel 5: Status vom TwinCAT-Router und der SPS erkennen/verändern | ADS-OCX Sample05.exe
Beispiel 6: Meldungen über den TwinCAT-Router senden/empfangen | ADS-OCX Sample06.exe
Beispiel 7: Handle einer SPS Variablen löschen | ADS-OCX Sample07.exe
Beispiel 9: Ereignisgesteuertes Lesen ( mit Konvertierung in einen anderen Typ) | ADS-OCX Sample09.exe

TwinCAT ADS-DLL

Beschreibung | Quelltexte
Beispiel 1: Lesen und Schreiben von Variablen mit Visual Basic | TcAdsDll ComSample01.exe
Beispiel 2: Ereignisgesteuertes Lesen mit Visual Basic | TcAdsDll ComSample02.exe

TwinCAT ADS.NET

Beschreibung
Einbinden der ADS.NET-Komponente in Microsoft Visual Studio .NET (VB)
Beschreibung | Quelltexte (for .NET framework)
Beispiel 1: Zugriff auf ein Array in der SPS | TwinCATADS_VBSample01.exe
Beispiel 2: Übertragen von Strukturen an die SPS | TwinCATADS_VBSample02.exe
Beispiel 3: Ereignisgesteuertes Lesen | TwinCATADS_VBSample03.exe
Beispiel 4: Lesen und Schreiben von STRING-Variablen | TwinCATADS_VBSample04.exe TwinCAT.Ads.NET v1.0.0.10 und höher: TwinCATADS_VBSample04b.exe
Beispiel 5: Lesen und Schreiben von DATE/TIME-Variablen | TwinCATADS_VBSample05.exe
Beispiel 6: SPS-Variablendeklaration auslesen | TwinCATADS_VBSample06.exe
Beispiel 7: Lesen und Schreiben von SPS-Variablen eines beliebigen Types (ReadAny, WriteAny) | TwinCATADS_VBSample07.exe

TwinCAT ADS-Script-DLL

Beschreibung | Quelltexte
Beispiel 2: Lesen und Schreiben von SPS-Variablen | ADS-Script-DLL Sample02.exe


ADS Return Codes

Error codes: 0x000..., 0x500..., 0x700..., 0x1000..., 0x274C...

Global Error Codes

Hex | Dec | Description | Possible Causes | Solution
0x0 | 0 | no error |  |
0x1 | 1 | Internal error |  |
0x2 | 2 | No Rtime |  |
0x3 | 3 | Allocation locked memory error |  |
0x4 | 4 | Insert mailbox error | No ADS mailbox was available to process this message. | Reduce the number of ADS calls (e.g ADS-Sum commands or Max Delay Parameter)
0x5 | 5 | Wrong receive HMSG |  |
0x6 | 6 | target port not found | ADS Server not started |
0x7 | 7 | target machine not found | Missing ADS routes |
0x8 | 8 | Unknown command ID |  |
0x9 | 9 | Bad task ID |  |
0xA | 10 | No IO |  |
0xB | 11 | Unknown ADS command |  |
0xC | 12 | Win 32 error |  |
0xD | 13 | Port not connected |  |
0xE | 14 | Invalid ADS length |  |
0xF | 15 | Invalid AMS Net ID |  |
0x10 | 16 | Low Installation level |  |
0x11 | 17 | No debug available |  |
0x12 | 18 | Port disabled |  |
0x13 | 19 | Port already connected |  |
0x14 | 20 | ADS Sync Win32 error |  |
0x15 | 21 | ADS Sync Timeout |  |
0x16 | 22 | ADS Sync AMS error |  |
0x17 | 23 | ADS Sync no index map |  |
0x18 | 24 | Invalid ADS port |  |
0x19 | 25 | No memory |  |
0x1A | 26 | TCP send error |  |
0x1B | 27 | Host unreachable |  |
0x1C | 28 | Invalid AMS fragment |  |

Router Error Codes

Hex | Dec | Description | Possible Causes | Solution
0x500 | 1280 | ROUTERERR_NOLOCKEDMEMORY | No locked memory can be allocated |
0x501 | 1281 | ROUTERERR_RESIZEMEMORY | The size of the router memory could not be changed |
0x502 | 1282 | ROUTERERR_MAILBOXFULL | The mailbox has reached the maximum number of possible messages. The current sent message was rejected | Check the connection between the communication partners
0x503 | 1283 | ROUTERERR_DEBUGBOXFULL | The mailbox has reached the maximum number of possible messages. The sent message will not be displayed in the debug monitor | Check the connection to the debug monitor
0x504 | 1284 | ROUTERERR_UNKNOWNPORTTYPE | The port type is unknown |
0x505 | 1285 | ROUTERERR_NOTINITIALIZED | Router is not initialised |
0x506 | 1286 | ROUTERERR_PORTALREADYINUSE | The desired port number is already assigned |
0x507 | 1287 | ROUTERERR_NOTREGISTERED | Port not registered |
0x508 | 1288 | ROUTERERR_NOMOREQUEUES | The maximum number of Ports reached |
0x509 | 1289 | ROUTERERR_INVALIDPORT | The port is invalid. |
0x50A | 1290 | ROUTERERR_NOTACTIVATED | TwinCAT Router not active |
0x50B | 1291 | ROUTERERR_FRAGMENTBOXFULL |  |
0x50C | 1292 | ROUTERERR_FRAGMENTTIMEOUT |  |
0x50D | 1293 | ROUTERERR_TOBEREMOVED |  |

General ADS Error Codes

Hex | Dec | Description | Possible Causes | Solution
0x700 | 1792 | error class <device error> |  |
0x701 | 1793 | Service is not supported by server |  |
0x702 | 1794 | invalid index group |  |
0x703 | 1795 | invalid index offset |  |
0x704 | 1796 | reading/writing not permitted |  |
0x705 | 1797 | parameter size not correct |  |
0x706 | 1798 | invalid parameter value(s) |  |
0x707 | 1799 | device is not in a ready state |  |
0x708 | 1800 | device is busy |  |
0x709 | 1801 | invalid context (must be in Windows) |  |
0x70A | 1802 | out of memory |  |
0x70B | 1803 | invalid parameter value(s) |  |
0x70C | 1804 | not found (files, ...) |  |
0x70D | 1805 | syntax error in command or file |  |
0x70E | 1806 | objects do not match |  |
0x70F | 1807 | object already exists |  |
0x710 | 1808 | symbol not found |  |
0x711 | 1809 | symbol version invalid | Onlinechange | Release handle and get a new one
0x712 | 1810 | server is in invalid state |  |
0x713 | 1811 | AdsTransMode not supported |  |
0x714 | 1812 | Notification handle is invalid | Onlinechange | Release handle and get a new one
0x715 | 1813 | Notification client not registered |  |
0x716 | 1814 | no more notification handles |  |
0x717 | 1815 | size for watch too big |  |
0x718 | 1816 | device not initialized |  |
0x719 | 1817 | device has a timeout |  |
0x71A | 1818 | query interface failed |  |
0x71B | 1819 | wrong interface required |  |
0x71C | 1820 | class ID is invalid |  |
0x71D | 1821 | object ID is invalid |  |
0x71E | 1822 | request is pending |  |
0x71F | 1823 | request is aborted |  |
0x720 | 1824 | signal warning |  |
0x721 | 1825 | invalid array index |  |
0x722 | 1826 | symbol not active | Onlinechange | Release handle and get a new one
0x723 | 1827 | access denied |  |
0x724 | 1828 | missing license |  | Activate license for TwinCAT 3 function
0x72c | 1836 | exception occured during system start |  | Check each device transistions
0x740 | 1856 | Error class <client error> |  |
0x741 | 1857 | invalid parameter at service |  |
0x742 | 1858 | polling list is empty |  |
0x743 | 1859 | var connection already in use |  |
0x744 | 1860 | invoke ID in use |  |
0x745 | 1861 | timeout elapsed |  | Check ADS routes of sender and receiver and your firewall setting
0x746 | 1862 | error in win32 subsystem |  |
0x747 | 1863 | Invalid client timeout value |  |
0x748 | 1864 | ads-port not opened |  |
0x750 | 1872 | internal error in ads sync |  |
0x751 | 1873 | hash table overflow |  |
0x752 | 1874 | key not found in hash |  |
0x753 | 1875 | no more symbols in cache |  |
0x754 | 1876 | invalid response received |  |
0x755 | 1877 | sync port is locked |  |

RTime Error Codes

Hex | Dec | Description | Possible Causes
0x1000 | 4096 | RTERR_INTERNAL | Internal fatal error in the TwinCAT real-time system
0x1001 | 4097 | RTERR_BADTIMERPERIODS | Timer value not vaild
0x1002 | 4098 | RTERR_INVALIDTASKPTR | Task pointer has the invalid value ZERO
0x1003 | 4099 | RTERR_INVALIDSTACKPTR | Task stack pointer has the invalid value ZERO
0x1004 | 4100 | RTERR_PRIOEXISTS | The demand task priority is already assigned
0x1005 | 4101 | RTERR_NOMORETCB | No more free TCB (Task Control Block) available. Maximum number of TCBs is 64
0x1006 | 4102 | RTERR_NOMORESEMAS | No more free semaphores available. Maximum number of semaphores is 64
0x1007 | 4103 | RTERR_NOMOREQUEUES | No more free queue available. Maximum number of queue is 64
0x1008 | 4104 | TwinCAT reserved. |
0x1009 | 4105 | TwinCAT reserved. |
0x100A | 4106 | TwinCAT reserved. |
0x100B | 4107 | TwinCAT reserved. |
0x100C | 4108 | TwinCAT reserved. |
0x100D | 4109 | RTERR_EXTIRQALREADYDEF | An external synchronisation interrupt is already applied
0x100E | 4110 | RTERR_EXTIRQNOTDEF | No external synchronsiation interrupt applied
0x100F | 4111 | RTERR_EXTIRQINSTALLFAILED | The apply of the external synchronisation interrupt failed
0x1010 | 4112 | RTERR_IRQLNOTLESSOREQUAL | Call of a service function in the wrong context
0x1017 | 4119 | RTERR_VMXNOTSUPPORTED | Intel VT-x extension is not supported.
0x1018 | 4120 | RTERR_VMXDISABLED | Intel VT-x extension is not enabled in BIOS.
0x1019 | 4121 | RTERR_VMXCONTROLSMISSING | Missing feature in Intel VT-x extension.
0x101A | 4122 | RTERR_VMXENABLEFAILS | Enabling Intel VT-x fails.

TCP Winsock Error Codes

Hex | Dec | Description | Possible Causes | Solution
0x274c | 10060 | A socket operation was attempted to an unreachable host | Host unreachable | Check network connection via ping
0x274d | 10061 | A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. | Host unreachable | Check network connection via ping
0x2751 | 10065 | No connection could be made because the target machine actively refused it |  |
 |  | Further Winsock error codes: Win32 Error Codes |  |


Visual Basic 6.0 Variablenlängen

VB-Variablentyp | Variablenlänge in Byte
Boolean | 2
Integer | 2
Long | 4
Single | 4
Double | 8
String | Anzahl der Zeichen * 2
Byte | 1

Größen von Arrays

Die Länge eines Arrays berechnet sich aus der Anzahl der einzelnen Array-Elemente, multipliziert mit der Länge des Variablentyps.

Beispiel

Soll ein Array von 5 Long Elementen ausgelesen werden, beträgt die Länge 20 Byte(5 Elemente * 4 Byte).

Bei einem String mit 25 Zeichen, beträgt die Länge 50 Byte(25 Zeichen * 2 Byte).


Einbinden in Visual Basic

ADS-OCX auswählen

Um das ADS-OCX auszuwählen müssen Sie in Visual Basic unter dem Menüpunkt Projekt den Befehl Komponenten... auswählen und den Eintrag AdsOcx OLE Control module markieren.

Anschließend erscheint das ADS-OCX in der Toolbox von Visual Basic (rechts unten).

Eigenschaften definieren

Bevor Sie das ADS-OCX nutzen können, müssen Sie dieses auf eine Form ziehen und die Eigenschaften einstellen. Die allgemeinen Eigenschaften können über die Eigenschaften Seiten des ADS-OCX oder in der Visual Basic Eigenschaften-Liste konfiguriert bzw. ausgelesen werden. Sehr übersichtlich ist die Darstellung in der Eigenschaften Seite, da hier die Eigenschaften nach Gruppen sortiert dargestellt werden. Damit das Visual Basic-Programm besser lesbar ist, fangen (fast) alle Eigenschaften, Methoden und Ereignisse mit Ads an.

AMS-Eigenschaften

Diese Seite beschreibt den Kommunikationskanal zwischen dem ADS-OCX und dem ADS-Gerät, welches angesprochen werden soll. Es wird an dieser Stelle auch von ADS-Client und ADS-Server gesprochen. Der ADS-Client ist das Programm, welches beim ADS-Server Informationen oder Dienste anfordert. In unserem Fall ist das Visual Basic-Programm, mit dem ADS-OCX der ADS-Client. In den meisten Beispielen ist der TwinCAT PLC-Server der ADS-Server.

Jedes ADS-Gerät besitzt innerhalb von TwinCAT eine eindeutige Adresse. Diese Adresse setzt sich zusammen aus einer NetId und der Portnummer. Die NetId muss für jedes TwinCAT System innerhalb eines Netzwerks eindeutig sein. Welche NetId ein Rechner besitzt, kann durch das System-Control im Dialog TwinCAT System Eigenschaften auf der Seite AMS Router abgelesen werden. Die NetId besteht aus 6 Ziffern, die durch einen Punkt voneinander getrennt sind. Geben Sie keine NetId an, wenn Sie lokale ADS-Geräte ansprechen wollen. Neben der NetId wird jedes ADS-Gerät zusätzlich durch eine Portnummer adressiert. Jede Portnummern darf auf einem TwinCAT-Rechner nur einmal vorkommen. Weitere Informationen finden Sie auch unter TwinCAT ADS.

Wollen Sie z.B. auf dem lokalen Rechner das Laufzeitsystem 1 der SPS ansprechen, so lassen Sie das Feld NetId vom Server leer und tragen die Portnummer 801 unter Port vom Server ein. Die Felder unter Client können bei Ihnen andere Werte enthalten als oben abgebildet.

Wenn Sie mit dem ADS-OCX mehrere ADS-Geräte ansprechen wollen (z.B. SPS und NC), dann sollten Sie für jedes dieser ADS-Geräte ein ADS-OCX verwenden. Sie sollten nicht während der Laufzeit die Portnummer oder die NetId ändern.

ADS Client-Eigenschaften

Diese Seite zeigt Typ und Version des ADS-Gerätes mit dem ADS-OCX, sowie den aktuellen Status der ADS-Schnittstelle innerhalb des ADS-OCX.

Die Eigenschaftsgruppe Identification zeigt Typ, Version, Revision und Build des ADS-OCX an. Der andere Kommunikationspartner hat die Möglichkeit diese Werte abzufragen, um weitere Informationen über das ADS-Gerät zu bekommen. Diese Felder können von der Applikation frei gesetzt werden.
In der Eigenschaftgruppe Control/State wird der aktuelle Status der ADS-Schnittstelle innerhalb des ADS-OCX angezeigt.

ADS Server-Eigenschaften

Diese Seite zeigt Typ und Version des ADS-Gerätes, welches vom ADS-OCX angesprochen werden soll. Außerdem wird auch vom ADS-Gerät der aktuelle Status angezeigt.

Die Eigenschaftsgruppe Identification zeigt Typ, Version, Revision und Build des ADS-Gerätes an, welches durch das ADS-OCX angesprochen wird. Diese Eigenschaften sind nur lesbar.
In der Eigenschaftsgruppe Control/State wird der aktuelle Status der ADS-Schnittstelle innerhalb des ADS-Gerätes angezeigt.
Die Eigenschaftsgruppe Refresh ist reserviert und wird noch nicht unterstützt.

Bei den oben abgebildeten Dialog wird vom ADS-OCX die SPS angesprochen. Diese befindet sich im RUN-Zustand und hat die Version 2.6.0.

Das ADS-OCX ist jetzt so konfiguriert, dass es die SPS ansprechen kann.


AdsOcx Visual Basic Beispiel: Manuelle Installation des ADS-OCX

TwinCAT ADS-OCX: Installation

Manuelle Installation des ADS OCX

Das ADS OCX kann mit Regsvr32 eingefügt werden. Dazu ist der Pfad der zu registrierenden Datei anzugeben.

Mit Start --> Ausführen --> Regsvr32 <Pfad zur AdsOcx-Datei>\AdsOcs.ocx eingeben.

Ein Reboot des Rechners ist nicht erforderlich.


AdsOcx Visual Basic Beispiel01: Zugriff auf ein Array in der SPS

TwinCAT ADS-OCX: Beispiele

Zugriff auf ein Array in der SPS

Aufgabe

In der SPS befindet sich ein Array, welches von Visual Basic mit einem Lesebefehl ausgelesen werden soll.

Beschreibung

In der SPS befindet sich ein Array mit 100 Elementen vom Typ Integer (2 Byte). Das Array wird in der SPS mit den Werten 3500 bis 3599 aufgefüllt.
In der Load-Ereignisfunktion vom Visual Basic-Programm wird als erstes der Handle der SPS-Variablen geholt. Beim Beenden des Programms wird dieser in der Unload-Ereignisfunktion wieder freigegeben.
Betätigt der Benutzer den Button auf der Form, so wird mit der Methode AdsSyncRead[Datatype]VarReq() das komplette Array aus der SPS in die Visual Basic Variable Data eingelesen.
Die Variable Data muss den gleichen Aufbau haben, wie die entsprechende Variable in der SPS; 100 Elemente vom Typ Integer (2 Byte). Die Längenangabe bei dem Methodenaufruf ist 200, da die Länge der angeforderten Daten 200 Byte (100 Elemente mit je 2 Byte) beträgt.
In der folgenden FOR-Schleife wird das Array aus der SPS in einem Listbox-Control angezeigt.

Visual Basic 6 Programm

Dim hVar As Long
Dim Data(100) As Integer

'--- wird beim Starten aufgerufen ---
Private Sub Form_Load()
  '--- Exception freigeben --- AdsOcx1.EnableErrorHandling = True
  Call AdsOcx1.AdsCreateVarHandle("Main.PLCVar", hVar)
End Sub

'--- wird beim Beenden aufgerufen ---
Private Sub Form_Unload(Cancel As Integer)
  Call AdsOcx1.AdsDeleteVarHandle(hVar)
End Sub

'--- wird vom Bediener aufgerufen ---
Private Sub cmd_read_Click()
  Dim intIndex As Integer
  '--- Array komplett auslesen ---
  Call AdsOcx1.AdsSyncReadIntegerVarReq(hVar, 200, Data(0))
  '--- Array Elemente in Form anzeigen ---
  lstArray.Clear
  For intIndex = 0 To 99
    lstArray.AddItem (CStr(intIndex) & Chr(vbKeyTab) & _ CStr(Data(intIndex)))
  Next
End Sub

SPS-Programm

PROGRAM MAIN
VAR
  PLCVar : ARRAY [0..99] OF INT;
  Index: BYTE;
END_VAR

FOR Index := 0 TO 99 DO
  PLCVar[Index] := 3500 + INDEX;
END_FOR

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample01.exe


AdsOcx Visual Basic Beispiel02: Übertragen von Strukturen an die SPS

TwinCAT ADS-OCX: Beispiele

Übertragen von Strukturen an die SPS

Aufgabe

Von Visual Basic soll eine Struktur in die SPS geschrieben werden. Die Elemente der Struktur haben verschiedene Datentypen.

Beschreibung

Damit die CPU unter Windows NT/2000 schneller auf Variablen zugreifen kann, werden diese von Visual Basic (und auch von anderen Programmiersprachen) im Hauptspeicher nach bestimmten Richtlinien ausgerichtet. Dieses Ausrichten der Variablen wird Alignment (engl. Ausrichten) bezeichnet. Dadurch kann es vorkommen, dass innerhalb einer Struktur 'Speicherlücken' entstehen. Da Visual Basic und IEC1131-3 unterschiedliche Richtlinien für das Alignment besitzen, müssen diese durch Dummyvariablen aufgefüllt werden.
Leider lässt sich unter Visual Basic keine Allgemeinregel für das Alignment definieren. Es besteht aber die Möglichkeit mit zwei Visual Basic Funktionen die Speicherbelegung einer Struktur zu analysieren. Es sind die Funktionen VarPtr() und LenB().
VarPtr() gibt die Adresse einer Variablen zurück, LenB() die Länge in Byte, die eine Variable (oder eine ganze Struktur) belegt. Das untere Beispiel zeigt den Speicheraufbau der Struktur in einer Form an. Anhand dieser Informationen kann ermittelt werden, welche 'Speicherlücken' die Struktur besitzt. In dem Beipielprogramm werden diese durch die Variablen VarDummyX aufgefüllt.
Achtung: Die Funktion VarPtr() steht erst ab Visual Basic 5 zur Verfügung.

In der folgenden Skizze wird die Speicheraufteilung nochmals grafisch dargestellt:

Ein Rechteck bedeutet, dass die Variable an dieser Stelle ein Byte belegt. Ein Kreuz stellt an dieser Stelle ein Byte da, welches von keiner Variablen belegt wird. Die Kreuze wurden in dem Beispielprogramm durch Dummyvariablen aufgefüllt.

Strukturdeklaration in Visual Basic

Type VBStruct
      VarInteger   As Integer
    VarDummy1    As Integer
    VarLong      As Long
    VarByte      As Byte
    VarDummy2    As Byte
    VarDummy3    As Byte
    VarDummy4    As Byte
    VarDouble    As Double
    VarSingle    As Single
End Type

Strukturdeklaration in der SPS

Nachdem die Struktur im Visual Basic-Programm dem Alignment angepasst wurde, muss die Struktur im SPS-Programm ebenfalls ergänzt werden:

TYPE PLCStruct
STRUCT
    PLCVarInteger : INT;
    PLCVarDummy1  : INT;
    PLCVarLong    : DINT;
    PLCVarByte    : SINT;
    PLCVarDummy2  : SINT;
    PLCVarDummy3  : SINT;
    PLCVarDummy4  : SINT;
    PLCVarDouble  : LREAL;
    PLCVarSingle  : REAL;
END_STRUCT
END_TYPE

Visual Basic 6 Programm

Dim hVar As Long
Dim VBVar As VBStruct

'--- wird beim Starten aufgerufen ---
Private Sub Form_Load()
      '--- Exception freigeben --- AdsOcx1.EnableErrorHandling = True
      Call AdsOcx1.AdsCreateVarHandle("Main.PLCVar", hVar)
      '--- Adressen der Variablen anzeigen ---
      lblInteger.Caption = VarPtr(VBVar.VarInteger)
      lblLong.Caption = VarPtr(VBVar.VarLong)
      lblByte.Caption = VarPtr(VBVar.VarByte)
      lblDouble.Caption = VarPtr(VBVar.VarDouble)
      lblSingle.Caption = VarPtr(VBVar.VarSingle)
      '--- Länge der Struktur anzeigen ---
      lblVarLength.Caption = LenB(VBVar)
End Sub

'--- wird beim Beenden aufgerufen ---
Private Sub Form_Unload(Cancel As Integer)
      Call AdsOcx1.AdsDeleteVarHandle(hVar)
End Sub

'--- wird vom Bediener aufgerufen ---
Private Sub cmd_write_Click()
    Dim intIndex As Integer
      '--- Struktur auffüllen ---
      VBVar.VarInteger = CInt(txtInteger.Text)
      VBVar.VarLong = CLng(txtLong.Text)
      VBVar.VarByte = CByte(txtByte.Text)
      VBVar.VarDouble = CDbl(txtDouble.Text)
      VBVar.VarSingle = CSng(txtSingle.Text)
      '--- Struktur in SPS schreiben ---
      Call AdsOcx1.AdsSyncWriteIntegerVarReq(hVar, LenB(VBVar), VBVar.VarInteger)
End Sub

SPS-Programm

PROGRAM MAIN
VAR
      PLCVar : PLCStruct;
END_VAR

Optimierungen

Durch eine geschickte Anordnung der VBStruct-Membervariablen in der VB-Applikation kann das hinzufügen der Dummy-Bytes vermieden werden. Folgende Regel muss dabei beachtet werden:

  • Ordnen Sie die Membervariablen in der VB-Struktur nach der belegten Speichergrösse: Zuerst die grössten und zum Schluss die kleinsten Datentypen.
  • Die letzten Bytes können (müssen aber nicht) auf volle 4 Bytes aufgefüllt werden.

Optimierte Strukturdeklaration in Visual Basic

Type VBStruct
    VarDouble As Double 	' 8 bytes
    VarSingle As Single	'+4 bytes
    VarLong As Long		'+4 byte
    VarInteger As Integer	'+2 bytes
    VarByte As Byte		'+1 byte
                '+1 hidden padding byte in memory
                '=20 bytes (LenB result)
End Type

Optimierte Strukturdeklaration in der SPS

TYPE PLCStruct
STRUCT
    PLCVarDouble : LREAL;
    PLCVarSingle : REAL;
    PLCVarLong : DINT;
    PLCVarInteger : INT;
    PLCVarByte : SINT;
END_STRUCT
END_TYPE

Unsere optimierte VB Struktur beginnt jetzt mit einem Double, entsprechend muss das VB-Programm geändert werden:

'--- wird vom Bediener aufgerufen ---
Private Sub cmd_write_Click()
...
    '--- Struktur in SPS schreiben ---
    call AdsOcx1.AdsSyncWriteDoubleVarReq(hVar, Len(VBVar), VBVar.VarDouble)
End Sub

Neben dem geänderten Methodennamen muss die zu schreibende Datenlänge mit der Len-Funktion und nicht mit LenB ermittelt werden. Wenn Sie LenB benutzen, werden die Daten nicht in die SPS geschrieben. Die Ursache liegt darin, daß LenB eine Länge = 20 Bytes zurückliefert (inklusive eines padding bytes im VB Speicher), unsere Struktur in der SPS aber nur 19 Bytes lang ist.

Len vs. LenB

  • With user-defined types, Len returns the size as it will be written to the file.
  • With user-defined types, LenB returns the in-memory size, including any padding between elements.

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample02.exe


AdsOcx Visual Basic Beispiel03: Ereignisgesteuertes Lesen

TwinCAT ADS-OCX: Beispiele

Ereignisgesteuertes Lesen

Aufgabe

In der SPS befinden sich 7 globale Variablen. Jede SPS-Variable ist von einem anderen Datentyp. Die Werte der Variablen sollen auf möglichst effektive Weise ausgelesen und der Wert mit Zeitstempel auf einer Form in Visual Basic dargestellt werden.

Beschreibung

In dem Load-Ereignis der Form wird mit der Methode AdsReadVarConnectEx() eine Verbindung zu jeder SPS-Variablen hergestellt. Der Handle dieser Verbindung wird in einen globalen Array abgelegt.
Der zweite Parameter der Methode AdsReadVarConnectEx() gibt die Art des Datenaustausches an. Hier wurde ADSTRANS_SERVERONCHA gewählt. Dadurch wird der Wert der SPS-Variable nur dann übertragen, wenn dieser sich in der SPS geändert hat (siehe Datentyp ADSOCXTRANSMODE). Über den dritten Parameter wird angegeben das alle 100ms die SPS überprüft, ob sich die entsprechende Variable geändert hat.

Bei einer Änderung der SPS-Variablen wird das Ereignis AdsReadConnectUpdateEx() aufgerufen. Als Parameter wird der Zeitstempel, der Handle, der Wert und eine Referenz auf das Control, in dem der Wert angezeigt werden soll übergeben.
In dem Unload-Ereignis werden die Verbindungen mit der Methode AdsDisconnectEx() wieder aufgelöst. Dieses sollten Sie umbedingt beachten, da jede Verbindung, die mit AdsReadVarConnectEx() hergestellt wurde, ReSsourcen verbraucht.
Setzen Sie außerdem die CycleTime auf angemessene Werte, da zu viele Schreib / Leseoperationen das System so stark auslasten kann, dass die Bedieneroberfläche stark verlangsamt wird.

Visual Basic 6 Programm

Option Explicit

Dim hConnect(0 to 6) As Long

Private Sub Form_Load()
    Dim nErr As Long

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarBoolean", ADSTRANS_SERVERONCHA, 100, hConnect(0), lblBoolean)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarBoolean: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarInteger", ADSTRANS_SERVERONCHA, 100, hConnect(1), lblInteger)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarInteger: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarLong", ADSTRANS_SERVERONCHA, 100, hConnect(2), lblLong)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarLong: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarDouble", ADSTRANS_SERVERONCHA, 100, hConnect(3), lblDouble)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarDouble: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarSingle", ADSTRANS_SERVERONCHA, 100, hConnect(4), lblSingle)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarSingle: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarString", ADSTRANS_SERVERONCHA, 100, hConnect(5), lblString)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarString: " & nErr)

    nErr = AdsOcx1.AdsReadVarConnectEx(".PLCVarByte", ADSTRANS_SERVERONCHA, 100, hConnect(6), lblByte)
    If (nErr > 0) Then Call MsgBox("Error AdsReadVarConnectEx -> .PLCVarByte: " & nErr)
End Sub

Private Sub AdsOcx1_AdsReadConnectUpdateEx(ByVal dateTime As Date,
                                           ByVal nMs As Long,
                                           ByVal hConnect As Long,
                                           ByVal data As Variant,
                                           Optional ByVal hUser As Variant)
    hUser.Caption = ("Date Time: " & dateTime & "," & nMs & "  Data: " & data)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Dim nIndex As Long
    For nIndex = 0 To 6
        Call AdsOcx1.AdsDisconnectEx(hConnect(nIndex))
    Next
End Sub

SPS-Programm

VAR_GLOBAL
    PLCVarBoolean : BOOL;
    PLCVarInteger	: INT;
    PLCVarLong	: DINT;
    PLCVarDouble	: LREAL;
    PLCVarSingle	: REAL;
    PLCVarString	: STRING(10);
    PLCVarByte	: BYTE;
END_VAR

PROGRAM MAIN
VAR
    ;
END_VAR

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample03.exe


AdsOcx Visual Basic Beispiel04: SPS-Variablendeklaration auslesen

TwinCAT ADS-OCX: Beispiele

SPS-Variablendeklaration auslesen

Aufgabe

Aus der SPS sollen alle Informationen der Variablen ausgelesen werden (Symbol-Upload).

Beschreibung

Durch betätigen des Buttons auf der Form wird die Ereignisfunktion cmdReadSymbols_Click() aufgerufen. Die Methode AdsReadSymbolInfo() liefert die Anzahl der Variablen (Symbole) und die Länge der Daten, in der die Symbole gespeichert sind. Bei dem ersten Aufruf der Methode AdsEnumSymbols() muss der Parameter bNext auf FALSE gesetzt werden. Dadurch werden alle Informationen des ersten Symbols ausgelesen. Bei jedem weiteren Aufruf wird bNext auf TRUE gesetzt. Durch die FOR-Schleife wird AdsEnumSymbols() so oft aufgerufen, wie sich Symbole in der SPS befinden.

Visual Basic 6 Programm

Option Explicit

'--- wird beim Starten des Programms aufgerufen ---
Private Sub Form_Load()
    '--- Exception freigeben ---
    AdsOcx1.EnableErrorHandling = True
    '--- Anzeigeliste- und Felder löschen ---
    lstSymbols.Clear
    lblSymbols.Caption = "Symbols: "
End Sub

'--- wird durch den Bediener aufgerufen ---
Private Sub cmdReadSymbols_Click()
    Dim nSymbolsAvailable As Long
    Dim cbBufSizeNeeded As Long
    Dim strSymbolName As String
    Dim strComment As String
    Dim nSymbolType As Long
    Dim cbSymbolSize As Long
    Dim nIndexOffset As Long
    Dim nIndexGroup As Long
    Dim intIndex As Long

    '--- Anzeigeliste löschen ---
    lstSymbols.Clear

    Call AdsOcx1.AdsReadSymbolInfo(nSymbolsAvailable, cbBufSizeNeeded)
    lblSymbols.Caption = "Symbols: " & nSymbolsAvailable

    '--- erstes Symbol laden und anzeigen ---
    Call AdsOcx1.AdsEnumSymbols(strSymbolName, nSymbolType, cbSymbolSize, _
                                strComment, nIndexGroup, nIndexOffset, False)
    lstSymbols.AddItem ("0" & vbTab & Format(strSymbolName, "!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@") & vbTab & _
                        GetSymbolType(nSymbolType) & vbTab & cbSymbolSize & vbTab & strComment & vbTab & _
                        "0x" & Hex(nIndexGroup) & vbTab & "0x" & Hex(nIndexOffset))

    '--- die restlichen Symbole laden und anzeigen ---
    For intIndex = 1 To nSymbolsAvailable - 1
        Call AdsOcx1.AdsEnumSymbols(strSymbolName, nSymbolType, cbSymbolSize, _
                                    strComment, nIndexGroup, nIndexOffset, True)
        lstSymbols.AddItem (intIndex & vbTab & Format(strSymbolName, "!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@") & vbTab & _
                            GetSymbolType(nSymbolType) & vbTab & cbSymbolSize & vbTab & strComment & vbTab & _
                            "0x" & Hex(nIndexGroup) & vbTab & "0x" & Hex(nIndexOffset))
    Next intIndex
End Sub

Private Function GetSymbolType(VarType As ADSDATATYPEID) As String
    Select Case VarType
        Case ADST_BIT:     GetSymbolType = "BIT"
        Case ADST_INT8:    GetSymbolType = "INT8"
        Case ADST_INT16:   GetSymbolType = "INT16"
        Case ADST_INT32:   GetSymbolType = "INT32"
        Case ADST_INT64:   GetSymbolType = "INT64"
        Case ADST_UINT8:   GetSymbolType = "UINT8"
        Case ADST_UINT16:  GetSymbolType = "UINT16"
        Case ADST_UINT32:  GetSymbolType = "UINT32"
        Case ADST_UINT64:  GetSymbolType = "UINT64"
        Case ADST_REAL32:  GetSymbolType = "REAL32"
        Case ADST_REAL64:  GetSymbolType = "REAL64"
        Case ADST_REAL80:  GetSymbolType = "REAL80"
        Case ADST_BIGTYPE: GetSymbolType = "BIGTYPE"
        Case ADST_VOID:    GetSymbolType = "VOID"
    End Select
End Function

SPS-Programm

PROGRAM MAIN
VAR
    REAL32_1 AT %MB0 : REAL;  (* 1 *)
    REAL32_2 AT %MB4 : REAL;  (* 2 *)
    REAL32_3 AT %MB8 : REAL;  (* 3 *)
    REAL32_4 AT %MB12: REAL;  (* 4 *)
    REAL32_5 AT %MB16: REAL;  (* 5 *)

    REAL64_1 AT %MB20 : LREAL;  (* 6 *)
    REAL64_2 AT %MB28 : LREAL;  (* 7 *)
    REAL64_3 AT %MB36 : LREAL;  (* 8 *)
    REAL64_4 AT %MB44 : LREAL;  (* 9 *)
    REAL64_5 AT %MB52 : LREAL;  (* 10 *)

    INT32_1 AT %MB60 : DINT;  (* 11 *)
    INT32_2 AT %MB64 : DINT;  (* 12 *)
    INT32_3 AT %MB68 : DINT;  (* 13 *)
    INT32_4 AT %MB72 : DINT;  (* 14 *)
    INT32_5 AT %MB76 : DINT;  (* 15 *)

    UINT32_1 AT %MB80 : UDINT;  (* 16 *)
    UINT32_2 AT %MB84 : UDINT;  (* 17 *)
    UINT32_3 AT %MB88 : UDINT;  (* 18 *)
    UINT32_4 AT %MB92 : UDINT;  (* 19 *)
    UINT32_5 AT %MB96 : UDINT;  (* 20 *)

    INT16_1 AT %MB100 : INT;  (* 21 *)
    INT16_2 AT %MB102 : INT;  (* 22 *)
    INT16_3 AT %MB104 : INT;  (* 23 *)
    INT16_4 AT %MB106 : INT;  (* 24 *)
    INT16_5 AT %MB108 : INT;  (* 25 *)

    UINT16_1 AT %MB110 : UINT;  (* 26 *)
    UINT16_2 AT %MB112 : UINT;  (* 27 *)
    UINT16_3 AT %MB114 : UINT;  (* 28 *)
    UINT16_4 AT %MB116 : UINT;  (* 29 *)
    UINT16_5 AT %MB118 : UINT;  (* 30 *)

    INT8_1 AT %MB120 : SINT;  (* 31 *)
    INT8_2 AT %MB121 : SINT;  (* 32 *)
    INT8_3 AT %MB122 : SINT;  (* 33 *)
    INT8_4 AT %MB123 : SINT;  (* 34 *)
    INT8_5 AT %MB124 : SINT;  (* 35 *)

    UINT8_1 AT %MB125 : USINT;  (* 36 *)
    UINT8_2 AT %MB126 : USINT;  (* 37 *)
    UINT8_3 AT %MB128 : USINT;  (* 38 *)
    UINT8_4 AT %MB129 : USINT;  (* 39 *)
    UINT8_5 AT %MB130 : USINT;  (* 40 *)

    BOOL_1 AT %MX131.0 : BOOL;  (* 41 *)
    BOOL_2 AT %MX131.1 : BOOL;  (* 42 *)
    BOOL_3 AT %MX131.2 : BOOL;  (* 43 *)
    BOOL_4 AT %MX131.3 : BOOL;  (* 44 *)
    BOOL_5 AT %MX131.4 : BOOL;  (* 45 *)

    ARRAY_1 : ARRAY[1 .. 10] OF SINT; (* 46 *)
    ARRAY_2 : ARRAY[1 .. 10] OF INT;  (* 47 *)
    ARRAY_3 : ARRAY[1 .. 10] OF DINT; (* 48 *)
    ARRAY_4 : ARRAY[1 .. 10] OF LREAL;(* 49 *)
    ARRAY_5 : ARRAY[1 .. 10] OF BOOL; (* 50 *)
END_VAR

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample04.exe


AdsOcx Visual Basic Beispiel05: Status vom Router und der SPS erkennen/verändern

TwinCAT ADS-OCX: Beispiele

Status vom Router und der SPS erkennen/verändern

Aufgabe

Das ADS-OCX bietet Möglichkeiten, Statusänderungen vom TwinCAT-Router und den ADS-Geräten abzufangen. Dazu stehen die Ereignisse AdsRouterRemove(), AdsRouterShutdown(), AdsRouterStart(), AdsServerStateChanged() und AdsServerSymChanged() zur Verfügung.

Beschreibung

Wird beim Stoppen des TwinCAT-Routers das Ereignis AdsRouterShutdown() aufgerufen, so kann das betreffende Programm entsprechend darauf reagieren. Beim Starten des TwinCAT-Router wird das Ereignis AdsRouterStart() aufgerufen, in dem dann z.B. mit der Methode AdsReadVarConnectEx() die Verbindungen zu den ADS-Variablen wieder hergestellt werden kann. Wird in der Systemsteuerung von Windows NT/2000/XP der TwinCAT-Router komplett aus dem Betriebssystem entfernt, so wird das Ereignis AdsRouterRemove() aufgerufen.
Neben Statusänderungen des TwinCAT-Routers können auch Zustandsänderungen in ADS-Geräten abgefangen werden. Besondere Bedeutung hat dieses bei der SPS. Durch das Ereignis AdsServerStateChanged() kann festgestellt werden, ob die SPS gestartet oder gestoppt wurde. Mit dem Ereignis AdsServerSymChanged() werden Änderungen an der Symboltabelle mitgeteilt. Dieses geschieht z.B. wenn das SPS-Programm komplett neu übersetzt wird und anschließend in die SPS übertragen wird.

So wie der Status eines ADS-Gerätes abgefragt werden kann, so kann dieser auch geändert werden. Die Methode AdsSyncWriteControlReq() bietet diese Möglichkeit. Die SPS kann die ADS-Zustände STOP und RUN annehmen. Durch ein Check-Button in dem unteren Beispiel-Programm, kann der Bediener zwischen diesen beiden Zuständen umschalten.

Bei jeder Statusänderung des TwinCAT-Routers erfolgt ein entsprechender Eintrag in die Listbox.

Achtung: Wird eine Änderung der Symboltabelle erkannt, so kann es sein das eine Variable, die mit AdsReadVarConnectEx() angesprochen wird, gelöscht oder umbenannt wurde. Beim Auftreten des Ereignisses AdsServerSymChanged() sollten alle Connectes und Handles gelöscht und anschließend neu angelegt werden.

Visual Basic 6 Programm

Option Explicit

'--- wird beim Starten aufgerufen ---
Private Sub Form_Load()
    Call lstEvent.Clear
    AdsOcx1.EnableErrorHandling = True
End Sub

'--- wird aufgerufen, wenn sich der Status des ADS-Gerätes ändert ---
Private Sub AdsOcx1_AdsServerStateChanged(ByVal nAdsState As ADSOCXLib.ADSSTATE, ByVal nDeviceState As Long)
    Select Case nAdsState
        Case ADSSTATE_INVALID:      lstEvent.AddItem ("PLC invalid")
        Case ADSSTATE_IDLE:         lstEvent.AddItem ("PLC idle")
        Case ADSSTATE_RESET:        lstEvent.AddItem ("PLC reset")
        Case ADSSTATE_INIT:         lstEvent.AddItem ("PLC init")
        Case ADSSTATE_START:        lstEvent.AddItem ("PLC start")
        Case ADSSTATE_RUN:          lstEvent.AddItem ("PLC run")
                                    chkRunStop.Value = 1
        Case ADSSTATE_STOP:         lstEvent.AddItem ("PLC stop")
                                    chkRunStop.Value = 0
        Case ADSSTATE_SAVECFG:      lstEvent.AddItem ("PLC savecfg")
        Case ADSSTATE_LOADCFG:      lstEvent.AddItem ("PLC loadcfg")
        Case ADSSTATE_POWERFAILURE: lstEvent.AddItem ("PLC powerfailure")
        Case ADSSTATE_POWERGOOD:    lstEvent.AddItem ("PLC powergood")
        Case ADSSTATE_ERROR:        lstEvent.AddItem ("PLC error")
    End Select
End Sub

'--- wird bei Änderung der Symboltabelle aufgerufen ---
Private Sub AdsOcx1_AdsServerSymChanged()
    lstEvent.AddItem ("PLC symbol changed")
End Sub

'--- wird beim Entfernen des TwinCAT-Routers aufgerufen ---
Private Sub AdsOcx1_AdsRouterRemove()
    lstEvent.AddItem ("TwinCAT-Router remove")
End Sub

'--- wird beim Stoppen des TwinCAT-Routers aufgerufen ---
Private Sub AdsOcx1_AdsRouterShutdown()
    lstEvent.AddItem ("TwinCAT-Router shutdown")
End Sub

'--- wird beim Starten des TwinCAT-Routers aufgerufen ---
Private Sub AdsOcx1_AdsRouterStart()
    lstEvent.AddItem ("TwinCAT-Router start")
End Sub

'--- wird vom Bediener aufgerufen ---
Private Sub chkRunStop_Click()
    Dim nState As ADSOCXLib.ADSSTATE
    Dim nRet As Integer
    nState = IIf(chkRunStop.Value = 0, ADSSTATE_STOP, ADSSTATE_RUN)
    Call AdsOcx1.AdsSyncWriteControlReq(nState, 0&, 0&, nRet)
End Sub

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample05.exe


AdsOcx Visual Basic Beispiel06: Meldungen über den Router senden/empfangen

TwinCAT ADS-OCX: Beispiele

Meldungen über den Router senden/empfangen

Aufgabe

ADS-Geräte können über den TwinCAT-Router Meldungen zu anderen ADS-Geräten schicken. Diese können dort empfangen und ausgewertet werden. Ebenso ist es möglich, Meldungen in den Windows NT/2000/XP Event Logger zu schreiben.
Das folgende Visual Basic-Programm empfängt Meldungen von der SPS und zeigt diese auf dem Bildschirm an. Ebenso kann von dem Visual Basic-Programm aus, Meldungen in den Windows NT/2000/XP Event Logger geschrieben werden.

Beschreibung

Um Meldungen Empfangen zu können, muss als erstes mit der Methode AdsEnableLogNotification() ein Filter definiert werden. Hierbei wird der Bereich der Portnummern angegeben, von dessen ADS-Geräten Meldungen empfangen werden sollen. Als zweiten Parameter wird noch die Meldeart angegeben (Fehler, Hinweis oder Warnung). Mit dem OR-Operator können auch mehrere Meldearten kombiniert werden.
Jedesmal wenn eine Meldung von einem ADS-Gerät abgeschickt wurde und die Filterbedingungen erfüllt sind, wird das Ereignis AdsLogNotification() aufgerufen. Über die Parameter kann die Quelle, die Art, der Zeitpunkt und die Meldung an sich ermittelt werden.
Soll eine Meldung mit Hilfe des ADS-OCX abgeschickt werden, so wird hierzu die Methode AdsLogFmtString() benutzt. Der erste Parameter enthält den Meldetyp (Fehler, Hinweis oder Warnung). Der Meldetext kann bis zu vier Platzhalter für numerische Werte enthalten. Dadurch können z.B. Werte übertragen werden, die erst zur Laufzeit des Programms bekannt sind. Alle Meldungen, die mit dem ADS-OCX abgeschickt werden, werden automatisch in den Event Logger von Windows NT/2000/XP geschrieben.

Von dem Visual Basic-Programm kann der Event Viewer von Windows NT/2000/XP aufgerufen werden. Hiermit lassen sich alle Meldungen betrachten, die im Event Logger enthalten sind. Event Logger und Event Viewer werden mit Windows NT/2000/XP standardmäßig ausgeliefert. Nährere Informationen entnehmen Sie bitte der Windows NT/2000/XP Dokumentation.

Das SPS-Programm setzt zyklisch alle 5 Sekunden ein Hinweis ab. Dieser Hinweis wird zusätzlich noch in den Windows NT/2000/XP Event Logger geschrieben. Die SPS-Funktion ADSLOGDINT() ist in der Dokumentation zur SPS beschrieben.

Hinweis: Alle Meldungen, die über den TwinCAT-Router abgeschickt werden, können im System Manager online beobachtet werden. Hierzu muss im Menü Ansicht die Logger Ausgabe aktiv sein.

Windows NT/2000/XP beinhaltet API-Funktionen mit denen die gespeicherten Meldungen aus dem Event Logger wieder ausgelesen werden können. Visual Basic hat leider (noch) keine Komponenten, um auf die gespeicherten Meldungen im Event Logger zugreifen zu können. In der Zeitschrift basicopro 6/98 Seite 56ff aus dem Steingräberverlag (http://www.basicpro.de) ist ein Artikel veröffentlicht worden, der die Anwendung der API-Funktionen unter Visual Basic demonstriert.

Anwendung

Bei der Entwicklung und Fehlersuche von Applikationen hat sich diese Möglichkeit als sehr hilfreich erwiesen. So kann z.B. ein SPS-Programm oder ein Visual Basic-Programm bestimmte interne Programmzustände anzeigen (im System Manager) und speichern (Windows NT/2000 Event Logger). Für diese Art der Programmverfolgung ist es nicht notwendig die Entwicklungsumgebung (z.B. auf einem Maschinenrechner) zu installieren.

Achten Sie darau,f dass nicht zu viele Meldungen in kurzer Zeit übertragen werden, da dieses das Gesamtsystem sonst beeinträchtigen könnte.

Tip: Wollen Sie in Ihrem Programm Meldungen protokollieren (z.B. Störungen einer Maschine), so sollten Sie dafür den TwinCAT-Event Logger benutzen. Dieser ist deutlich leistungsfähiger als der Event Logger von Windows NT/2000/XP und auf die Anforderungen der Automatisierungstechnik abgestimmt.

Visual Basic 6 Programm

Option Explicit

'--- wird beim Starten des Programms aufgerufen ---
Private Sub Form_Load()
    cboMessageType.ListIndex = 0
    AdsOcx1.EnableErrorHandling = True
    '--- Meldungen abfangen ---
    Call AdsOcx1.AdsEnableLogNotification(1, 65535, ADSLOG_MSGTYPE_HINT Or ADSLOG_MSGTYPE_ERROR Or ADSLOG_MSGTYPE_WARN)
End Sub

'--- wird beim eintreffen einer Nachricht vom AdsOCX aufgreufen ---
Private Sub AdsOcx1_AdsLogNotification(ByVal dateTime As Date, ByVal nMs As Long, _
                                       ByVal dwMsgCtrl As Long, ByVal nServerPort As Long, _
                                       ByVal szDeviceName As String, ByVal szLogMsg As String)
    '--- Meldung anzeigen ---
    lstMessages.AddItem Format(DateValue(dateTime), "!@@@@@@@@@@") & _
                        Format(TimeValue(dateTime), "!@@@@@@@@@@@@@@@") & _
                        Format(nMs, "000   ") & _
                        Format(szDeviceName, "!@@@@@@@@@@") & _
                        Format(nServerPort, "00000     ") & _
                        szLogMsg
End Sub

'--- Meldung absetzen ---
Private Sub cmdSend_Click()
    Dim Para1 As Long
    Dim Para2 As Double
    Dim Para3 As Integer
    Dim Para4 As Integer
    '--- Parameter setzen ---
    Para1 = CLng(txt1Para.Text)
    Para2 = CDbl(txt2Para.Text)
    Para3 = CInt(txt3Para.Text)
    Para4 = CInt(txt4Para.Text)
    '--- Meldung absetzen ---
    Call AdsOcx1.AdsLogFmtString(cboMessageType.ItemData(cboMessageType.ListIndex), _
                                 txtMessage.Text, Para1, Para2, Para3, Para4)
End Sub

'--- Ereignisanzeige von Windows NT/2000 anzeigen ---
Private Sub cmdEventViewer_Click()
    Call Shell("eventvwr.exe", vbNormalFocus)
End Sub

'--- List löschen ---
Private Sub cmdClearList_Click()
    Call lstMessages.Clear
End Sub

SPS Programm

PROGRAM MAIN
VAR
    PLCVarInteger AT %MW0  : INT;
    TP_1  : TP;
    TOGGEL  : BOOL;
    AdsLogResult  : DINT;
END_VAR

TOGGEL := NOT TOGGEL;
TP_1( IN := TOGGEL, PT := t#5s);
IF (TP_1.Q = 0) THEN
    IF (TOGGEL = 0) THEN
        PLCVarInteger := PLCVarInteger + 1;
        AdsLogResult := ADSLOGDINT(ADSLOG_MSGTYPE_HINT OR ADSLOG_MSGTYPE_LOG , 'Message from the PLC: %d', PLCVarInteger);
    END_IF
END_IF

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample06.exe


AdsOcx Visual Basic Beispiel07: Handle einer SPS Variable löschen

TwinCAT ADS .NET Komponente: Beispiele

Handle einer SPS Variablen löschen

In diesem Beispiel wird gezeigt, wie das Handle einer SPS-Variablen gelöscht werden kann:

Visual Basic 6 Programm

Dim handle As Long

'--- Is called at the start ---
Private Sub Form_Load()
    txtHandle.Text = handle
End Sub

' --- Is called when "Get Handle" is pressed ---
Private Sub btnGetHandle_Click()
    Call AdsOcx1.AdsCreateVarHandle("MAIN.PLCVar", handle)
    txtHandle.Text = handle
End Sub

' --- Is called when "Release Handle" is pressed ---
Private Sub btnReleaseHandle_Click()
    Call AdsOcx1.AdsDeleteVarHandle(handle)
    handle = 0
    txtHandle.Text = handle
End Sub

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample07.exe


AdsOcx Visual Basic Beispiel09: Ereignisgesteuertes Lesen (mit Konvertierung in einen anderen Typ)

TwinCAT ADS-OCX: Beispiele

Ereignisgesteuertes Lesen (mit Konvertierung in einen anderen Typ)

Ab TwinCAT 2.8 Build > 743 und höher

Aufgabe

In der SPS befinden sich 4 Variablen vom unterschiedlichen Typ. Die Variablen sollen auf möglichst effektive Weise ausgelesen und die Werte auf einer Visual Basic Form dargestellt werden. Mit einer Checkbox kann zwischen zwei Verbindungsmodi (ADSTRANS_SERVERCYCLE oder ADSTRANS_SERVERONCHA) umgeschaltet werden. Mit zwei Buttons kann die Verbindung zu den SPS-Variablen aufgebaut oder abgebaut werden.

Bei den SPS-Variablen handelt es sich um strukturierte Datentypen. Diese werden z.B. von der SPS als ein Datenblock an den AdsOcx-Client gesendet. Das AdsOcx kann aber an die VB-Ereignisroutine nur Variablen vom bestimmten Datentyp als Parameter übergeben, darunter den Variant-Typ. Mit der Methode AdsReadVarConvertConnect kann der Typ der Variant-Variablen in der VB-Ereignisroutine vom Benutzer vorher festgelegt werden. Die Ereignisdaten werden dann vom AdsOcx in die Variant-Variable kopiert und so an die VB-Ereignisroutine übergeben. Ein Variant-Array kann auch eine komplexe Struktur in der SPS abbilden. Wieviele Daten in die einzelnen Variant-Elemente kopiert werden, wird durch den Typ der einzelnen Elemente festgelegt. Einige Ausnahmen z.B. bei Strings (die Stringlänge muss vorher entsprechend gesetzt werden) und boolschen Variablen (aus 1 Byte Daten wird ein 2 Byte VB-Boolean ) sind dabei zu beachten.

Folgende SPS-Variablen sollen auf der Form angezeigt werden:

  • Der Wert eines Aufzählungstyps (Enum) soll in eine Long-Variable eingelesen und im Label angezeigt werden.
  • Der Wert eines Strukturierten-Datentyps (Struktur mit 4-Booleans) soll in eine Long-Variable eingelesen und in einer CheckBox dargestellt werden. Die CheckBox soll ausgewählt werden, wenn eine der boolschen Variablen in der SPS den Wert TRUE besitzt.
  • Der Wert eines Stringarrays soll in einer ListBox angezeigt werden.
  • Der Wert eines Strukturierten-Datentyps soll in ein Variantarray eingelesen und in einer weiteren ListBox angezeigt werden.

Die SPS Applikation

VAR_GLOBAL
    eColors 		: E_Colors := cWhite;
    st4Switches 	: ST_4Switches;
    arr3Strings 	: ARRAY[1..3] OF STRING :=1('First'), 1('Second'),1('Third');
    stBigStruct 	: ST_BigStruct;
END_VAR

Online-Ansicht der SPS-Daten:

die Definition des Aufzählungstyps:

TYPE E_Colors :
(
    cUnknown,
    cWhite := 1,
    cBlue := 2,
    cRed := 3,
    cBlack
);
END_TYPE

Die Definition der Struktur mit 4 boolschen Variablen:

TYPE ST_4Switches :
STRUCT
    bLevel1 : BOOL;
    bLevel2 : BOOL;
    bLevel3 : BOOL;
    bLevel4 : BOOL;
END_STRUCT
END_TYPE

Die Definition des Strukturierten-Datentyps:

TYPE ST_BigStruct :
STRUCT
    single : REAL;
    long : DINT;
    boolean : BOOL;
    stSub1 : ST_Sub1;
    counter : DINT;
    datetime : DT := DT#2003-01-20-15:12:44;
END_STRUCT
END_TYPE

Dieser besitzt wiederum 2 Unterstrukturen:

TYPE ST_Sub1 :
STRUCT
    bFirst : BOOL;
    bSecond : BOOL;
    bThird : BOOL;
    stSub2 : ST_Sub2;
END_STRUCT
END_TYPE
TYPE ST_Sub2 :
STRUCT
    integer : INT;
    double : LREAL;
    string20 : STRING(20) := 'Unknown';
END_STRUCT
END_TYPE

Visual Basic 6 Programm

Option Explicit
Dim adsErr As Long
Dim hConnect_EnumVar As Long
Dim hConnect_4Switches As Long
Dim hConnect_StringArray As Long
Dim hConnect_BigStruct As Long

Beim Laden der Form wird eine Verbindung zum ersten SPS-Laufzeitsystem aufgebaut:

Private Sub Form_Load()
    AdsOcx1.AdsAmsServerNetId = AdsOcx1.AdsAmsClientNetId
    AdsOcx1.AdsAmsServerPort = 801
    AdsOcx1.EnableErrorHandling = True
End Sub

Bei einem Mausklick auf den AdsReadVarConvertConnect - Button wird eine Verbindung zu den SPS-Variablen aufgebaut. Beim Erfolg liefert die Methode AdsReadVarConvertConnect ein Handle zurück. Nur über dieses Handle wird die Verbindung identifiziert und kann später abgebaut werden.

1. Der Aufzählungstyp in der SPS belegt nur 2 Byte Speicher. Diese 2 Byte werden in eine Long-Variable (4 Byte) eingelesen und in der Ereignisfunktion zurückgeliefert. Man könnte aber genauso gut den VB Integer-Datentyp verwenden.

2. Die 4 boolschen Werte der Strukturvariablen belegen in der SPS 4 einzelne Bytes SPS-Speicher. Diese werden in eine Long-Variable eingelesen und in der Ereignisfunktion als eine Long-Variable zurückgeliefert.

3. Die Strings in dem Array belegen in der SPS insgesamt 243 Byte Speicher (Definierte Stringlänge + 1 Byte für die Nullterminierung)*3. Die Länge der einzelnen VB-Strings muss der Länge der SPS-Strings entsprechen um die einzelnen Strings trennen zu können. Besitzt der String die Länge Null, werden keine Ereignisdaten in eine Stringvariable hineinkopiert.

4. Die Strukturvariable kann in ein eindimensionales Variant-Array eingelesen werden. Die einzelnen Arrayelemente können vom unterschiedlichen Typ sein. Vor dem Aufbau der Verbindung müssen aber die einzelnen Arrayelemente mit entsprechendem Typ initialisiert werden.

Private Sub cmdConnect_Click()
    Dim adsTransMode As ADSOCXTRANSMODE
    adsTransMode = IIf(chkTransMode.Value = vbChecked, ADSTRANS_SERVERCYCLE, ADSTRANS_SERVERONCHA)

    'Connects to enum var
    Dim convertedEnumVar As Long
    adsErr = AdsOcx1.AdsReadVarConvertConnect(".eColors", adsTransMode, 300, hConnect_EnumVar, convertedEnumVar, lblEnum)

    'Connects to struct with 4 boolean variables
    Dim converted4Switches As Long
    adsErr = AdsOcx1.AdsReadVarConvertConnect(".st4Switches", adsTransMode, 300, hConnect_4Switches, converted4Switches, chk4Switches)

    'Connects to array of strings
    Dim convertedStringArray(1 To 3) As String
    Dim i As Integer
    For i = LBound(convertedStringArray) To UBound(convertedStringArray)
        convertedStringArray(i) = String(81, "#")
    Next i
    adsErr = AdsOcx1.AdsReadVarConvertConnect(".arr3Strings", adsTransMode, 300, hConnect_StringArray, convertedStringArray, lstStringArray)

    'Connects to struct variable
    Dim convertedBigStruct(1 To 11) As Variant
    convertedBigStruct(1) = CSng(0) 		'stBigStruct.single
    convertedBigStruct(2) = CLng(0)		'stBigStruct.long
    convertedBigStruct(3) = CBool(False)	'stBigStruct.boolean
    convertedBigStruct(4) = CBool(False)	'stBigStruct.stSub1.bFirst
    convertedBigStruct(5) = CBool(False)	'stBigStruct.stSub1.bSecond
    convertedBigStruct(6) = CBool(False)	'stBigStruct.stSub1.bThird
    convertedBigStruct(7) = CInt(0)		'stBigStruct.stSub1.stSub2.integer
    convertedBigStruct(8) = CDbl(0)		'stBigStruct.stSub1.stSub2.double
    convertedBigStruct(9) = CStr(String(21, "*"))'stBigStruct.stSub1.stSub2.string20
    convertedBigStruct(10) = CLng(0)		'stBigStruct.counter
    convertedBigStruct(11) = CDate(0)		'stBigStruct.datetime
    adsErr = AdsOcx1.AdsReadVarConvertConnect(".stBigStruct", adsTransMode, 300, hConnect_BigStruct, convertedBigStruct, lstBigStruct)

    cmdConnect.Enabled = False
    cmdDisconnect.Enabled = True
End Sub

Bei einem Mausklick auf AdsDisconnectEx - Button werden die Verbindungen zu den SPS-Variablen getrennt:

Private Sub cmdDisconnect_Click()
    adsErr = AdsOcx1.AdsDisconnectEx(hConnect_EnumVar)
    adsErr = AdsOcx1.AdsDisconnectEx(hConnect_4Switches)
    adsErr = AdsOcx1.AdsDisconnectEx(hConnect_StringArray)
    adsErr = AdsOcx1.AdsDisconnectEx(hConnect_BigStruct)

    cmdConnect.Enabled = True
    cmdDisconnect.Enabled = False
End Sub

Die Ereignisroutine AdsReadConvertConnectUpdate. Diese Ereignisroutine wird zyklisch (wenn ADSTRANS_SERVERCYCLE ausgewählt) oder immer nur dann aufgerufen, wenn sich der Wert der SPS-Variablen geändert hat (bei ADSTRANS_SERVERONCHA). Der hUser Parameter kann dafür benutzt werden, um die Ereignisdaten dem passenden Control (Label, CheckBox, ListBox ) zuordnen zu können.

Private Sub AdsOcx1_AdsReadConvertConnectUpdate(ByVal dateTime As Date, ByVal nMs As Long, ByVal hConnect As Long, data As Variant, Optional hUser As Variant)
    Dim i As Integer
    If TypeOf hUser Is CheckBox Then

        chk4Switches.Value = IIf(data = 0, vbUnchecked, vbChecked)
        chk4Switches.Caption = IIf(data = 0, "ALL disbled", "At least ONE enabled")

    ElseIf TypeOf hUser Is ListBox Then

        If hUser Is lstStringArray Then
            Call lstStringArray.Clear
            For i = LBound(data) To UBound(data)
                Call lstStringArray.AddItem("Type: " & TypeName(data(i)) & " Value: " & data(i))
            Next i
        ElseIf hUser Is lstBigStruct Then
            Call lstBigStruct.Clear
            For i = LBound(data) To UBound(data)
                Call lstBigStruct.AddItem("Type: " & TypeName(data(i)) & " Value: " & data(i))
            Next i
        End If

    Else 'lblEnum
        Dim objLabel As Label
        Set objLabel = hUser
        objLabel.Caption = "eColors: " & data
    End If
End Sub

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-OCX Sample09.exe


TcAdsDll Visual Basic Beispiel01: Lesen und Schreiben von Variablen mit Visual Basic

TwinCAT TcADSDll: Beispiele

Lesen und Schreiben von Variablen mit Visual Basic

Dieses Beispiel-Programm demonstriert wie die Com-Schnittstellen der TcAdsDll von Visual Basic angesprochen werden können, um Variablen aus der SPS zu lesen bzw. in die SPS zu schreiben.

In der Load-Ereignisfunktion vom Visual Basic-Programm wird mit CreateObject das TcClient-Objekt erzeugt. Mit Hilfe der Methode Connect wird dann eine Verbindung zur SPS hergestellt. Dabei wird als NetID ein "0.0.0.0.0.0" übergeben, womit eine Verbindung zum lokalen Rechner hergestellt wird.

Durch betätigen des Read-Buttons werden die Variablen aus der SPS gelesen. Dazu wird die Method Read des TcAdsSync-Objektes aufgerufen. Dieser Methode wird ein Byte-Array mit der Länge der zu lesenden Variablen übergeben. Danach muss dieses Array in den entsprechenden VB-Datentypen umkopiert werden. Wenn das Datenlayout identisch ist kann hierzu die Api-Routine RtlMoveMemory benutzt werden. Beim Schreiben in die SPS wird das Byte-Array zuerst mit den erforderlichen Daten gefüllt und dann erst die Methode Write aufgerufen.

Visual Basic 6 Programm

Option Explicit
Dim WithEvents ads As TcAdsDll.TcAdsSync

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(lpDest As Any, lpSrc As Any, ByVal Length As Long)

Private Sub Form_Load()
  On Error GoTo errFunc
  Dim client As TcAdsDll.TcClient
  Dim netId As AmsNetId

  Set client = CreateObject("TcAdsDll.TcClient")
  netId.b(0) = 0
  netId.b(1) = 0
  netId.b(2) = 0
  netId.b(3) = 0
  netId.b(4) = 0
  netId.b(5) = 0
  Set ads = client.Connect(netId, 801)

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub cmdRead_Click()
  On Error Resume Next
  TextBoolean.Text = ReadBoolean(&H4020&, 0)
  TextInteger.Text = ReadInteger(&H4020&, 2)
  TextLong.Text = ReadLong(&H4020&, 4)
  TextSingle.Text = ReadSingle(&H4020&, 8)
  TextDouble.Text = ReadDouble(&H4020&, 12)
End Sub

Private Sub cmdWrite_Click()
On Error Resume Next
  Call WriteBoolean(&H4020&, 0, TextBoolean.Text)
  Call WriteInteger(&H4020&, 2, TextInteger.Text)
  Call WriteLong(&H4020&, 4, TextLong.Text)
  Call WriteSingle(&H4020&, 8, TextSingle.Text)
  Call WriteDouble(&H4020&, 12, TextDouble.Text)
End Sub

Private Sub WriteBoolean(indexGroup As Long, indexOffset As Long, val As Boolean)
  On Error GoTo errFunc
  Dim arrRead(0 To 0) As Byte
  Dim cbLen As Long

  cbLen = 1
  If (val = True) Then
    arrRead(0) = 1
  Else
    arrRead(0) = 0
  End If

  Call ads.Write(indexGroup, indexOffset, cbLen, arrRead(0))

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub WriteInteger(indexGroup As Long, indexOffset As Long, val As Integer)
  On Error GoTo errFunc
  Dim arrRead(0 To 1) As Byte
  Dim cbLen As Long

  cbLen = 2
  Call CopyMemory(arrRead(0), val, cbLen)
  Call ads.Write(indexGroup, indexOffset, cbLen, arrRead(0))

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub WriteLong(indexGroup As Long, indexOffset As Long, val As Long)
  On Error GoTo errFunc
  Dim arrRead(0 To 3) As Byte
  Dim cbLen As Long

  cbLen = 4
  Call CopyMemory(arrRead(0), val, cbLen)
  Call ads.Write(indexGroup, indexOffset, cbLen, arrRead(0))

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub WriteSingle(indexGroup As Long, indexOffset As Long, val As Single)
  On Error GoTo errFunc
  Dim arrRead(0 To 3) As Byte
  Dim cbLen As Long

  cbLen = 4
  Call CopyMemory(arrRead(0), val, cbLen)
  Call ads.Write(indexGroup, indexOffset, cbLen, arrRead(0))

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub WriteDouble(indexGroup As Long, indexOffset As Long, val As Double)
  On Error GoTo errFunc
  Dim arrRead(0 To 7) As Byte
  Dim cbLen As Long

  cbLen = 8
  Call CopyMemory(arrRead(0), val, cbLen)
  Call ads.Write(indexGroup, indexOffset, cbLen, arrRead(0))

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Function ReadBoolean(indexGroup As Long, indexOffset As Long) As Boolean
  On Error GoTo errFunc
  Dim arrRead(0 To 0) As Byte
  Dim cbRead As Long
  Dim cbLen As Long
  Dim val As Boolean

  cbLen = 1
  Call ads.Read(indexGroup, indexOffset, cbLen, cbRead, arrRead(0))

  If (arrRead(0) = 0) Then
    val = False
  Else
    val = True
  End If
  ReadBoolean = val

  Exit Function
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Function

Private Function ReadInteger(indexGroup As Long, indexOffset As Long) As Integer
  On Error GoTo errFunc
  Dim arrRead(0 To 1) As Byte
  Dim cbRead As Long
  Dim cbLen As Long
  Dim val As Integer

  cbLen = 2
  Call ads.Read(indexGroup, indexOffset, cbLen, cbRead, arrRead(0))
  Call CopyMemory(val, arrRead(0), cbLen)
  ReadInteger = val

  Exit Function
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Function

Private Function ReadLong(indexGroup As Long, indexOffset As Long) As Long
On Error GoTo errFunc
  Dim arrRead(0 To 3) As Byte
  Dim cbRead As Long
  Dim cbLen As Long
  Dim val As Long

  cbLen = 4
  Call ads.Read(indexGroup, indexOffset, cbLen, cbRead, arrRead(0))
  Call CopyMemory(val, arrRead(0), cbLen)
  ReadLong = val

  Exit Function
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Function

Private Function ReadSingle(indexGroup As Long, indexOffset As Long) As Single
On Error GoTo errFunc
  Dim arrRead(0 To 3) As Byte
  Dim cbRead As Long
  Dim cbLen As Long
  Dim val As Single

  cbLen = 4
  Call ads.Read(indexGroup, indexOffset, cbLen, cbRead, arrRead(0))
  Call CopyMemory(val, arrRead(0), cbLen)
  ReadSingle = val

  Exit Function
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Function

Private Function ReadDouble(indexGroup As Long, indexOffset As Long) As Double
  On Error GoTo errFunc
  Dim arrRead(0 To 7) As Byte
  Dim cbRead As Long
  Dim cbLen As Long
  Dim val As Double

  cbLen = 8
  Call ads.Read(indexGroup, indexOffset, cbLen, cbRead, arrRead(0))
  Call CopyMemory(val, arrRead(0), cbLen)
  ReadDouble = val

  Exit Function
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Function

SPS-Programm

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

;

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | TcAdsDll_ComSample01.exe


TcAdsDll Visual Basic Beispiel02: Ereignisgesteuertes Lesen mit Visual Basic

TcAdsDll: Beispiele

Ereignisgesteuertes Lesen mit Visual Basic

In dem Load-Ereignis der Form wird mit der Methode AddDeviceNotification eine Verbindung zu den SPS-Variablen hergestellt. Bei einer Änderung der SPS-Variablen wird das Ereignis DeviceNotification des TcAdsSync-Objektes aufgerufen. In dem Unload-Ereignis oder durch Betätigen des Stop-Buttons werden die Verbindungen mit der Methode DelDeviceNotification wieder aufgehoben.

Visual Basic 6 Programm

Option Explicit
Dim WithEvents ads As TcAdsDll.TcAdsSync
Attribute ads.VB_VarHelpID = -1
Dim hValInteger As Long
Dim hValDouble As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
 (lpDest As Any, lpSrc As Any, ByVal Length As Long)

Private Sub Form_Load()
On Error GoTo errFunc
  Dim client As TcAdsDll.TcClient
  Dim netId As AmsNetId

  Set client = CreateObject("TcAdsDll.TcClient")
  netId.b(0) = 0
  netId.b(1) = 0
  netId.b(2) = 0
  netId.b(3) = 0
  netId.b(4) = 0
  netId.b(5) = 0
  Set ads = client.Connect(netId, 801)

  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub cmdStart_Click()
  Dim delay As Long
  Dim cycle As Long

  delay = 0
  cycle = 1000000 '100ms

  If hValInteger = 0 Then
    hValInteger = ads.AddDeviceNotification(&H4020&, 2, 2, ADSTRANS_SERVERONCHA, delay, cycle)
  End If
  If hValDouble = 0 Then
    hValDouble = ads.AddDeviceNotification(&H4020&, 12, 8, ADSTRANS_SERVERONCHA, delay, cycle)
  End If
  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

Private Sub cmdStop_Click()
  Call DeleteNotifications
End Sub

Private Sub Form_Unload(Cancel As Integer)
  Call DeleteNotifications
End Sub

Private Sub ads_DeviceNotification(pTime As TcAdsDll.TimeStamp, ByVal hNotification As Long, ByVal cbLen As Long, pData As Byte)
  Dim integerVal As Integer
  Dim doubleVal As Double

  If (hNotification = hValInteger And cbLen = 2) Then
    Call CopyMemory(integerVal, pData, cbLen)
    TextInteger.Text = integerVal
  ElseIf (hNotification = hValDouble And cbLen = 8) Then
    Call CopyMemory(doubleVal, pData, cbLen)
    TextDouble.Text = doubleVal
  End If
End Sub

Private Sub DeleteNotifications()
On Error GoTo errFunc
  If hValInteger <> 0 Then
    Call ads.DelDeviceNotification(hValInteger)
    hValInteger = 0
  End If
  If hValDouble <> 0 Then
    Call ads.DelDeviceNotification(hValDouble)
    hValDouble = 0
  End If
  Exit Sub
  errFunc:
    MsgBox "Error: (0x" & Format(Hex(Err.Number), "00000000") & "), " & Err.Description
End Sub

SPS-Programm

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

;

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | TcAdsDll_ComSample02.exe


TwinCAT.Ads in Visual Studio .NET (VB)

TwinCAT ADS .NET Komponente

Einbinden in Microsoft Visual Studio .NET (VB)

Neues Projekt erstellen

Die TwinCAT.Ads-Komponente kann nur in ein existierendes Projekt eingebunden werden. Starten Sie Visual StudioS und wählen Sie aus dem Menü das Kommando: File->New->Project...

Im New Project-Dialog wählen Sie bitte als Projekttyp: Visual Basic->Windows Forms Application.

Referenz hinzufügen

Um die Klassenbibliothek TwinCAT.Ads zu selektieren müssen Sie das Kommando Add Reference... des Project -Menus auswählen. Dies öffnet den Add Reference Dialog.
Alternativ können Sie auch mit einem Doppelklick auf My Project (1) die Projekt-Eigenschaften öffnen und dort unter References (2) den den Add...-Button (3) betätigen.

In diesem Dialog müssen Sie den Browse-Reiter auswählen und dort zu der Datei TwinCAT.Ads.dll navigieren. Bestätigen Sie dann die ausgewählte dll mit OK. Standardmäßig befindet sich die TwinCAT.Ads-Komponente im ..TwinCAT\Ads Api\.NET\-Ordner.

Namespace hinzufügen

Alle Typen der Klassenbibliothek gehören zum Namespace TwinCAT.Ads. Deshalb müssen folgende Zeilen am Anfang des Quelltextes anfügt werden:

Imports TwinCAT.Ads
Imports System.IO

Dies ermöglicht den Zugriff auf die in der TwinCAT.Ads definierten Datentypen ohne jedes mal den Namespace anzugeben. Die Klasse TcAdsClient ist der Kern der TwinCAT.Ads Klassenbibliothek und ermöglicht es dem Anwender mit einem ADS-Gerät zu kommunizieren. Als erstes muss eine Instanz der Klasse TcAdsClient erzeugt werden. Dann wird mit Hilfe der Connect Methode eine Verbindung mit dem ADS-Gerät hergestellt.

Eine Verbindung zu einem Ads-Gerät herstellen:

Private tcAds As TcAdsClient
...

tcAds = New TcAdsClient
tcAds.Connect("1.2.3.4.1.1", 801)

...

Die Daten werden mit Hilfe der AdsStream Klasse, die von System.IO.MemoryStream abgeleitet, übermittelt. Um Daten in Stream zu schreiben, kann die Klasse System.IO.BinaryWriter verwendet werden, und für das Lesen der Daten aus dem Stream ist die Klasse System.IO.BinaryReader verantwortlich.

Lesen einer SPS-Variablen:

' creates a stream with a length of 4 byte
Dim ds = New AdsStream(4)
Dim br = New BinaryReader(ds)

' reads a DINT from PLC
tcAds.Read(&H4020, 0, ds)
ds.Position = 0
TextBox1.Text = br.ReadInt32().ToString()

Schreiben einer SPS-Variablen:

' creates a stream with a length of 4 byte
Dim ds = New AdsStream(4)
Dim bw = New BinaryWriter(ds)

ds.Position = 0
bw.Write(New Integer = 100)

' writes a DINT to PLC
tcAds.Write(&H4020, 0, ds)

Eine Verbindung zu einem Ads-Gerät trennen:

tcAds.Dispose();

SPS-Programm:

PROGRAM MAIN
VAR
    test AT%MD0 : DINT;
END_VAR
test := test + 1


Visual Basic ADS.NET Beispiel01

TwinCAT Sample - VB - ADS .NET

Zugriff auf ein Array in der SPS

Aufgabe

In der SPS befindet sich ein Array, welches von einer .NET Applikation mit einem Lesebefehl ausgelesen werden soll.

Beschreibung

In der SPS befindet sich ein Array mit 100 Elementen vom Typ Integer (2 Byte). Das Array wird in der SPS mit den Werten 3500 bis 3599 aufgefüllt.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

...

#End Region

    Dim hVar As Integer
    Dim tcClient As TcAdsClient

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tcClient = New TcAdsClient()
        tcClient.Connect(801)

        Try
            hVar = tcClient.CreateVariableHandle("MAIN.PLCVar")
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try

    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        'Resourcen wieder freigeben
        Try
            tcClient.DeleteVariableHandle(hVar)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
        tcClient.Dispose()
    End Sub

    Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
        Try
            Dim dataStream As New AdsStream(100 * 2)
            Dim binRead As New BinaryReader(dataStream)

            'Array komplett auslesen
            tcClient.Read(hVar, dataStream)

            lbArray.Items.Clear()
            dataStream.Position = 0
            Dim i As Integer
            For i = 0 To 99
                lbArray.Items.Add(binRead.ReadInt16().ToString())
            Next
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

End Class

SPS-Programm

PROGRAM MAIN
VAR
    PLCVar : ARRAY [0..99] OF INT;
    Index: BYTE;
END_VAR
FOR Index := 0 TO 99 DO
    PLCVar[Index] := 3500 + INDEX;
END_FOR

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample01.exe


Visual Basic ADS.NET Beispiel02

TwinCAT Sample - VB - ADS .NET

Übertragen von Strukturen an die SPS

Aufgabe

Von einer .NET Applikation soll eine Struktur in die SPS geschrieben werden. Die Elemente der Struktur haben verschiedene Datentypen.

Beschreibung

Die Struktur, die in die SPS geschrieben werden soll:

TYPE PLCStruct
STRUCT
  intVal   : INT;  (*Offset 0*)
  dintVal  : DINT; (*Offset 2*)
  byteVal  : SINT; (*Offset 6*)
  lrealVal : LREAL;(*Offset 7*)
  realVal  : REAL; (*Offset 15 --> Gesamtgrösse 19 Bytes*)
END_STRUCT
END_TYPE

Das AdsStream Objekt wird mit einer Grösse von 19 Bytes initialisiert. Dies entspricht der Grösse des Datentyps PLCStruct in der SPS. Ein BinaryWriter wird verwendet, um die Daten der Editierfelder in den Stream zu schreiben. Nachdem die Position des Streams auf 0 gesetzt wird, werden die einzelnen Felder der Struktur in den Stream geschrieben. Als letztes wird der gesamte Stream mit Hilfe der TcAdsClient.Write in die SPS geschrieben.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

...

#End Region

    Dim hVar As Integer
    Dim tcClient As TcAdsClient

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Instanz der Klasse TcAdsClient erzeugen
        tcClient = New TcAdsClient()

        'Verbindung mit Port 801 auf dem lokalen Computer herstellen
        tcClient.Connect(801)

        Try
            hVar = tcClient.CreateVariableHandle("MAIN.PLCVar")
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        ' Resourcen wieder freigeben
        Try
            tcClient.DeleteVariableHandle(hVar)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
        tcClient.Dispose()
    End Sub

    Private Sub btnWrite_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim dataStream As New AdsStream(19)
        Dim binWrite As New BinaryWriter(dataStream)

        dataStream.Position = 0

        Try
            binWrite.Write(Short.Parse(tbInt.Text))
            binWrite.Write(Integer.Parse(tbDint.Text))
            binWrite.Write(Byte.Parse(tbByte.Text))
            binWrite.Write(Double.Parse(tbLReal.Text))
            binWrite.Write(Single.Parse(tbReal.Text))

            tcClient.Write(hVar, dataStream)

        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub
End Class

SPS-Programm

TYPE PLCStruct :
STRUCT
    intVal : INT;
    dintVal : DINT;
    sintVal : SINT;
    lrealVal : LREAL;
    realVal : REAL;
END_STRUCT
END_TYPE
PROGRAM MAIN
VAR
    PLCVar:PLCStruct;
END_VAR

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample02.exe


Visual Basic ADS.NET Beispiel03

TwinCAT Sample - VB - ADS .NET

Ereignissgesteuertes Lesen

Aufgabe

In der SPS befinden sich 7 globale Variablen. Jede SPS-Variable ist von einem anderen Datentyp. Die Werte der Variablen sollen auf möglichst effektive Weise ausgelesen und der Wert mit Zeitstempel auf einer Form dargestellt werden.

Beschreibung

In dem MainForm_Load-Ereignis der Form wird mit der Methode TcAdsClient.AddDeviceNotification() eine Verbindung zu jeder Variablen in der SPS erzeugt. Das Handle dieser Verbindung wird in einem Array gespeichert. Der Parameter TransMode spezifiziert die Art des Datenaustausches. In diesem Fall wird mit AdsTransMode.OnChange festgelegt, dass die SPS-Variable nur übermittelt wird falls sich der Wert in der SPS geändert hat(siehe AdsTransMode ). Der Parameter cycleTime bestimmt, wie oft die PLC checken soll, ob sich die entsprechende Varaiable geändert hat. MaxDelay ermöglicht es die Notifications für einen Zeitraum zu sammeln und nach Ablauf des Intervall im Block zu verschicken.

Wenn die SPS-Variable sich geändert hat, wird das TcAdsClient.AdsNotification() gefeuert. Der Parameter e der Eventhandler-Methode ist vom Typ AdsNotificationEventArgs und enthält die Zeit, das Handle, den Wert und das Textfeld, das die Daten anzeigen soll. In dem MainForm_FormClosing-Ereignis werden die Verbindungen wieder mit der Methode TcAdsClient.DeleteDeviceNotification() freigegeben. Dieses sollten Sie umbedingt beachten, da jede Verbindung die mit TcAdsClient.AddDeviceNotification() hergestellt wurde Resourcen verbraucht. Setzen Sie außerdem die CycleTime auf angemessene Werte, da zu viele Schreib / Leseoperationen das System so stark auslasten kann, dass die Bedieneroberfläche stark verlangsamt wird.

Hinweis: Im Callback (OnNotification()) dürfen keine zeitintensiven Aktionen ausgeführt werden.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "
...

#End Region

    ' Handle events (1): without withevents declaration
    Private tcClient As TcAdsClient
    ' Handle events (2):You can also declare tcClient as:
    ' Private WithEvents tcClient As TcAdsClient
    Private hConnect() As Integer
    Private dataStream As AdsStream
    Private binRead As BinaryReader

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim dataStream As New AdsStream(31)
        ' Encoding wird auf ASCII gesetzt, um Strings lesen zu können
        binRead = New BinaryReader(dataStream, System.Text.Encoding.ASCII)
        ' Instanz der Klasse TcAdsClient erzeugen
        tcClient = New TcAdsClient()
        ' Verbindung mit Port 801 auf dem lokalen Computer herstellen
        tcClient.Connect(801)

        ReDim hConnect(7)

        Try
            hConnect(0) = tcClient.AddDeviceNotification("MAIN.boolVal", dataStream, 0, 1, _
                AdsTransMode.OnChange, 100, 0, tbBool)
            hConnect(1) = tcClient.AddDeviceNotification("MAIN.intVal", dataStream, 1, 2, _
                AdsTransMode.OnChange, 100, 0, tbInt)
            hConnect(2) = tcClient.AddDeviceNotification("MAIN.dintVal", dataStream, 3, 4, _
                AdsTransMode.OnChange, 100, 0, tbDint)
            hConnect(3) = tcClient.AddDeviceNotification("MAIN.sintVal", dataStream, 7, 1, _
                AdsTransMode.OnChange, 100, 0, tbSint)
            hConnect(4) = tcClient.AddDeviceNotification("MAIN.lrealVal", dataStream, 8, 8, _
                AdsTransMode.OnChange, 100, 0, tbLreal)
            hConnect(5) = tcClient.AddDeviceNotification("MAIN.realVal", dataStream, 16, 4, _
                AdsTransMode.OnChange, 100, 0, tbReal)
            hConnect(6) = tcClient.AddDeviceNotification("MAIN.stringVal", dataStream, 20, 11, _
                AdsTransMode.OnChange, 100, 0, tbString)

            ' Handle events (1):
            AddHandler tcClient.AdsNotification, AddressOf OnNotification
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        Try
            tcClient.Dispose()
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    ' Handle events (2):
    ' Private Sub OnNotification(ByVal sender As Object, ByVal e As AdsSyncNotificationEventArgs) Handles tcClient.AdsSyncNotification
    ' Handle events (1):
    Private Sub OnNotification(ByVal sender As Object, ByVal e As AdsNotificationEventArgs)
        Dim time As New DateTime()
        time = DateTime.FromFileTime(e.TimeStamp)
        e.DataStream.Position = e.Offset
        Dim strValue As String = ""

        If (e.NotificationHandle = hConnect(0)) Then
            strValue = binRead.ReadBoolean().ToString()
        ElseIf (e.NotificationHandle = hConnect(1)) Then
            strValue = binRead.ReadInt16().ToString()
        ElseIf (e.NotificationHandle = hConnect(2)) Then
            strValue = binRead.ReadInt32().ToString()
        ElseIf (e.NotificationHandle = hConnect(3)) Then
            strValue = binRead.ReadByte().ToString()
        ElseIf (e.NotificationHandle = hConnect(4)) Then
            strValue = binRead.ReadDouble().ToString()
        ElseIf (e.NotificationHandle = hConnect(5)) Then
            strValue = binRead.ReadSingle().ToString()
        ElseIf (e.NotificationHandle = hConnect(6)) Then
            strValue = New String(binRead.ReadChars(11))
        End If

        Dim tb As New TextBox()
        tb = CType(e.UserData, TextBox)
        tb.Text = String.Format("DateTime: {0},{1}ms; {2}", time, time.Millisecond, strValue)
    End Sub
End Class

SPS-Programm

PROGRAM MAIN
VAR
    boolVal : BOOL;
    intVal : INT;
    dintVal : DINT;
    sintVal : SINT;
    lrealVal : LREAL;
    realVal : REAL;
    stringVal : STRING(10);
END_VAR
;

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample03.exe


Visual Basic ADS.NET Beispiel04

TwinCAT Sample - VB - ADS .NET

Lesen und Schreiben von STRING-Variablen

Aufgabe

Eine .NET Applikation soll einen String von der SPS lesen und einen String in die SPS schreiben.

Beschreibung

Der SPS-String hat den Namen: MAIN.text.

Im MainForm_Load-Ereignis wird eine neue Instanz der Klasse TcAdsClient erzeugt. Dann wird die Methode TcAdsClient.Connect des TcAdsClient Objektes aufgerufen, um eine Verbindung mit dem Port 801 herzustellen. Zum Schluss wird dann die Methode TcAdsClient.CreateVariableHandle aufgerufen, um sich ein Handle auf die SPS-Variable zu besorgen. Wenn das Programm beendet wird, wird das Handle in der Ereignis-Methode MainForm_FormClosing wieder freigegeben und die Dispose-Methode des TcAdsClient Objektes wird aufgerufen.

Wenn der Anwender den "Read"-Button betätigt, wird die String-Variable MAIN.text mit Hilfe der Methode TcAdsClient.Read aus der SPS gelesen und in dem Editierfeld angezeigt. Wenn der Anwender den "Write"-Button betätigt, wird der Text der im Editierfeld steht in die SPS-Variable MAIN.text geschrieben.

TwinCAT.Ads.NET Version < 1.0.0.10:

Die Länge vom AdsStream muss der Länge des Strings in der SPS + 1 (mit der Null-Terminierung) entsprechen. Der Parameter System.Text.Encoding.ASCII wird dem Konstruktor der BinaryReader Klasse übergeben. Dies ist notwendig, damit die BinaryReader Klasse in der Lage ist, die ANSI-Zeichen in den Typen char zu konvertieren.

TwinCAT.Ads.NET Version >= 1.0.0.10:

Mit Hilfe der Klassen AdsBinaryReader and AdsBinaryWriter können SPS-Strings aus einem AdsStream gelesen und in einen AdsStream geschrieben werden (siehe kommentierten Abschnitt des Beispiel-Programmes). Diese Klassen sind direkt von den Klassen BinaryReader und BinaryWriter abgeleitet. Um einen String aus dem Stream zu lesen wird die Methode AdsBinaryReader.ReadPlcString aufgerufen. Um einen String in den Stream zu schreiben wird die Methode AdsBinaryWriter.WritePLCString aufgerufen. Die Länge vom AdsStream muss der Länge des Strings in der SPS entsprechen (ohne die Null-Terminierrung). Die Länge der String-Variablen wird der Methode als Parameter übergeben und muss der Länge des Strings in der SPS entsprechen (ohne Null-Terminierung).

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form

    Private adsClient As TcAdsClient
    Private varHandle As Integer

#Region " Windows Form Designer generated code "

...

#End Region
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            adsClient = New TcAdsClient
            adsClient.Connect(801)
            varHandle = adsClient.CreateVariableHandle("MAIN.text")
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        adsClient.Dispose()
    End Sub

    Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
        Dim length As Integer
        Dim text As String
        Dim dataStream As AdsStream
        Dim reader As BinaryReader
        Try
            'length of the stream = length of string in sps + 1
            dataStream = New AdsStream(31)
            reader = New BinaryReader(dataStream, System.Text.Encoding.ASCII)
            length = adsClient.Read(varHandle, dataStream)
            text = New String(reader.ReadChars(length))
            'necessary if you want to compare the string to other strings
            'text = text.Substring(0, text.IndexOf(Chr(0)))
            textBox1.Text = text
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub btnWrite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim dataStream As AdsStream
        Dim writer As BinaryWriter
        Dim c As Char
        Try
            'length of the stream = length of string + 1
            dataStream = New AdsStream(textBox1.Text.Length + 1)
            writer = New BinaryWriter(dataStream, System.Text.Encoding.ASCII)
            writer.Write(textBox1.Text.ToCharArray())
            'add terminating zero
            writer.Write(Chr(0))
            adsClient.Write(varHandle, dataStream)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try

    End Sub

End Class

SPS Programm

PROGRAM MAIN
VAR
    text : STRING[30] := 'hello';
END_VAR
;

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample04.exe TwinCAT.Ads.NET v1.0.0.10 und höher Sample04b.exe


Visual Basic ADS.NET Beispiel05

TwinCAT Sample - VB - ADS .NET

Lesen und Schreiben von DATE/TIME-Variablen

Ab TwinCAT.Ads.NET Version >= 1.0.0.10

Aufgabe

Es soll eine .NET Applikation geschrieben werden die DATE/TIME-Variablen liest bzw. beschreibt.

Beschreibung

Das SPS-Program enthält folgende Variablen:

  • MAIN.Time1 vom Typ TIME;
  • MAIN.Date1 vom Typ DATE;

Im MainForm_Load-Ereignis der Form wird eine neue Instanz der Klasse TcAdsClient erzeugt. Dann wird die Methode TcAdsClient.Connect des TcAdsClient Objektes aufgerufen, um eine Verbindung mit dem Port 801 herzustellen. Zum Schluss wird dann die Methode TcAdsClient.CreateVariableHandle aufgerufen, um sich ein Handle auf die SPS-Variable zu besorgen. Wenn das Programm beendet wird, wird das Handle in der Ereignis-Methode: MainForm_FormClosing wieder freigegeben und die Dispose-Methode des TcAdsClient Objektes wird aufgerufen.

Wenn der Anwender den "Read"-Button betätigt, werden die Variablen MAIN.Time1, MAIN.Date1 usw. mit Hilfe der Methode TcAdsClient.Read aus dem AdsStream gelesen. Die Klasse AdsBinaryReader, die von BinaryReader abgeleitet ist, wird dazu eingesetzt , eine Zeit bzw. ein Datum aus der SPS zu lesen. Die Methode AdsBinaryReader.ReadPlcTIME liest die TIME-Variable aus dem Stream und konvertiert diese in den .NET Datentypen: TimeSpan. Die Methode AdsBinaryReader.ReadPlcDATE liest die DT-Variable aus dem AdsStream und konvertiert diese in den .NET Typen: DataTime.

Wenn der Anwender den "Write"-Button betätigt, werden die SPS-Variablen MAIN.Time1, MAIN.Date1 usw. beschrieben. Die Klasse AdsBinaryWriter, die von BinaryWriter abgeleitet ist, kann eingesetzt werden, um eine Zeit bzw. ein Datum in die SPS zu schreiben. Die Methode AdsBinaryWriter.WritePlcType schreibt die .NET Typen: TimeSpan und DateTime im SPS-Format in den Stream.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO

Public Class Form1
    Inherits System.Windows.Forms.Form

    Private adsClient As TcAdsClient
    Private varHandles(1) As Integer

#Region " Windows Form Designer generated code "

...

#End Region
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            adsClient = New TcAdsClient
            adsClient.Connect(801)
            varHandles(0) = adsClient.CreateVariableHandle("MAIN.Time1")
            varHandles(1) = adsClient.CreateVariableHandle("MAIN.Date1")
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        adsClient.Dispose()
    End Sub

    Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
        Dim length As Integer
        Dim text As String
        Dim dataStream As AdsStream
        Dim reader As AdsBinaryReader
        Try
            dataStream = New AdsStream(30)
            reader = New AdsBinaryReader(dataStream)
            adsClient.Read(varHandles(0), dataStream)
            textBox1.Text = reader.ReadPlcTIME().ToString()

            dataStream.Position = 0
            adsClient.Read(varHandles(1), dataStream)
            textBox2.Text = reader.ReadPlcDATE().ToString()
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub btnWrite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnWrite.Click
        Dim dataStream As AdsStream
        Dim writer As AdsBinaryWriter
        Dim c As Char
        Try
            dataStream = New AdsStream(4)
            writer = New AdsBinaryWriter(dataStream)
            writer.WritePlcType(TimeSpan.Parse(textBox1.Text))
            adsClient.Write(varHandles(0), dataStream)

            dataStream.Position = 0
            writer.WritePlcType(DateTime.Parse(textBox2.Text))
            adsClient.Write(varHandles(1), dataStream)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub
End Class

SPS Programm

PROGRAM MAIN
VAR
    Time1 	:TIME := T#521h33m23s231ms;
    Date1 	:DATE := D#1993-06-12;
END_VAR
;

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample05.exe


Visual Basic ADS.NET Beispiel06

TwinCAT Sample - VB - ADS .NET

SPS-Variablendeklaration auslesen

Ab TwinCAT.Ads.NET version >= 1.0.0.12

Aufgabe

Alle Variablen, die in der SPS deklariert sind, sollen in einer Baumansicht dargestellt.

Beschreibung

In der Ereignismethode MainForm_Load wird mit TcAdsClient.CreateSymbolInfoLoader eine Instanz der Klasse TcAdsSymbolInfoLoader erzeugt. Diese Klasse ist verantwortlich für das laden der Symbol-Information von der SPS. Durch das Betätigen des Buttons Load Symbols werden die Symbole mit Hilfe der Methode TcAdsSymbolInfoLoader.GetFirstSymbol von der SPS geladen. Als Rückgabewert wird das erste geladen Symbol in Form eines TcAdsSymbolInfo-Objektes zurückgeliefert. Die Methoden TcAdsSymbolInfo.NextSymbol und TcAdsSymbolInfo.FirstSubSymbol werden dann verwendet, um über alle Symbole zu itererieren und damit die Symbols-Baumansicht hierarchisch zu füllen. Wenn die Checkbox Flat angewählt ist werden die Symbole als flache Liste dargestellt. Dazu wird einfach über die Symbole von TcAdsSymbolInfoLoader enumeriert. Dabei werden auch die Sub-Symbole dargestellt.

Beim Selektieren eines TreeView-Items werden die Editierfelder mit der Symbol-Information gefüllt. Zusätzlich wird der Wert des Symbols mit TcAdClient.ReadSymbol ausgelesen und im Editierfeld Value ausgegeben. Durch Betätigen des Write Value Buttons wird die Methode TcAdsCient.WriteSymbol verwendet, um einen Wert in die SPS-Variable zu schreiben.

Um die Symbol-Information einer bestimmten Variablen auszulesen, kann entweder Read Symbol Info oder Find Symbol verwendet werden. Die erste Variante verwendet die Methode TcAdsClient.ReadSymbolInfo. Hierbei wird ein ADS-Aufruf verwendet, um die Symbol-Information für dieses Symbol von der SPS zu lesen. Die zweite Variante verwendet die Methode TcAdsSymbolInfoLoader.FindSymbol, die das Symbol in der Liste der bereits geladenen Symbole sucht. Wenn vorher noch keine Symbole geladen wurden, werden alle Symbole von der SPS geladen.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.IO
Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

...

#End Region

    Private symbolLoader As TcAdsSymbolInfoLoader
    Private adsClient As TcAdsClient
    Private currentSymbol As ITcAdsSymbol = Nothing

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            adsClient = New TcAdsClient
            adsClient.Connect(801)
            symbolLoader = adsClient.CreateSymbolInfoLoader()
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click
        Dim node As TreeNode
        treeViewSymbols.Nodes.Clear()
        Try
            If (Not cbFlat.Checked) Then
                Dim symbol As TcAdsSymbolInfo
                symbol = symbolLoader.GetFirstSymbol(True)
                While (Not symbol Is Nothing)
                    treeViewSymbols.Nodes.Add(CreateNewNode(symbol))
                    symbol = symbol.NextSymbol
                End While
            Else
                For Each symbol As TcAdsSymbolInfo In symbolLoader
                    node = New TreeNode(symbol.Name)
                    node.Tag = symbol
                    treeViewSymbols.Nodes.Add(node)
                Next
            End If
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub btnReadSymbolInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReadSymbolInfo.Click
        Dim symbol As ITcAdsSymbol
        Try
            symbol = adsClient.ReadSymbolInfo(tbSymbolname.Text)
            If (symbol Is Nothing) Then
                MessageBox.Show("Symbol " + tbSymbolname.Text + " not found")
                Return
            End If
            Call SetSymbolInfo(symbol)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub btnFindSymbol_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindSymbol.Click
        Dim symbol As ITcAdsSymbol
        Try
            symbol = symbolLoader.FindSymbol(tbSymbolname.Text)
            If (symbol Is Nothing) Then
                MessageBox.Show("Symbol " + tbSymbolname.Text + " not found")
                Return
            End If
            Call SetSymbolInfo(symbol)
        Catch err As Exception
            MessageBox.Show(err.Message)
        End Try
    End Sub

    Private Sub treeViewSymbols_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles treeViewSymbols.AfterSelect
        If (e.Node.Text.Length > 0) Then
            If (TypeOf e.Node.Tag Is TcAdsSymbolInfo) Then
                SetSymbolInfo(DirectCast(e.Node.Tag, ITcAdsSymbol))
            End If
        End If
    End Sub

    Private Sub btnWrite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnWrite.Click
        Try
            If (Not currentSymbol Is Nothing) Then
                adsClient.WriteSymbol(currentSymbol, tbValue.Text)
            End If
        Catch err As Exception
            MessageBox.Show("Unable to write Value. " + err.Message)
        End Try
    End Sub
    Private Function CreateNewNode(ByVal symbol As TcAdsSymbolInfo) As TreeNode
        Dim node As TreeNode
        Dim subsymbol As TcAdsSymbolInfo
        node = New TreeNode(symbol.Name)
        node.Tag = symbol
        subsymbol = symbol.FirstSubSymbol
        While (Not subsymbol Is Nothing)
            node.Nodes.Add(CreateNewNode(subsymbol))
            subsymbol = subsymbol.NextSymbol
        End While
        Return node
    End Function

    Private Sub SetSymbolInfo(ByVal symbol As ITcAdsSymbol)
        currentSymbol = symbol
        tbName.Text = symbol.Name.ToString()
        tbIndexGroup.Text = symbol.IndexGroup.ToString()
        tbIndexOffset.Text = symbol.IndexOffset.ToString()
        tbSize.Text = symbol.Size.ToString()
        tbDatatype.Text = symbol.Type
        tbDatatypeId.Text = symbol.Datatype.ToString()
        Try
            tbValue.Text = adsClient.ReadSymbol(symbol).ToString()
        Catch err As AdsDatatypeNotSupportedException
            tbValue.Text = err.Message
        Catch err As Exception
            MessageBox.Show("Unable to read Symbol Info. " + err.Message)
        End Try
    End Sub
End Class

SPS-Programm

PROGRAM MAIN
VAR
    REAL32_1 AT %MB0 : REAL;		(* 1 *)
    REAL32_2 AT %MB4 : REAL;		(* 2 *)
    REAL32_3 AT %MB8 : REAL;		(* 3 *)
    REAL32_4 AT %MB12: REAL;		(* 4 *)
    REAL32_5 AT %MB16: REAL;		(* 5 *)
    REAL64_1 AT %MB20 : LREAL;		(* 6 *)
    REAL64_2 AT %MB28 : LREAL;		(* 7 *)
    REAL64_3 AT %MB36 : LREAL;		(* 8 *)
    REAL64_4 AT %MB44 : LREAL;		(* 9 *)
    REAL64_5 AT %MB52 : LREAL;		(* 10 *)
    INT32_1 AT %MB60 : DINT;		(* 11 *)
    INT32_2 AT %MB64 : DINT;		(* 12 *)
    INT32_3 AT %MB68 : DINT;		(* 13 *)
    INT32_4 AT %MB72 : DINT;		(* 14 *)
    INT32_5 AT %MB76 : DINT;		(* 15 *)
    UINT32_1 AT %MB80 : UDINT;		(* 16 *)
    UINT32_2 AT %MB84 : UDINT;		(* 17 *)
    UINT32_3 AT %MB88 : UDINT;		(* 18 *)
    UINT32_4 AT %MB92 : UDINT;		(* 19 *)
    UINT32_5 AT %MB96 : UDINT;		(* 20 *)
    INT16_1 AT %MB100 : INT;		(* 21 *)
    INT16_2 AT %MB102 : INT;		(* 22 *)
    INT16_3 AT %MB104 : INT;		(* 23 *)
    INT16_4 AT %MB106 : INT;		(* 24 *)
    INT16_5 AT %MB108 : INT;		(* 25 *)
    UINT16_1 AT %MB110 : UINT;		(* 26 *)
    UINT16_2 AT %MB112 : UINT;		(* 27 *)
    UINT16_3 AT %MB114 : UINT;		(* 28 *)
    UINT16_4 AT %MB116 : UINT;		(* 29 *)
    UINT16_5 AT %MB118 : UINT;		(* 30 *)
    INT8_1 AT %MB120 : SINT;		(* 31 *)
    INT8_2 AT %MB121 : SINT;		(* 32 *)
    INT8_3 AT %MB122 : SINT;		(* 33 *)
    INT8_4 AT %MB123 : SINT;		(* 34 *)
    INT8_5 AT %MB124 : SINT;		(* 35 *)
    UINT8_1 AT %MB125 : USINT;		(* 36 *)
    UINT8_2 AT %MB126 : USINT;		(* 37 *)
    UINT8_3 AT %MB128 : USINT;		(* 38 *)
    UINT8_4 AT %MB129 : USINT;		(* 39 *)
    UINT8_5 AT %MB130 : USINT;		(* 40 *)
    BOOL_1 AT %MX131.0 : BOOL;		(* 41 *)
    BOOL_2 AT %MX131.1 : BOOL;		(* 42 *)
    BOOL_3 AT %MX131.2 : BOOL;		(* 43 *)
    BOOL_4 AT %MX131.3 : BOOL;		(* 44 *)
    BOOL_5 AT %MX131.4 : BOOL;		(* 45 *)
    ARRAY_1	: ARRAY[1 .. 10] OF SINT;	(* 46 *)
    ARRAY_2	: ARRAY[1 .. 10] OF INT;	(* 47 *)
    ARRAY_3	: ARRAY[1 .. 10] OF DINT;	(* 48 *)
    ARRAY_4	: ARRAY[1 .. 10] OF LREAL;	(* 49 *)
    ARRAY_5	: ARRAY[1 .. 10] OF BOOL;	(* 50 *)
    STRING_1 : STRING(20);
END_VAR
;

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample06.exe


Visual Basic ADS.NET Beispiel07

TwinCAT Sample - VB - ADS .NET

Lesen und Schreiben von SPS-Variablen eines beliebigen Types

Ab TwinCAT.Ads.NET Version >= 1.0.0.15

Aufgabe

Auslesen bzw. Beschreiben von Variablen eines beliebigen Typs mit Hilfe der Methode ReadAny bzw. WriteAny.

Beschreibung

ReadAny

In der Event-Methode btnRead_Click wird die Methode TcAdsClient.ReadAny verwendet um die Variablen per Handle auszulesen:

TwinCAT.Ads.TcAdsClient.ReadAny(System.Int32, System.Type)
TwinCAT.Ads.TcAdsClient.ReadAny(System.Int32, System.Type, System.Int32[])

Der Methode wird im Parameter type der Typ der zu lesenden Variable übergeben. Wenn die Methode erfolgreich gewesen ist, werden die gelesenen Daten als Objekt zurückgeliefert. Der Typ des Objektes entspricht dem Parameter type. Da bei einigen Datentypen(Arrays und Strings) zusätzliche Informationen notwendig sind gibt es eine Überladung der Methode ReadAny, die den zusätzlichen Parameter args enthält. Eine vollständige Liste der unterstützten Typen finden Sie in der Dokumentation der überladenen Methode.

Beispiel:

Eine globale SPS-Variable vom Type ARRAY[0..3] OF DINT soll gelesen werden:

Dim hArr As Integer
Dim arr(0 To 3) As Integer

hArr = adsClient.CreateVariableHandle(".arr")
arr = adsClient.ReadAny(hArr, GetType(Integer()), New Integer() {4})

...
adsClient.DeleteVariableHandle(hArr)

WriteAny

In der Event-Methode btnWrite_Click wird die Methode TcAdsClient.WriteAny verwendet um die Variablen per Handle zu beschreiben:

TwinCAT.Ads.TcAdsClient.WriteAny(System.Int32, System.Object)
TwinCAT.Ads.TcAdsClient.WriteAny(System.Int32, System.Object, System.Int32[])

Der Parameter value enthält das Objekt, das in die SPS geschrieben werden soll. Eine vollständige Liste der unterstützten Typen von value finden Sie in der Dokumentation der überladenen Methode.

Beispiel:

Eine globale SPS-Variable vom Typ ARRAY[0..3] OF DINT soll beschrieben werden:

Dim hArr As Integer
Dim arr As Integer() = New Integer() {1, 2, 3, 4}

hArr = adsClient.CreateVariableHandle(".arr")
adsClient.WriteAny(hArr, arr)

...
adsClient.DeleteVariableHandle(hArr)

Lesen und Schreiben von Strukturen (nicht möglich mit dem Compact Framework, CE):

Beim Lesen und beschreiben von Strukturen und Klassen, muss darauf geachtet werden, dass das Speicherlayout der Struktur dem Layout in der SPS entspricht. Das Layout kann mit dem Attribut StructLayoutAttribute festgelegt werden. Dabei muss als LayoutKind LayoutKind.Sequential ausgewählt werden und Pack auf 1 gesetzt werden. Die Klasse SimpleStruct ist deshalb wie folgt definiert worden:

<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Class SimpleStruct
    Public lrealVal As Double
    Public dintVal1 As Integer
End Class

Wenn Arrays, Strings oder boolsche Werte in einer Struktur/Klasse definiert sind, muss man festlegen, wie diese gemarshallt werden. Dies geschieht mit Hilfe des MarshalAs Attributs. Da Arrays und Strings unter .Net normalerweise keine feste Länge haben, muss mit dem Property SizeConst die Grösse des Arrays bzw. des Strings festgelegt werden. Das Marshallen von Mehrdimensionale Arrays oder Arrays von Strukturen ist mit dem Marhaler des .NET Frameworks 1.1 nicht möglich. Mehrdimensionale Arrays müssten auf eindimensionale Arrays abgebildet werden. Arrays von Strukturen müssten in der .NET Struktur aufgelöst werden.

In dem Beispiel wird das MarshalAsAttribute in der Klasse ComplexStruct verwendet:

<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Class ComplexStruct
    Public intVal As Short
    'specifies how .NET should marshal the array
    'SizeConst specifies the number of elements the array has.
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
    Public dintArr(4) As Integer
    <MarshalAs(UnmanagedType.I1)> _
    Public boolVal As Boolean
    Public byteVal As Byte
    'specifies how .NET should marshal the string
    'SizeConst specifies the number of characters the string has.
    '(inclusive the terminating null ).
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> _
    Public stringVal As String = ""
    Public simpleStruct1 As SimpleStruct = New SimpleStruct
End Class

Anmelden von ADS Notifications

In der Ereignis-Methode btnAddNotifications_Click wird die Methode AddDeviceNotificationEx dazu verwendet, Notifications für die SPS Variable anzumelden. Bei Änderung des Wertes der Variable wird das Ereignis AdsNotificationEx ausgelöst. Der Unterschied zu dem Ereignis AdsNotifcation, besteht darin das der Wert einer Variablen in einem Objekt gespeichert ist, anstatt in einem AdsStream. Der Methode AddNotificationEx muss dazu der Typ dieses Objektes übergeben werden:

notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.dint1", AdsTransMode.OnChange, 100, 0, tbDint1, GetType(Integer)))

Als User-Objekt wurde hier die Textbox, die den Wert anzeigen soll, übergeben. Wenn das Ereignis ausgelöst wird, wird die Ereignis-Methode adsClient_AdsNotificationEx aufgerufen.

Visual Basic (for .NET framework) Programm

Imports TwinCAT.Ads
Imports System.Runtime.InteropServices

Public Class Form1
    Inherits System.Windows.Forms.Form

    'PLC variable handles
    Private hdint1 As Integer
    Private hbool1 As Integer
    Private husint1 As Integer
    Private hlreal1 As Integer
    Private hstr1 As Integer
    Private hstr2 As Integer
    Private hcomplexStruct As Integer
    Private notificationHandles As ArrayList

#Region " Windows Form Designer generated code "

...

#End Region
    Private WithEvents adsClient As TcAdsClient

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        adsClient = New TcAdsClient
        notificationHandles = New ArrayList
        Try
            adsClient.Connect(801)
            btnDeleteNotifications.Enabled = False
            'create handles for the PLC variables
            hbool1 = adsClient.CreateVariableHandle("MAIN.bool1")
            hdint1 = adsClient.CreateVariableHandle("MAIN.dint1")
            husint1 = adsClient.CreateVariableHandle("MAIN.usint1")
            hlreal1 = adsClient.CreateVariableHandle("MAIN.lreal1")
            hstr1 = adsClient.CreateVariableHandle("MAIN.str1")
            hstr2 = adsClient.CreateVariableHandle("MAIN.str2")
            hcomplexStruct = adsClient.CreateVariableHandle("MAIN.ComplexStruct1")
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        adsClient.Dispose()
    End Sub

    Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
        Try
            'read by handle
            'the second parameter specifies the type of the variable
            tbDint1.Text = adsClient.ReadAny(hdint1, GetType(Integer)).ToString()
            tbUsint1.Text = adsClient.ReadAny(husint1, GetType(Byte)).ToString()
            tbBool1.Text = adsClient.ReadAny(hbool1, GetType(Boolean)).ToString()
            tblreal1.Text = adsClient.ReadAny(hlreal1, GetType(Double)).ToString()
            'with strings one has to additionally pass the number of characters
            'specified in the PLC project(default 80).
            'This value is passed is an Integer array.
            tbStr1.Text = adsClient.ReadAny(hstr1, GetType(String), New Integer() {80}).ToString()
            tbStr2.Text = adsClient.ReadAny(hstr2, GetType(String), New Integer() {5}).ToString()
            FillStructControls(adsClient.ReadAny(hcomplexStruct, GetType(ComplexStruct)))
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub btnWrite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnWrite.Click
        Try
            'write by handle
            'the second parameter is the object to be written to the PLC variable
            adsClient.WriteAny(hdint1, Integer.Parse(tbDint1.Text))
            adsClient.WriteAny(husint1, Byte.Parse(tbUsint1.Text))
            adsClient.WriteAny(hbool1, Boolean.Parse(tbBool1.Text))
            adsClient.WriteAny(hlreal1, Double.Parse(tblreal1.Text))
            'with strings one has to additionally pass the number of characters
            'the variable has in the PLC(default 80).
            adsClient.WriteAny(hstr1, tbStr1.Text, New Integer() {80})
            adsClient.WriteAny(hstr2, tbStr2.Text, New Integer() {5})
            adsClient.WriteAny(hcomplexStruct, GetStructFromControls())
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

    Private Sub btnAddNotifications_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddNotifications.Click
        notificationHandles.Clear()
        Try
            'register notification
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.dint1", AdsTransMode.OnChange, 100, 0, tbDint1, GetType(Integer)))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.usint1", AdsTransMode.OnChange, 100, 0, tbUsint1, GetType(Byte)))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.bool1", AdsTransMode.OnChange, 100, 0, tbBool1, GetType(Boolean)))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.lreal1", AdsTransMode.OnChange, 100, 0, tblreal1, GetType(Double)))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.str1", AdsTransMode.OnChange, 100, 0, tbStr1, GetType(String), New Integer() {80}))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.str2", AdsTransMode.OnChange, 100, 0, tbStr2, GetType(String), New Integer() {5}))
            notificationHandles.Add(adsClient.AddDeviceNotificationEx("MAIN.complexStruct1", AdsTransMode.OnChange, 100, 0, tbDint1, GetType(ComplexStruct)))
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        btnDeleteNotifications.Enabled = True
        btnAddNotifications.Enabled = False
    End Sub

    Private Sub btnDeleteNotifications_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeleteNotifications.Click
        'delete registered notifications.
        Try
            For Each handle As Integer In notificationHandles
                adsClient.DeleteDeviceNotification(handle)
            Next
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        notificationHandles.Clear()
        btnAddNotifications.Enabled = True
        btnDeleteNotifications.Enabled = False
    End Sub

    Private Sub adsClient_AdsNotificationEx(ByVal sender As Object, ByVal e As TwinCAT.Ads.AdsNotificationExEventArgs) Handles adsClient.AdsNotificationEx
        Dim txtBox As TextBox = e.UserData
        Dim type As Type = e.Value.GetType()
        If (type Is GetType(String) Or type.IsPrimitive()) Then
            txtBox.Text = e.Value
        ElseIf (type Is GetType(ComplexStruct)) Then
            FillStructControls(DirectCast(e.Value, ComplexStruct))
        End If
    End Sub

    Public Sub FillStructControls(ByVal struct As ComplexStruct)
        tbComplexStruct_IntVal.Text = struct.intVal
        tbComplexStruct_dintArr.Text = String.Format("{0}, {1}, {2}, {3}", struct.dintArr(0), struct.dintArr(1), struct.dintArr(2), struct.dintArr(3))
        tbComplexStruct_boolVal.Text = struct.boolVal
        tbComplexStruct_ByteVal.Text = struct.byteVal
        tbComplexStruct_stringVal.Text = struct.stringVal
        tbComplexStruct_SimpleStruct1_lrealVal.Text = struct.simpleStruct1.lrealVal
        tbComplexStruct_SimpleStruct_dintVal.Text = struct.simpleStruct1.dintVal1
    End Sub

    Public Function GetStructFromControls() As ComplexStruct
        Dim struct As ComplexStruct = New ComplexStruct
        Dim stringArr() As String = tbComplexStruct_dintArr.Text.Split(New Char() {","})

        struct.intVal = Short.Parse(tbComplexStruct_IntVal.Text)
        For i As Integer = 0 To stringArr.Length - 1
            struct.dintArr(i) = Integer.Parse(stringArr(i))
        Next
        struct.boolVal = Boolean.Parse(tbComplexStruct_boolVal.Text)
        struct.byteVal = Byte.Parse(tbComplexStruct_ByteVal.Text)
        struct.stringVal = tbComplexStruct_stringVal.Text
        struct.simpleStruct1.dintVal1 = Integer.Parse(tbComplexStruct_SimpleStruct_dintVal.Text)
        struct.simpleStruct1.lrealVal = Double.Parse(tbComplexStruct_SimpleStruct1_lrealVal.Text)
        Return struct
    End Function
End Class

<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Class SimpleStruct
    Public lrealVal As Double
    Public dintVal1 As Integer
End Class

<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Class ComplexStruct
    Public intVal As Short
    'specifies how .NET should marshal the array
    'SizeConst specifies the number of elements the array has.
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
    Public dintArr(4) As Integer
    <MarshalAs(UnmanagedType.I1)> _
    Public boolVal As Boolean
    Public byteVal As Byte
    'specifies how .NET should marshal the string
    'SizeConst specifies the number of characters the string has.
    '(inclusive the terminating null ).
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> _
    Public stringVal As String = ""
    Public simpleStruct1 As SimpleStruct = New SimpleStruct
End Class

SPS-Program

TYPE TSimpleStruct :
STRUCT
    lrealVal : LREAL := 1.23;
    dintVal : DINT := 120000;
END_STRUCT
END_TYPE

TYPE TComplexStruct :
STRUCT
    intVal : INT :=1200;
    dintArr : ARRAY[0..3] OF DINT:= 1,2,3,4;
    boolVal : BOOL := FALSE;
    byteVal : BYTE :=10;
    stringVal : STRING(5) := 'hallo';
    simpleStruct1 : TSimpleStruct;
END_STRUCT
END_TYPE

PROGRAM MAIN
VAR
    (*primitive Types*)
    bool1		:BOOL 	:= FALSE;
    int1		:INT 	:= 30000;
    dint1		:DINT	:=125000;
    usint1		:USINT	:=200;
    real1		:REAL	:= 1.2;
    lreal1		:LREAL	:=3.5;
    (*string Types*)
    str1		:STRING 	:= 'this is a test string';
    str2		:STRING(5):= 'hallo';
    (*struct Types*)
    complexStruct1 	: TComplexStruct;
END_VAR
;

Sprache / IDE | Beispielprogram auspacken
Visual Basic (for .NET framework) | Sample07.exe


Beispiel - Visual Basic

TwinCAT ADS-Script-DLL - Reference

Lesen und Schreiben von SPS Variablen

Wie in der Einleitung schon erwähnt, ist die ADS-Script-DLL in erster Linie für Scriptsprachen entwickelt worden. Trotzdem ist an dieser Stelle ein Visual Basic Programm. Es dient legendlich dazu, die Möglichkeiten der ADS-Script-DLL besser zu demonstrieren. Für Anwendungen, die mit Visual Basic erstellt werden sollen, ist das ADS-OCX besser geeignet.

Laden Sie als erstes das SPS-Programm in die lokale SPS (Laufzeitsystem 1) auf Ihrem PC. Starten Sie anschließend das Visual Basic Programm:

Wenn Sie keine anderen Angaben machen, wird ein Kommunikationskanal zu Ihrer lokalen SPS hergestellt. Durch Eingabe einer anderen AdsAmsNetId und einer anderen Portnummer können Sie eine Verbindung zu einem anderen Laufzeitsystem auf einem anderen PC herstellen. Auf diesem Laufzeitsystem muss dann allerdings das oben genannte SPS-Programm aktiv sein. Ebenfalls muss der evtl. ausgewählte Remote Rechner im TwinCAT System Control eingetragen sein.

Sie können wahlweise die SPS-Variablen per Adresse (IndexGroup und IndexOffset), oder per Variablenname auslesen. Gleiches gilt auch für das Schreiben neuer Werte. Für den Bediener hat dieses keine Bedeutung. Es soll nur die beiden Möglichkeiten aufführen.

In der oberen rechten Ecke kann der Zustand der SPS ausgelesen und verändert werden. Eine 5 entspricht dem RUN-Zustand und eine 6 dem STOP-Zustand.

Visual Basic 6 Programm

Option Explicit

Public TcClientSync As TCSCRIPTLib.TcScriptSync
Public nAdsAmsPort As Integer
Public strAdsAmsNetId As String

Private Sub Form_Load()
    Set TcClientSync = CreateObject("TcScript.TcScriptSync")
    Call TcClientSync.ConnectTo("", 801)
End Sub

Private Sub Form_Terminate()
    Set TcClientSync = Nothing
End Sub

Private Sub cmdConnect_Click()
    nAdsAmsPort = CLng(txtAdsAmsPort.Text)
    if (Len(txtAdsAmsNetId.Text) > 0) Then
       strAdsAmsNetId = txtAdsAmsNetId.Text
    Else
       strAdsAmsNetId = ""
    End If
    Set TcClientSync = CreateObject("TcScript.TcScriptSync")
    Call TcClientSync.ConnectTo(strAdsAmsNetId, nAdsAmsPort)
End Sub

Private Sub cmdRead_Click()
    Dim VarBool As Variant
    Dim VarInt8 As Byte
    Dim VarInt16 As Integer
    Dim VarInt32 As Long
    Dim VarReal32 As Single
    Dim VarReal64 As Double

    VarBool = TcClientSync.ReadBool(&H4020, 0)
    lblBoolean.Caption = VarBool

    VarInt8 = TcClientSync.ReadInt8(&H4020, 2)
    lblInt8.Caption = VarInt8

    VarInt16 = TcClientSync.ReadInt16(&H4020, 4)
    lblInt16.Caption = VarInt16

    VarInt32 = TcClientSync.ReadInt32(&H4020, 6)
    lblInt32.Caption = VarInt32

    VarReal32 = TcClientSync.ReadReal32(&H4020, 10)
    lblReal32.Caption = VarReal32

    VarReal64 = TcClientSync.ReadReal64(&H4020, 14)
    lblReal64.Caption = VarReal64
End Sub

Private Sub cmdReadByName_Click()
    Dim VarBool As Variant
    Dim VarInt8 As Byte
    Dim VarInt16 As Integer
    Dim VarInt32 As Long
    Dim VarReal32 As Single
    Dim VarReal64 As Double

    VarBool = TcClientSync.ReadVar(".PLCBoolVar")
    lblBoolean.Caption = VarBool

    VarInt8 = TcClientSync.ReadVar(".PLCSIntVar")
    lblInt8.Caption = VarInt8

    VarInt16 = TcClientSync.ReadVar(".PLCIntVar")
    lblInt16.Caption = VarInt16

    VarInt32 = TcClientSync.ReadVar(".PLCDIntVar")
    lblInt32.Caption = VarInt32

    VarReal32 = TcClientSync.ReadVar(".PLCRealVar")
    lblReal32.Caption = VarReal32

    VarReal64 = TcClientSync.ReadVar(".PLCLRealVar")
    lblReal64.Caption = VarReal64
End Sub

Private Sub cmdWrite_Click()
    Dim VarBool As Boolean
    Dim VarInt8 As Byte
    Dim VarInt16 As Integer
    Dim VarInt32 As Long
    Dim VarReal32 As Single
    Dim VarReal64 As Double

    If (txtBoolean.Text <> "") Then
        VarBool = CBool(txtBoolean.Text)
        Call TcClientSync.WriteBool(&H4020, 0, VarBool)
        txtBoolean.Text = VarBool
    End If

    If (txtInt8.Text <> "") Then
        VarInt8 = CByte(txtInt8.Text)
        Call TcClientSync.WriteInt8(&H4020, 2, VarInt8)
        txtInt8.Text = VarInt8
    End If

    If (txtInt16.Text <> "") Then
        VarInt16 = CInt(txtInt16.Text)
        Call TcClientSync.WriteInt16(&H4020, 4, VarInt16)
        txtInt16.Text = VarInt16
    End If

    If (txtInt32.Text <> "") Then
        VarInt32 = CLng(txtInt32.Text)
        Call TcClientSync.WriteInt32(&H4020, 6, VarInt32)
        txtInt32.Text = VarInt32
    End If

    If (txtReal32.Text <> "") Then
        VarReal32 = CSng(txtReal32.Text)
        Call TcClientSync.WriteReal32(&H4020, 10, VarReal32)
        txtReal32.Text = VarReal32
    End If

    If (txtReal64.Text <> "") Then
        VarReal64 = CDbl(txtReal64.Text)
        Call TcClientSync.WriteReal64(&H4020, 14, VarReal64)
        txtReal64.Text = VarReal64
    End If
End Sub

Private Sub cmdWriteByName_Click()
    Dim VarBool As Boolean
    Dim VarInt8 As Byte
    Dim VarInt16 As Integer
    Dim VarInt32 As Long
    Dim VarReal32 As Single
    Dim VarReal64 As Double

    If (txtBoolean.Text <> "") Then
        VarBool = CBool(txtBoolean.Text)
        Call TcClientSync.WriteVar(".PLCBoolVar", VarBool)
        txtBoolean.Text = VarBool
    End If

    If (txtInt8.Text <> "") Then
        VarInt8 = CByte(txtInt8.Text)
        Call TcClientSync.WriteVar(".PLCSIntVar", VarInt8)
        txtInt8.Text = VarInt8
    End If

    If (txtInt16.Text <> "") Then
        VarInt16 = CInt(txtInt16.Text)
        Call TcClientSync.WriteVar(".PLCIntVar", VarInt16)
        txtInt16.Text = VarInt16
    End If

    If (txtInt32.Text <> "") Then
        VarInt32 = CLng(txtInt32.Text)
        Call TcClientSync.WriteVar(".PLCDIntVar", VarInt32)
        txtInt32.Text = VarInt32
    End If

    If (txtReal32.Text <> "") Then
        VarReal32 = CSng(txtReal32.Text)
        Call TcClientSync.WriteVar(".PLCRealVar", VarReal32)
        txtReal32.Text = VarReal32
    End If

    If (txtReal64.Text <> "") Then
        VarReal64 = CDbl(txtReal64.Text)
        Call TcClientSync.WriteVar(".PLCLRealVar", VarReal64)
        txtReal64.Text = VarReal64
    End If
End Sub

Private Sub cmdReadState_Click()
    lblAdsState.Caption = TcClientSync.ReadAdsState()
End Sub

Private Sub cmdWriteState_Click()
    If (txtAdsState.Text <> "") Then
        If (txtAdsState.Text <> TcClientSync.ReadAdsState()) Then
            Call TcClientSync.WriteAdsState(txtAdsState.Text)
        End If
    End If
End Sub

SPS Programm

VAR_GLOBAL
    PLCBoolVar	AT %MX0.0: BOOL := TRUE;
    PLCSIntVar	AT %MB2	: USINT := 75;
    PLCIntVar	AT %MB4	: UINT := 12423;
    PLCDIntVar	AT %MB6	: UDINT := 43234532;
    PLCRealVar	AT %MB10	: REAL := 3.1415;
    PLCLRealVar	AT %MB14	: LREAL := 3.141592654;
END_VAR

Sprache / IDE | Beispielprogramm auspacken
Visual Basic 6 | ADS-Script-DLL Sample02.exe