Twincat 3 Ads Notification Handler Event Handler - Ereignisgesteuertes Lesen

Neuling2014

Level-1
Beiträge
20
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

in dem InfoSystem von Beckhoff existiert ein Beispiel über das ereignisgesteuerte Lesen von Beckhoff Variablen.
http://infosys.beckhoff.com/index.p...es_net/html/twincat.ads.sample03.htm&id=15632

Quellcode heruntergeladen ausprobiert. Super!! Es läuft.
Nun habe ich versucht diesen Quellcode auf eine Consolen Application mit C# aufzusetzen.
Ohne Erfolg :-( Das Programm läuft durch, aber es springt nicht in die Event Methoden.

Hat jemand damit schon Erfahrungen gesammelt?

Danke und Grüße
Neuling2014

PS: Hier ist der richtige Link
http://infosys.beckhoff.com/index.p...es_net/html/twincat.ads.sample03.htm&id=15632
Falsch kopiert :confused:
 
Zuletzt bearbeitet:
Hallo!

Die Methoden aus der TcAdsDll.dll haben eigentlich nichts mit der Oberfläche bzw. der Umgebung zu tun.
Ob Konsole oder Windows Form....sollte da keinen Unterschied machen.
 
Hallo,
sieht dein Script denn genauso aus wie in dem verlinkten Beispiel ?
Hast du im Form_Load-Script den Eventhandler zugewiesen ?
Ansonsten poste das doch mal bitte dein Script ...

Gruß
Larry
 
Hallo Larry,

das Projekt besteht aktuell nur aus der Program.cs.
Die wie folgt aussieht:

Code:
namespace ConsoleTest
{
    class Program
    {

        private TcAdsClient _tcClient = null;
        private AdsStream _adsStream = null;
        private BinaryReader _binRead = null;
        private int _notificationHandle = 0;


        static void Main (string[] args)
        {
            Load();
        }

       
        private void Load()
        {
            try
            {
                _tcClient = new TcAdsClient();

                /* connect the client to the local PLC */
                _tcClient.Connect(851);

                _adsStream = new AdsStream(2);                /* stream storing the ADS state of the PLC */
                _binRead = new BinaryReader(_adsStream);    /* reader to read the state data */

                /* register callback to react on state changes of the local AMS router */
                _tcClient.AmsRouterNotification +=
                                        new AmsRouterNotificationEventHandler(AmsRouterNotificationCallback);


                _notificationHandle = _tcClient.AddDeviceNotification(
                                            (int)AdsReservedIndexGroups.DeviceData,    /* index group of the device state*/
                                            (int)AdsReservedIndexOffsets.DeviceDataAdsState, /*index offsset of the device state */
                                            _adsStream,    /* stream to store the state */
                                            AdsTransMode.OnChange,    /* transfer mode: transmit ste on change */
                                            0,    /* transmit changes immediately */
                                            0,
                                            null);

                /* register callback to react on state changes of the local PLC */
                _tcClient.AdsNotification += new AdsNotificationEventHandler(OnAdsNotification);
            }
            catch (AdsErrorException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /* callback function called on state changes of the PLC */
        void OnAdsNotification(object sender, AdsNotificationEventArgs e)
        {
            if (e.NotificationHandle == _notificationHandle)
            {
                AdsState plcState = (AdsState)_binRead.ReadInt16(); /* state was written to the stream */
                Console.WriteLine(plcState.ToString());
            }
        }

        /* callback function called on state changes of the local AMS router */
        void AmsRouterNotificationCallback(object sender, AmsRouterNotificationEventArgs e)
        {
            Console.WriteLine(e.State.ToString());
        }

        //private void _exitButton_Click(object sender, EventArgs e)
        //{
        //    this.Close();
        //}

        //private void Close ()
        //{
        //    try
        //    {
                
        //        if(_notificationHandle != null) _tcClient.DeleteDeviceNotification(_notificationHandle);
        //        _tcClient.Dispose();
        //    }
        //    catch(AdsErrorException ex)
        //    {
        //        MessageBox.Show(ex.Message);
        //    }
        //}
    }
}
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du musst dein Programm am laufen halten. Entweder mit einer Schleife (while (!Abbruchbedingung) {}) oder mit einem Console.ReadKey() oder Console.ReadLine() am Ende.
Obwohl ich mir bei den letzten beiden nicht sicher bin, ob die nicht andere Events blocken während sie auf die Tasten warten. Versuch macht Kluch!
 
Hmm, beide Varianten funktionieren nicht while und ReadKey()

Code:
namespace TestNotification
{
    class Program
    {
        static void Main (string[] args)
        {

            Twincat test = new Twincat();
            test.Load();
            DateTime now = DateTime.Now;
            DateTime future = now.AddMinutes(1);

            while (now < future)
            {
                now = DateTime.Now;
            }
        }
    }

    public class Twincat
    {
        private TcAdsClient _tcClient = null;
        private AdsStream _adsStream = null;
        private BinaryReader _binRead = null;
        private int _notificationHandle = 0;
       
        public void Load()
        {
            try
            {
                _tcClient = new TcAdsClient();

                /* connect the client to the local PLC */
                _tcClient.Connect(851);

                _adsStream = new AdsStream(2);                /* stream storing the ADS state of the PLC */
                _binRead = new BinaryReader(_adsStream);    /* reader to read the state data */

                /* register callback to react on state changes of the local AMS router */
                _tcClient.AmsRouterNotification +=
                                        new AmsRouterNotificationEventHandler(AmsRouterNotificationCallback);


                _notificationHandle = _tcClient.AddDeviceNotification(
                                            (int)AdsReservedIndexGroups.DeviceData,    /* index group of the device state*/
                                            (int)AdsReservedIndexOffsets.DeviceDataAdsState, /*index offsset of the device state */
                                            _adsStream,    /* stream to store the state */
                                            AdsTransMode.OnChange,    /* transfer mode: transmit ste on change */
                                            0,    /* transmit changes immediately */
                                            0,
                                            null);

                /* register callback to react on state changes of the local PLC */
                _tcClient.AdsNotification += new AdsNotificationEventHandler(OnAdsNotification);
            }
            catch (AdsErrorException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /* callback function called on state changes of the PLC */
        void OnAdsNotification(object sender, AdsNotificationEventArgs e)
        {
            if (e.NotificationHandle == _notificationHandle)
            {
                AdsState plcState = (AdsState)_binRead.ReadInt16(); /* state was written to the stream */
                Console.WriteLine(plcState.ToString());
            }
        }

        /* callback function called on state changes of the local AMS router */
        void AmsRouterNotificationCallback(object sender, AmsRouterNotificationEventArgs e)
        {
            Console.WriteLine(e.State.ToString());
        }

        //private void _exitButton_Click(object sender, EventArgs e)
        //{
        //    this.Close();
        //}

        //private void Close ()
        //{
        //    try
        //    {
                
        //        if(_notificationHandle != null) _tcClient.DeleteDeviceNotification(_notificationHandle);
        //        _tcClient.Dispose();
        //    }
        //    catch(AdsErrorException ex)
        //    {
        //        MessageBox.Show(ex.Message);
        //    }
        //}
    }
}
 
@MasterOhh:
Die Form selbst hält schon alles offen. Solange du die nicht schliesst und disposed passiert dem Prozess selbst erstmal nichts.

@TE:
In der OnNotification-Methode lasst doch mal das IF weg und führe den Code darin absolut aus - eventuell auch mal einen Breakpoint setzen um zu sehen ob die Methode aufgerufen wird und von wem (Sender).
Also etwa so :
Code:
      void OnAdsNotification(object sender, AdsNotificationEventArgs e)
        {
                AdsState plcState = (AdsState)_binRead.ReadInt16(); /* state was written to the stream */
                Console.WriteLine(plcState.ToString());
           }

Gruß
Larry
 
Für mich ist das hier auch ein wenig Rätselraten.
Was ist mir dem hier :
Code:
               _notificationHandle = _tcClient.AddDeviceNotification(
                                            (int)AdsReservedIndexGroups.DeviceData,    /* index group of the device state*/
                                            (int)AdsReservedIndexOffsets.DeviceDataAdsState, /*index offsset of the device state */
                                            _adsStream,    /* stream to store the state */
                                            AdsTransMode.OnChange,    /* transfer mode: transmit ste on change */
                                            0,    /* transmit changes immediately */
                                            0,
                                           [COLOR=#ff0000] null[/COLOR]);
In dem Beispiel wird dort der Datentyp übergeben und bei dir NULL - hast du das mal versucht ?
 
Was ist, wenn du mal eine Variable deines Programms abfragst ?
Code:
                            hConnect[0] = tcClient.AddDeviceNotification([COLOR=#ff0000]"MAIN.boolVal"[/COLOR],dataStream,0,1,
                                        AdsTransMode.OnChange,100,0,[COLOR=#ff0000]tbBool[/COLOR]);
... idealerweise sollte die eine Art Blink-Merker sein ...
 
Hallo,
dann müssen wir ggf. etwas weiter unten anfassen ...
In dem Beckhoff-Beispiel wird das Ganze ja auf eine Form bezogen.
Hier erfolgt die Initialisierung in der überschriebenen Methode, die beim Laden der Form automatisch aufgerufen wird.
Du hast dir ja eine eigene Klasse erstellt (was ja auch nicht verwerflich ist). Zu welchem Zeitpunkt und wie wird diese Klasse denn instanziert, und die beinhalteten Methoden aufgerufen (z.B. die Load-Methode) ?
Hast du darin schon mal einen Breakpoint gesetzt ?
Wenn das richtig aufgerufen wird, sind denn deine Objekte alle sinnvoll und auch sinnvoll zugewiesen ?

Prinzipiell würde ich dazu tendieren, dir vorzuschlagen, das Beckhoff-Beispiel genau identisch zu erstellen und wenn das funktioniert, dieses abzuwandeln. Du hast in deinem Konstrukt nach meiner Meinung zu viele Unbekannte drin (ich würde so, wie beschrieben, vorgehen um weiter zu kommen).

Gruß
Larry
 
Das Problem liegt nicht an der SPS oder an ADS Funktionen.
sondern schlicht und ergreifend daran das dein C# Programm
also Consolenprogramm den Message Loop nicht abarbeitet.
Die einfachst Methode um dies zu tun,ist Application.Run() welche auch jede Winformsanwendung nutzt.
D.h. für Dich.
Twincat test = new Twincat();
test.Load();
Application.Run();
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo soma,

das war des Pudels Kern :)
mit Application.Run(); springt er automatisch in die Notification Methode!

D.h. ich kann diese Twincat ADS Klasse nicht in einer .NET Library Class aufrufen ...
Sehr ärgerlich. Oder kennst du da auch einen Trick?

Grüße
 
Hallo,
das das Problem so weit unten liegt hatte ich nun nicht vermutet - man braucht ja eigentlich immer eine Anzeige - sogar und vor Allem zum Testen ...

Aber natürlich kannst du das in eine Bibliothek einbauen. Du baust dir doch darin eine Methode (oder mehrere) oder ggf. sogar eine Komponente oder ein Control, dass schlußendlich an einer Form (z.B.) laufen würden - oder in einem Thread. Es muss am Ende (in der Applikation) nur jemanden geben, der hin und wieder das Application.DoEvents anstößt ...

Gruß
Larry
 
Hallo,

kannst du mir ein Beispiel zeigen/schreiben, in dem das ganze in einem Thread verpackt ist?
Ich wüßte jetzt nicht, wie ich das ganze einbauen sollte.

Danke und Grüße
Neuling2014
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nein ... da ich nicht weiß, welche der Klassen Thread-fest sind (also wo du ggf. mit Invoke arbeiten mußt).
Du kannst aber eine zyklische Abfrage auch relativ einfach über die Verwendung eines Timers realisieren. Dann hast du es wieder im Haupt-Thread und arbeitest auch von daher mit Events.

Gruß
Larry
 
Die Idee mit dem Timer hatte ich auch schon.
Das hatte in dem Consolen Programm eingebaut. Aber das hatte nicht den gewünschten Effekt.
Die zyklische Abfrage wollte ich eigentlich vermeiden.
Hintergrund: Die Notification geht auf eine Beckhoff Variable und wenn diese sich ändern, erfolgt eine Abarbeitung im .NET Code.
Eine zyklische Abfrage würde beeinhalten einen eigenen Thread für diese Abfrage aufzusetzen. Was ich eigentlich vermeiden wollte.
 
Zurück
Oben