Ereignisgesteuertes Lesen
Sollen in einer Bedieneroberfläche kontinuierlich Werte aus der SPS oder NC angezeigt werden, so ist das Benutzen von AdsSyncReadReq() sehr aufwendig, da diese Funktion zyklisch aufgerufen werden muss. Durch das Definieren sogenannter Notifications (Meldungen) kann ein TwinCAT Server dazu veranlasst werden, Werte über ADS an ein anderes ADS-Gerät zu übertragen. Hierbei wird unterschieden, ob der TwinCAT Server die Werte zyklisch oder nur bei Veränderung übertragen soll.
Mit der Funktion AdsSyncAddDeviceNotificationReq() wird eine Notification erzeugt. Die Callback-Funktion wird anschließend selbständig von TwinCAT aufgerufen. Mit AdsSyncDelDeviceNotificationReq() wird die Notification wieder gelöscht. Da die Anzahl der Notifications begrenzt ist, sollten Sie in Ihrem Programm dafür sorgen, das nicht mehr benötigte Notifications gelöscht werden. Weitere Informationen finden Sie bei der Beschreibung zur Struktur AdsNotificationAttrib.
Das folgende Programm startet eine Notification auf dem Handle einer Variablen. Bei jeder Änderung der SPS-Variablen, wird die Callback-Funktion aufgerufen. Als Parameter enthält die Callback-Funktion unter anderem eine Variable vom Typ AdsNotificationHeader. In dieser Struktur sind alle notwendigen Informationen (Wert, Zeitstempel, ...) enthalten.
Download: sample08-c-ads-dll-eventdrivenreading.zip
Hinweis | |
Zeitintensive Aktionen oder ADS-Befehle Im Callback dürfen keine zeitintensiven Aktionen oder ADS-Befehle ausgeführt werden. |
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <winbase.h>
// ADS headers
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsApi.h"
using namespace std;
void _stdcall Callback(AmsAddr*, AdsNotificationHeader*, unsigned long);
void main()
{
long nErr, nPort;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
ULONG hNotification, hUser;
AdsNotificationAttrib adsNotificationAttrib;
char szVar []={"MAIN.PlcVar"};
// Open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
pAddr->port = 801;
// Set the attributes of the notification
adsNotificationAttrib.cbLength = 4;
adsNotificationAttrib.nTransMode = ADSTRANS_SERVERONCHA;
adsNotificationAttrib.nMaxDelay = 0;
adsNotificationAttrib.nCycleTime = 10000000; // Unit = 100ns, 1sec = 10000000
// Get variable handle
nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(hUser), &hUser, sizeof(szVar), szVar);
if (nErr) cerr << "Error: AdsSyncReadWriteReq: " << nErr << '\n';
// Initiate the transmission of the PLC-variable
nErr = AdsSyncAddDeviceNotificationReq( pAddr,
ADSIGRP_SYM_VALBYHND,
hUser,
&adsNotificationAttrib,
Callback,
hUser,
&hNotification);
if (nErr) cerr << "Error: AdsSyncAddDeviceNotificationReq: " << nErr << '\n';
cout.flush();
// Wait for user intraction (keystroke)
_getch();
// Finish the transmission of the PLC-variable
nErr = AdsSyncDelDeviceNotificationReq(pAddr, hNotification);
if (nErr) cerr << "Error: AdsSyncDelDeviceNotificationReq: " << nErr << '\n';
// Release the variable handle
nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(hUser), &hUser);
if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';
// Close the communication port
nErr = AdsPortClose();
if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';
}
// Callback-function
void __stdcall Callback(AmsAddr* pAddr, AdsNotificationHeader* pNotification, ULONG hUser)
{
int nIndex;
static ULONG nCount = 0;
SYSTEMTIME SystemTime, LocalTime;
FILETIME FileTime;
LARGE_INTEGER LargeInteger;
TIME_ZONE_INFORMATION TimeZoneInformation;
cout << ++nCount << ". Notification:\n";
// print (to screen)) the value of the variable
cout << "Value: " << *(ULONG *)pNotification->data << '\n';
cout << "Notification: " << pNotification->hNotification << '\n';
// Convert the timestamp into SYSTEMTIME
LargeInteger.QuadPart = pNotification->nTimeStamp;
FileTime.dwLowDateTime = (DWORD)LargeInteger.LowPart;
FileTime.dwHighDateTime = (DWORD)LargeInteger.HighPart;
FileTimeToSystemTime(&FileTime, &SystemTime);
// Convert the time value Zeit to local time
GetTimeZoneInformation(&TimeZoneInformation);
SystemTimeToTzSpecificLocalTime(&TimeZoneInformation, &SystemTime, &LocalTime);
// Print out the timestamp
cout << LocalTime.wHour << ":" << LocalTime.wMinute << ":" << LocalTime.wSecond << '.' << LocalTime.wMilliseconds;
// Print out the ADS-address of the sender
cout << "\nServerNetId: ";
for (nIndex = 0; nIndex < 6; nIndex++)
cout << (int)pAddr->netId.b[nIndex] << ".";
cout << " Port: " << pAddr->port << "\n\n";
cout.flush();
}