使用c#从TwinCAT功能块读取属性



我们使用C#应用程序通过TwinCAT ADS v.3从Beckhoff PLC读取变量。如果我们试图使用相同的代码来读取属性,则代码会失败并出现异常。

FUNCTION_BLOCK FB_Sample
VAR
SomeVariable : INT;
END_VAR
PROPERTY SomeProp : INT // declared in a separate file
// Code used to read variable (symbol)
var handle = client.CreateVariableHandle("sampleProgram.Source.SomeVariable");
var result = client.ReadAny(handle, typeof(int));
client.DeleteVariableHandle(handle);
// Adapted code used to read property (not a symbol)
var handle = client.CreateVariableHandle("sampleProgram.Source.SomeProp"); // This fails
var result = client.ReadAny(handle, typeof(int));
client.DeleteVariableHandle(handle);

当尝试使用上面的代码创建变量句柄时,我们会收到TwinCAT.Ads.AdsErrorException: 'Ads-Error 0x710 : Symbol could not be found.'

因为我们知道METHOD必须用{attribute 'TcRpcEnable'}标记,所以它可以用以下代码调用:

client.InvokeRpcMethod("{symbolPath}", "{methodName}", {parameters} });

我们也尝试在属性上使用属性{attribute 'TcRpcEnable'}。使用TcAdsClient.CreateSymbolLoader并在所有可用符号上循环,我们发现该属性的getter/setter随后被标记为rpc方法。

Console.WriteLine($"Name: {rpcMethod.Name}; Parameters.Count: {rpcMethod.Parameters.Count}; ReturnType: {rpcMethod.ReturnType};");
RpcMethods: 2
Name: __setSomeProp; Parameters.Count: 1; ReturnType: ;
Name: __getSomeProp; Parameters.Count: 0; ReturnType: INT;

但是,尽管我们可以尝试,我们不能调用rpc方法:

var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "__getSomeProp", Array.Empty<object>());
// Throws: TwinCAT.Ads.AdsErrorException: 'Ads-Error 0x710 : Symbol could not be found.'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "__get{SomeProp}", Array.Empty<object>());
// Throws: TwinCAT.Ads.RpcMethodNotSupportedException: 'The RPC method '__get{SomeProp}' is not supported on symbol 'sampleProgram.Source!'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "get{SomeProp}", Array.Empty<object>());
// Throws: TwinCAT.Ads.RpcMethodNotSupportedException: 'The RPC method 'get{SomeProp}' is not supported on symbol 'sampleProgram.Source!'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source.SomeProp", "get", Array.Empty<object>());
// Throws: System.ArgumentNullException: 'Value cannot be null.
//         Parameter name: symbol'

关于如何读取/写入定义为函数块属性的变量,有什么建议吗?

定义新属性时,会自动为该属性创建get集合

您通常使用属性来读取或写入功能块VAR部分中的变量。

VAR部分中的所有变量都是私有,因此需要属性从功能块外部访问这些VAR。

与方法不同,理论上的属性不应该进行任何复杂的计算或运行任何逻辑。

我想指出的一点是,不需要也不应该通过ADS调用属性。无论如何,您都可以通过ADS访问所有私有VAR,因此首先不需要通过ADS调用属性。

@编辑

我仍然认为属性不应该包含任何逻辑,因此没有必要通过ADS调用它们

然而,总有例外。

请注意,根据Beckhoff文档,只有简单的数据类型和指针才能工作,而不是结构。此外,";在紧凑的运行时系统中功能监视是不可能的

这里是我在实验{attribute‘monitoring’:=‘call’}属性后的工作示例

在Twincat:中

{attribute 'monitoring' := 'call'}
PROPERTY RemoteCall : INT
GET:
RemoteCall := buffer;
SET:
buffer := buffer + RemoteCall;

在C#中

class Program
{
static TcAdsClient tcClient;
static void Main(string[] args)
{
tcClient = new TcAdsClient();
tcClient.Connect(851);

AdsStream dataStream = new AdsStream(2);
int iHandle = tcClient.CreateVariableHandle("MAIN.fbTest.RemoteCall");
tcClient.Read(iHandle, dataStream);
Console.WriteLine("Remote Var before property call: " + BitConverter.ToInt16(dataStream.ToArray(), 0));
tcClient.WriteAny(iHandle,Convert.ToInt16(2));
tcClient.Read(iHandle, dataStream);
Console.WriteLine("Remote Var after property call: " + BitConverter.ToInt16(dataStream.ToArray(), 0));
Console.WriteLine();
Console.ReadLine();
}
}

根据Stefan Hennecken在他的博客上的说法,该房产必须用一个pragma进行装饰才能启用:

{attribute ‘monitoring’ := ‘call’}
PROPERTY PUBLIC nProp : BYTE

然后可以使用以下代码示例进行读取/写入:

using (AdsClient client = new AdsClient())
{
byte valuePlc;
client.Connect(AmsNetId.Local, 851);
valuePlc = (byte)client.ReadValue(“MAIN.fbFoo.nProp”, typeof(byte));
client.WriteValue(“MAIN.fbFoo.nProp”, ++valuePlc);
}

最新更新