我对 OOP 和 TwinCat 还很陌生,所以请耐心等待。我目前正在为一台小型机器开发软件,该软件将与 TF2000 HMI 结合使用。因为事件网格占用了很多工作,所以我想设置 TC3 EventLogger。我了解您如何创建警报等,并且我可以在 HMI 事件网格中显示它们。
它对于单个事件效果很好,但现在我想更进一步,添加每个功能块的错误。例如FB_TemperatureController可以报告过热,FB_Motor可以报告停止错误等等。
如何设置事件记录器,以便我可以从每个实例化的 FB 发送相同的错误?
我想到创建一个FB_FaultHandler:
FUNCTION_BLOCK FB_FaultHandler
VAR
fbEventLogger : FB_TcEventLogger;
aMessages : ARRAY [0..100] OF Fb_TcMessage;
aAlarms : ARRAY [0..100] OF Fb_TcAlarm;
END_VAR
METHOD init
VAR_INPUT
END_VAR
aAlarms[0].CreateEx(Tc_Events.AlarmEvents.Error_Overtemp, TRUE, 0);
aAlarms[1].CreateEx(Error2, TRUE, 0);
aAlarms[2].CreateEx(Error3, TRUE, 0);
aAlarms[3].CreateEx(Error4, TRUE, 0);
aAlarms[4].CreateEx(, TRUE, 0);
aAlarms[5].CreateEx(, TRUE, 0);
aAlarms[6].CreateEx(, TRUE, 0);
不过,我还是有一些不喜欢的地方:
METHOD setError
VAR_INPUT
nErrorId: INT;
bErrorActive: BOOL;
END_VAR
FB_FaultHandler
会将其放入 aAlarms[96]
我还没有真正在任何地方找到任何关于此的真实样本。我观看了网络研讨会,但老实说,它的描述非常糟糕。如果您提供任何帮助、意见或良好事件记录器的示例,我将不胜感激。
在互联网的帮助下,我的脑海中浮现出了一些想法。手头没有编译系统。但你可以做类似下面代码的事情。
必须有一个用于日志记录的基类(您的 FB_FaultHandler)。所有具有日志记录功能的类都可以从中派生。它对实例路径使用反射。我从来没有在 twincat 中使用过反射,因为我通常解决这类问题的方式有点不同。但我认为这是最通用的解决方案。
最终类的示例是 FB_MyClassesWithLoggingFunctionality。
MAIN 中还有一个初始化代码的小存根。您必须初始化并触发Info Class FB_SourceInfo 的设置。它在 FB_SourceInfo 中设置实例信息。这是一个可以移交给 CreateEx 方法的类,并且应该提供实例信息的来源。
在下面的 MAIN 示例中,源信息类似于 -project-.MAIN.fbClass
// -------------- Base class for all classes with logging
{attribute 'reflection'}
FUNCTION_BLOCK FB_FaultHandler
VAR
{attribute 'instance-path'}
{attribute 'noinit'}
sErrorSource : STRING; // make sure that this variable is large enough to hold the path
fbFaultInfo : FB_SourceInfo;
fbEventLogger : FB_TcEventLogger;
aMessages : ARRAY [0..100] OF Fb_TcMessage;
aAlarms : ARRAY [0..100] OF Fb_TcAlarm;
END_VAR
METHOD InitInfo
fbFaultInfo.InitInfo(sErrorSource);
// example: use faultInfo
aAlarms[0].CreateEx(Tc_Events.AlarmEvents.Error_Overtemp, TRUE, fbFaultInfo);
END_METHOD
METHOD logError
VAR_INPUT
errorId : INT;
END_VAR
END_METHOD
// Raise error
END_FUNCTION_BLOCK
// ------------ FB for source Info
FUNCTION_BLOCK FB_SourceInfo IMPLEMENTS I_TcSourceInfo
VAR
sSourceInfo : STRING
METHOD InitInfo
VAR_INPUT
source : STRING
END_VAR
sSourceInfo := source;
END_METHOD
END_FUNCTION_BLOCK
// ------------------ Final class that has logging functions
FUNCTION_BLOCK FB_MyClassesWithLoggingFunctionality EXTENDS FB_FaultHandler
METHOD DoSomething
VAR_INPUT
END_VAR
IF bError then
logError(id);
END_IF
END_METHOD
// Usage
PROGRAM MAIN
VAR
fbClass : FB_MyClassesWithLoggingFunctionality;
bInit : BOOL;
END_VAR
IF NOT bInit THEN
fbClass.InitInfo();
bInit := FALSE;
END_IF
END_PROGRAM
我建议查看属性“instance-path”的文档。这应该告诉您功能块的哪个实例是源(Motor1 或 Motor2)。您将在那里找到源代码示例。
https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529681547.html
我自己也曾为同样的问题而苦苦挣扎。以下是我的成功处理方法。
所有 FB_TcAlarm 都必须在类型系统中定义;据我所知,没有办法解决这个问题。但是,一旦您使用各种特定事件创建了 TcEventClass,您就可以根据需要多次实例化它们。
此外,当我“引发”FB_TcAlarms 时,我不需要指定 FB_TcEventLogger。我实例化 FB_TcEventLogger 并对其进行操作的唯一一次是当我想要使用该对象的方法/属性时;例如.ClearLoggedEvents、.ExportToCsv
我所做的是制作自己的 FB_Alarm,其中包含 FB_TcAlarm 对象。我将希望 FB_TcAlarm 使用的 TcEventEntry 定义(如类型系统中所定义)传递到该 FB 中。然后,我只有一个状态机,它在“引发”、“确认”和“清除”时遍历 FB_TcAlarm 的状态。我们通过 TE2000 EventGrid 控件进行确认。
在我的每个功能处理单元(电机、X-Y 龙门架等)中,我嵌入了 FB_Alarm 并传递了我想要引发的警报类型的正确输入。我还有一个 sIdentifier 字符串,它根据 EventLogger 手册中讨论的 {n} 参数功能自动放入事件的“显示文本”内。
因此,如果我的 X-Y Gantry 内的电机有警报,警报的路径和我推入的显示文本都将唯一标识警报的来源。
我确信这读起来就像垃圾,但我确实感受到了您对 Beckhoff 手册的模糊性的痛苦。