TwinCAT3应用——与高级语言(C#)ADS通讯

TC3与C#ADS通讯进行数据读写

本文章旨在说明TwinCAT3的ADS通讯应用,利用C#对倍福中常见数据类型(INT、BOOL、STRING、WSTRING、ARRAY、STRUCT等)变量进行读写操作。

1. TwinCAT ADS技术

(备注:此部分大家可以前往倍福虚拟学堂进行学习: https://tr.beckhoff.com.cn/course/view.php?id=150
在这里插入图片描述

  • ADS即(Automation Device Specification)自动化设备规范;
  • TwinCAT系统各模块均作为独立的设备;
  • 每个任务均存在一个服务模块,服务端或客户端;
  • 由Message Router统一交换数据。
  • 在这里插入图片描述

2. ADS通讯方式及命令参数

2.1 ADS通讯方式在这里插入图片描述
  • 异步通讯变量上限:550
  • 批量读取变量上限:500
  • 异步和批量读取需要通道支持
2.2 ADS命令参数

在这里插入图片描述

3. 程序实现

本例中采用按变量名方式进行读写调试。其具体实现方法如下:

step1 建立工程

建立c#的项目工程、Twincat3 项目工程,在c#中实现对Twincat3 中的变量进行读写。

step2 添加引用

在C#工程中引入 TwinCAT.Ads.dll 库文件(此文件可到BECKHOFF官网下载)
在这里插入图片描述

step3 前期工作

1)TC3变量创建

TYPE StructAxis :
STRUCT
 Triggle:         BOOL:=TRUE;
 Velocity:        LREAL:=200;
 //Acceleration:    LREAL;
 //Jrek:            LREAL;
 //Deceleration:    LREAL;
 //Done:            BOOL;
 //Busy:            BOOL;
 //Error:           BOOL;
 //ErrorID:         LREAL;
END_STRUCT
END_TYPE

PROGRAM MAIN
VAR
 //c# test
 Date_Int:         INT:=10;          
 Date_Bool:        BOOL:=FALSE;
 Date_Array:       ARRAY[0..2] OF INT;
 Date_Struct:      StructAxis;
 Date_string:      STRING:='Made by dashuaixiaoping';
 {attribute 'TcEncoding':='UTF-8'}
 Date_wstring:     STRING:=wsLiteral_TO_UTF8("大帅小平制作"); 
END_VAR

2)设计Form
本例添加以下控件进行调试:(比较粗糙,请忽略)
在这里插入图片描述
3)创建Adsclient

public TcAdsClient _client = new TcAdsClient();

4)连接PLC

_client.Connect(851);

5)创建句柄

 public int _myIntHand = 0;
 public int _myBoolHand = 0;
 public int _myStringHand = 0;
 public int _myWstringHand = 0;
 public int _myArrayHand = 0;
 public int _myStructHand = 0;

 _myIntHand = _client.CreateVariableHandle("MAIN.Date_Int");
 _myBoolHand = _client.CreateVariableHandle("MAIN.Date_Bool");
 _myStringHand = _client.CreateVariableHandle("Main.Date_string");
 _myWstringHand = _client.CreateVariableHandle("Main.Date_wstring");
 _myArrayHand = _client.CreateVariableHandle("Main.Date_Array");
 _myStructHand = _client.CreateVariableHandle("Main.Date_Struct");

6)释放句柄

 //释放句柄
 _client.DeleteVariableHandle(_myIntHand);
 _client.DeleteVariableHandle(_myBoolHand);
_client.DeleteVariableHandle(_myStringHand);
_client.DeleteVariableHandle(_myWstringHand);
 _client.DeleteVariableHandle(_myArrayHand);
_client.DeleteVariableHandle(_myStructHand);
step4 开始读写

TwinCAT.Ads.dll 库文件中提供了多个重载读写方法,本例中主要运用演示了:

public object ReadAny(int variableHandle, Type type, int[] args);
public int Read(int variableHandle, AdsStream dataStream, int offset, int length);
public void WriteAny(int variableHandle, object value, int[] args);
public void Write(int variableHandle, AdsStream dataStream, int offset, int length);

1)ReadAny/WriteAny 实现

//读
//INT
rInttb.Text = _client.ReadAny(_myIntHand, typeof(short)).ToString();
//BOOL
rBooltb.Text = _client.ReadAny(_myBoolHand, typeof(bool)).ToString();
//STRING
rStrtb.Text = _client.ReadAny(_myStringHand, typeof(string), new int[] { 16 }).ToString();
//WSTRING
Encoding defaultEncoding = Encoding.Default;           //当前系统默认用"BGK"进行解码与编码
Encoding utf8Encoding = Encoding.UTF8;
string temStr = _client.ReadAny(_myWstringHand, typeof(string), new int[] { 32 }).ToString();
byte[] tempBytes = defaultEncoding.GetBytes(temStr);    //解码:将字符、符号等转换为二进制机器语言
string str = utf8Encoding.GetString(tempBytes);         //编码:将二进制机器语言转换为字符、符号等
rWstrtb.Text = str;
//ARRAY
short[] tempArr = (short[])_client.ReadAny(_myArrayHand, typeof(short[]), new int[] { 4 });
rArr0tb.Text = tempArr[0].ToString();
rArr1tb.Text = tempArr[1].ToString();
rArr2tb.Text = tempArr[2].ToString();
//STRUCT
 Mystruct struct1 = (Mystruct)_client.ReadAny(_myStructHand, typeof(Mystruct));
rStruct1tb.Text = struct1.Triggle.ToString();
rStruct2tb.Text = struct1.Velocity.ToString();

//写
//INT
_client.WriteAny(_myIntHand, Convert.ToInt16(wInttb.Text));
//BOOL
_client.WriteAny(_myBoolHand, Convert.ToBoolean(wBooltb.Text));
//STRING
_client.WriteAny(_myStringHand, wStrtb.Text, new int[] { 16 });
//WSTRING
string str = wWstrtb.Text;
byte[] tempBytes = Encoding.UTF8.GetBytes(str);
_client.WriteAny(_myWstringHand,tempBytes);
//ARRAY
short[] temArr = new short[3];
temArr[0] = short.Parse(wArr0tb.Text);
temArr[1] = short.Parse(wArr1tb.Text);
temArr[2] = short.Parse(wArr2tb.Text);
_client.WriteAny(_myArrayHand, temArr);
//STRUCT
Mystruct tempStruct = new Mystruct();
tempStruct.Triggle = Boolean.Parse(wStruct1tb.Text);
tempStruct.Velocity = double.Parse(wStruct2tb.Text);
_client.WriteAny(_myStructHand, tempStruct);

2)Read/Write 实现
这里用到stream类,其具体含义与用法可参考博文:C# 温故而知新:Stream篇(—)

//读
AdsStream rStream = new AdsStream(100);
AdsBinaryReader reader = new AdsBinaryReader(rStream);
//INT
 _client.Read(_myIntHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);  //初始化流的当前位置( 等效于stream.Position = 0;)
rInttb.Text = reader.ReadInt16().ToString(); //读取两位数,同时position后移两位(ReadInt16的作用)
//BOOL
_client.Read(_myBoolHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
rBooltb.Text = reader.ReadBoolean().ToString();
//ARRAY
_client.Read(_myArrayHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
rArr0tb.Text = reader.ReadInt16().ToString();
rArr1tb.Text = reader.ReadInt16().ToString();
rArr2tb.Text = reader.ReadInt16().ToString();
//STRUCT
_client.Read(_myStructHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
rStruct1tb.Text = reader.ReadBoolean().ToString();
//因为struct中每个成员的数据类型不一样,
//系统默认将读到的每个成员以成员中长度最长的位数存储在stream中
//如此处的结构体中成员长度最长的数据类型为Double(对于倍福中的LREAL),占8位
//所以需将stream向后移动8位
rStream.Seek(8, System.IO.SeekOrigin.Begin);
rStruct2tb.Text = reader.ReadDouble().ToString();
//STRING
_client.Read(_myStringHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
rStrtb.Text = reader.ReadPlcString(81, Encoding.Default);
 //WSTRING
_client.Read(_myWstringHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
//在倍福那边将WSTRING定义成UTF8格式的STRING,C#中以byte[]形式读取,然后以UTF8编码
rWstrtb.Text = Encoding.UTF8.GetString(reader.ReadBytes(81));

//写
AdsStream wStream = new AdsStream(100);
AdsBinaryWriter writer = new AdsBinaryWriter(wStream);
//INT
 wStream.Seek(0, System.IO.SeekOrigin.Begin);
writer.Write(short.Parse(wInttb.Text));
_client.Write(_myIntHand, wStream, 0, 2);
//BOOL
wStream.Seek(0, System.IO.SeekOrigin.Begin);
writer.Write(Boolean.Parse(wBooltb.Text));
 _client.Write(_myBoolHand, wStream, 0, 1);
//ARRAY
wStream.Seek(0, System.IO.SeekOrigin.Begin);
writer.Write(Int16.Parse(wArr0tb.Text));
writer.Write(Int16.Parse(wArr1tb.Text));
writer.Write(Int16.Parse(wArr2tb.Text));
_client.Write(_myArrayHand, wStream, 0, 6);
//STRUCT
wStream.Seek(0, System.IO.SeekOrigin.Begin);
writer.Write(Boolean.Parse(wStruct1tb.Text));
byte[] tempBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0 };  //占位,使得BOOL和Double都占位8个
writer.Write(tempBytes);
writer.Write(Double.Parse(wStruct2tb.Text));
_client.Write(_myStructHand, wStream, 0, 16);
//STRING
wStream.Seek(0, System.IO.SeekOrigin.Begin);
byte[] tempBytes1 = Encoding.Default.GetBytes(wStrtb.Text);
writer.Write(tempBytes1);
_client.Write(_myStringHand, wStream, 0, 81);
//WSTRING
wStream.Seek(0, System.IO.SeekOrigin.Begin);
byte[] tempBytes2 = Encoding.UTF8.GetBytes(wWstrtb.Text);
writer.Write(tempBytes2);
_client.Write(_myWstringHand, wStream, 0, 81);

4. 注意事项

  • WSTRING的读写
    WSTRING是TC3中的变量,主要用于存放中文字符,其详细介绍请参考博文:
    BECKHOFF TwinCAT3 常见问题2

    值得注意的是,如果在C#中直接将WSTING通过string字符串的形式进行读写,会存在乱码问题,此问题的具体解决方案如下:

    step1:
    在TC3中将带中文的字符的变量命名为UTF-8编码规则下的STRING型;如:

     {attribute 'TcEncoding':='UTF-8'}
     Date_wstring:     STRING:=wsLiteral_TO_UTF8("大帅小平制作");

{attribute ‘TcEncoding’:=‘UTF-8’} 的用法参照:https://infosys.beckhoff.com/english.php?content=…/content/1033/tc3_plc_intro/5873680907.html&id=6249601214176997827
如需深入了解Unicode/UTF-8/UTF-16等解码编码问题可参考博文:
从字节理解Unicode(UTF8/UTF16)

step2:
在C#中接收string,然后用UTF-8进行编码,如下:

//Write方法
AdsStream rStream = new AdsStream(100);
AdsBinaryReader reader = new AdsBinaryReader(rStream);
_client.Read(_myWstringHand, rStream);
rStream.Seek(0, System.IO.SeekOrigin.Begin);
//在倍福那边将WSTRING定义成UTF8格式的STRING,C#中以byte[]形式读取,然后以UTF8编码
rWstrtb.Text = Encoding.UTF8.GetString(reader.ReadBytes(81));

关于此处,本人也尝试用WriteAny进行实现,但是总会遇到编码解码不完全,或者写入TC3时覆盖不完全等问题,所以弃用了WriteAny方法,如有读者利用WriteAny测试成功,还请留言指点(抱拳)。

  • TC3与C#变量类型对应关系
    在这里插入图片描述

5. 完整工程项目文件

链接:https://pan.baidu.com/s/12ly_fzMBRk7I5DQUUQTV6Q
提取码:aihx

后记:笔者才疏学浅,如有错误,望读者指正。

  • 10
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Twincat3 ADS通讯是Beckhoff公司开发的一种用于实时数据传输和控制的通讯协议。ADS代表"Automation Device Specification",它提供了一种高效、可靠的方式,使得不同的设备可以在实时环境中进行通信。 Twincat3 ADS通讯通过TCP/IP协议实现,可以应用于不同的物理层和网络拓扑结构。它支持点对点和多点到多点的通信模式,并且具有低延迟、高带宽的特点。 ADS通讯的基本构成是Client和Server,其中Client可以是Twincat PLC、HMI或其他应用程序,而Server则是承担实际数据处理和传输任务的设备或程序。Client和Server之间通过AdsLib库进行通信,通过发送请求和接收响应来进行数据传输。 Twincat3 ADS通讯具有灵活的数据读写方式。Client可以通过ADS API发送请求,Server则根据请求进行数据读取或写入,并将结果返回给Client。此外,ADS通讯还支持周期性数据传输,可以实现实时数据的更新和同步。 使用Twincat3 ADS通讯可以实现高效的实时控制和监控系统。它可以方便地与各种设备和系统进行接口对接,同时还提供了强大的调试和诊断功能。通过ADS通讯,用户可以实时获取设备状态、控制操作和传输数据,从而提高生产效率和质量。 总之,Twincat3 ADS通讯是一种可靠、高效的实时通讯协议,通过它实现的系统可以实现快速、准确的数据传输和控制。它在工业自动化和控制领域有着广泛的应用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值