ADS In C#

ADS in C#


  • 包: Beckhoff.TwinCAT.Ads[4.4.4],可以直接使用NuGet下载安装
  • 示例

PLC 结构体定义

TYPE S_Cmd :
STRUCT
	done: BOOL;
	iAttr: INT;
END_STRUCT
END_TYPE

PLC 变量声明

lrTest: LREAL:=1.3;
iTest: INT:=2;
sTestId: STRING:= 'hello';
sCmd: S_Cmd;
arrTests: ARRAY[1..32] OF INT:=[1,2,3,4,28(3)];
fbTrigITests: TON;
fbTrigLrTests: TON;

PLC 任务主程序(为了触发Notification,这里做了些定时自增操作)

fbTrigITests(IN:= NOT fbTrigITests.Q, PT:= T#1S, Q=> , ET=> );
IF fbTrigITests.Q THEN
	iTest := iTest + 1;
END_IF

fbTrigLrTests(IN:= NOT fbTrigLrTests.Q, PT:= T#3S, Q=> , ET=> );
IF fbTrigLrTests.Q THEN
	lrTest := lrTest+ 1;
END_IF

上位机C#主程序

using System;
using System.Collections;
using System.IO;
using TwinCAT.Ads;

namespace TestA
{
    class Program
    {
        static ArrayList notifyHdls = new ArrayList();
        static AdsStream dataStream = new AdsStream(16);
        static BinaryReader binRead = new BinaryReader(dataStream, System.Text.Encoding.ASCII);

        static void Main(string[] args)
        {
            TcAdsClient client = new TcAdsClient();
            client.Connect("192.168.0.112.1.1", 851); //建立ADS通信连接

            string varName = "MAIN.iTest";
            string varNameLr = "MAIN.lrTest";

            //根据变量名读取
            var val = (Int16)client.ReadSymbol(varName, typeof(Int16), true);
            Console.WriteLine($"MAIN.iTest: {val}");

            //根据变量句柄读取
            var varHdl = client.CreateVariableHandle(varName);
            val = (Int16)client.ReadAny(varHdl, typeof(Int16));

            var varInfo = client.ReadSymbolInfo(varName); //获取变量信息
            Console.WriteLine($"group: {varInfo.IndexGroup},offset: {varInfo.IndexOffset}");

            //根据变量Group+Offset通过流读取
            var adsStream = new AdsStream(sizeof(Int16));
            client.Read((UInt32)varInfo.IndexGroup, (UInt32)varInfo.IndexOffset, adsStream);
            BinaryReader binReader = new BinaryReader(adsStream);
            Console.WriteLine($"-MAIN.iTest: {binReader.ReadInt16()}");

            //根据变量名读取字符串
            string sVal = client.ReadSymbol("MAIN.sTestId", typeof(string), true).ToString();
            Console.WriteLine($"MAIN.sTestId:{sVal}");

            //根据变量名读取数组
            Int16[] arrTests = (Int16[])client.ReadSymbol("MAIN.arrTests", typeof(Int16[]), true);
            Console.WriteLine($"MAIN.arrTests:{string.Join("-", arrTests)}");

            //根据变量名读取结构体
            Cmd c = (Cmd)client.ReadSymbol("MAIN.sCmd", typeof(Cmd), true);
            Console.WriteLine($"MAIN.sCmd: {c.done},{c.iLastCaller},{c.udExeCnt}");

            //根据变量名写入
            client.WriteSymbol(varName, 100, true);

            //根据变量句柄写入
            client.WriteAny(varHdl, (Int16)200);

            //根据句柄通过流写入
            var adsStreamW = new AdsStream(sizeof(Int16));
            BinaryWriter binWriter = new BinaryWriter(adsStreamW);
            binWriter.Write((Int16)3);
            client.Write(varHdl, adsStreamW);

            //根据变量名写入字符串
            client.WriteSymbol("MAIN.sTestId", "ok", true);

            //根据变量名写入数组,会覆盖整个数组
            Int16[] arrTestsW = new Int16[] { 9, 8, 7 };
            client.WriteSymbol("MAIN.arrTests", arrTestsW, true);

            //根据变量名写入结构体
            Cmd cw = new Cmd();
            cw.done = true;
            cw.iLastCaller = 100;
            client.WriteSymbol("MAIN.sCmd", cw, true);

            //事件驱动读取
            notifyHdls.Add(client.AddDeviceNotification(varName, dataStream, AdsTransMode.OnChange, 500, 0, varName));
            notifyHdls.Add(client.AddDeviceNotification(varNameLr, dataStream, AdsTransMode.OnChange, 500, 0, varNameLr));
            client.AdsNotification += new AdsNotificationEventHandler(AdsNotificationHandler);

            //多线程版本
            //notifyHdls.Add(client.AddDeviceNotificationEx(varName, AdsTransMode.OnChange, 500, 0, varName, typeof(Int16)));
            //notifyHdls.Add(client.AddDeviceNotificationEx(varNameLr, AdsTransMode.OnChange, 500, 0, varNameLr, typeof(Double)));
            //client.AdsNotificationEx += new AdsNotificationExEventHandler(AdsNotificationExHandler);

            Console.ReadLine();
            foreach(int hdl in notifyHdls)
            {
                client.DeleteDeviceNotification(hdl);
            }
            client.DeleteVariableHandle(varHdl);
            notifyHdls.Clear();
            client.Close();
        }

        static void AdsNotificationHandler(object sender, AdsNotificationEventArgs e)
        {
            DateTime time = DateTime.FromFileTime(e.TimeStamp);
            e.DataStream.Position = e.Offset;

            if (e.NotificationHandle == (int)notifyHdls[0])
                Console.WriteLine(binRead.ReadInt16().ToString() + e.UserData);
            else if (e.NotificationHandle == (int)notifyHdls[1])
                Console.WriteLine(binRead.ReadDouble().ToString() + e.UserData);
            else
                ;
        }

        static void AdsNotificationExHandler(object sender, AdsNotificationExEventArgs e)
        {
            string userData = (string)e.UserData;
            Type type = e.Value.GetType();
            Console.WriteLine($"TransId: {e.UserData}, {e.Value}");
            
            switch (userData) {
                case "MAIN.iTest":
                    //todo
                    break;
                case "MAIN.lrTest":
                    //todo
                    break;
                default:
                    break;
            }
        }
    }
}

对应PLC中S_Cmd,上位机中需要定义如下结构体:


namespace TestA
{
    public struct Cmd
    {
        public bool done;
        public short iAttr;
    }
}

你可能感兴趣的:(C#,自动化,工控)