处理模拟输入卡的 TwinCAT 错误

问题描述 投票:0回答:1

我想知道在使用模拟输入卡(例如带有 TwinCAT 的热电偶输入卡)时应采用哪些最佳实践。我具体感兴趣的是:

  • 为多个输入声明变量的正确方法
  • 将所述变量链接到输入通道的正确方法
  • 通过使用“状态”一词处理错误的正确方法

我对 4 通道输入热电偶卡的尝试如下:

  1. 为名为 IO 的输入和输出创建全局变量列表,然后为每个热电偶通道声明值和状态数组:
    // Term 4 EL3314: thermocouple signals
    TcInputValue_CH     AT %I* : ARRAY[1..4] OF INT;
    TcInputStatus_CH    AT %I* : ARRAY[1..4] OF WORD;
  1. 手动链接变量。编译后,TcInputValue_CH和TcInputStatus_CH都显示为PlcTask输入,因此我可以手动将它们链接到相应的变量。对于较大的项目来说,能够使用属性“TcLinkTo”会很好,如下所示:
    {attribute 'TcLinkTo' := 'TIID^Device 1 (EtherCAT)^Term 1 (EK1100)^Term 4 (EL3314)^TC Inputs Channel 1^Value'} 
    但是我不知道如何对数组执行此操作。
  2. 为了处理错误,我首先创建了适当的变量来保存热电偶通道的温度以及该通道的状态。所以这需要一个结构:
TYPE ST_TC :
STRUCT
    Temperature     : REAL;
    Status          : WORD;
END_STRUCT
END_TYPE

还有一个全局变量:

"Kiln GVL"
(* Sensor variables *)
    EastTC                  : ST_TC;
    WestTC                  : ST_TC;
        // other thermocouples could be added

然后我创建了两个程序。第一个程序是“ReadSensors”,它基本上帮助将模拟输入卡值格式化为适当的变量。我这样做:

    // Analog input Thermocouple conversion to Celsius
    Kiln.EastTC.Temperature := TO_REAL(IO.TcInputValue_CH[1]) / 10.0;
    Kiln.WestTC.Temperature := TO_REAL(IO.TcInputValue_CH[3]) / 10.0;
    
    // Thermocouple Fault detection
    Kiln.EastTC.Status := IO.TcInputStatus_CH[1];
    Kiln.WestTC.Status := IO.TcInputStatus_CH[3];

第二个程序用于安全检查,通过查看状态字寄存器并检查每个地址,我创建了一些错误代码 状态词例如低于范围的位地址

VAR
    // Error codes
    Underrange          : WORD := 16#1;
    Overrange           : WORD := 16#2;
    Error               : WORD := 16#40;
END_VAR

然后使用按位 AND 执行错误处理,因此检测到错误并可以保存类型以供进一步处理,例如在 HMI 警报消息中。

    IF TO_BOOL(Kiln.EastTC.Status AND Error) THEN
        Kiln.Error := E_ERROR_MESSAGE.TcError;
        // describe error type:
        IF TO_BOOL(Kiln.EastTC.Status AND Underrange) THEN
            Kiln.TcErrorType := E_TC_ERROR.UnderRange;
        END_IF
        // describe error type:
        IF TO_BOOL(Kiln.EastTC.Status AND Overrange) THEN
            Kiln.TcErrorType := E_TC_ERROR.OverRange;
        END_IF
    END_IF
    // repeat for all other channels...

我的方法有效吗?对于读取大量模拟输入来说,它可能非常冗长,所以我想知道如何对其进行优化。任何建议将不胜感激!

代码已编译并且似乎可以工作,尽管我还没有使用真实的硬件对其进行测试。最重要的是,我想知道如何更专业地做到这一点。

plc twincat structured-text
1个回答
0
投票

为多个输入声明变量的正确方法

我真的不认为有创建和声明 IO 变量的“正确方法”。这取决于你在做什么。我个人更喜欢将所有 IO 放在一个结构中,通常称为

ST_<machine name>TerminalInputs/Outputs
,然后将该结构放置在将执行逻辑的
FB
Program
内。所有从/到 IO 变量的链接都是在
POU
内完成的,它控制专用部分的对象(通过依赖项注入或通过内部声明的单元的输入和输出)。

对于某些事情,在 FB 内声明 IO 是有意义的,但就我个人而言,我并不经常这样做,因为就我而言,我总是通过 ADS 访问这些变量到“HMI”软件,因此可以访问所有变量集中在一个位置使事情变得更加容易。

您应该知道的一件事是,对于大多数 Beckhoff EC 从站来说,还有一个选项可以创建 PLC 数据类型并直接链接它,但请记住,如果您更改 PDO,数据类型将会更改,并且新的 GUID 将发生变化。以适当的结构生成:

enter image description here

创建后,您可以将整个输入数据链接到如下结构: enter image description here

如您所见,整个输入结构已创建,您也不需要“思考”如何解析状态: enter image description here

我不经常使用该功能,但有时它很好。缺点是,正如我提到的,如果更改 PDO,生成的数据类型可能会“消失”。

将所述变量链接到输入通道的正确方法

我以前从未使用过属性来链接变量。也许它很有用,但我个人更喜欢手动链接,它把“集群”从 PLC 代码中剔除,当你的电工把事情搞混时,你只需点击 2 次鼠标就可以解决你的问题,而不是查看表格在这个过程中投入和迷失,只是我的意见。就数组而言,您可以在这个 Beckhoff link 上找到一个示例。这是我引用的例子:

{attribute 'TcLinkTo' := '[1].bIn  := TIID^Device 1 (EtherCAT)^Term 1 (EK1100)^Term 2 (EL1008)^Channel 4^Input;
                              [1].bOut := TIID^Device 1 (EtherCAT)^Term 1 (EK1100)^Term 3 (EL2008)^Channel 4^Output;
                              [2].bIn  := TIID^Device 1 (EtherCAT)^Term 1 (EK1100)^Term 2 (EL1008)^Channel 5^Input;
                              [2].bOut := TIID^Device 1 (EtherCAT)^Term 1 (EK1100)^Term 3 (EL2008)^Channel 5^Output'}
    aModule         : ARRAY[1..2] OF FB_Module;

通过使用“状态”一词处理错误的正确方法

我想说,如果你想处理各个通道的错误,你应该为TC模块创建一个FB(没有复制粘贴代码),而不仅仅是数据类型。在 FB 内部处理错误并将其传递到您希望它们出现的任何位置。作为一个例子,这可能是这样的:

TYPE ST_TcInputData :
STRUCT
    Temperature : INT;
    Status      : WORD;
END_STRUCT
END_TYPE

    FUNCTION_BLOCK FB_TcHanlder EXTENDS FB_HasInstanceName  // Basically i get the instance name and path, look at {attribute 'refelection'}

VAR_INPUT
    scalingFactor   : INT := 10;    // Scaling factor, depends on the precision of the module as well as CoE settings
END_VAR

VAR_OUTPUT
    temperature : REAL; // Actual, calculated temperature
    error       : BOOL;
    underrange  : BOOL;
    overrange   : BOOL;
END_VAR

VAR
    Inputs : ST_TcInputData;
    _logger : I_LoggerEx;
END_VAR

VAR
    incorrectScalingTrigger : R_TRIG;
    errorTrigger            : R_TRIG;
END_VAR

逻辑

    incorrectScalingTrigger(CLK := scalingFactor <= 0);
IF incorrectScalingTrigger.Q THEN
    _logger.LogWarning(CONCAT('Incorrect scaling parameter at instance ', THIS^.InstanceName));
END_IF

IF scalingFactor = 0 THEN
    // Handle incorrect parameter setting... example
    temperature := Inputs.Temperature;
ELSE
    temperature := DINT_TO_REAL(Inputs.Temperature) / INT_TO_REAL(scalingFactor);
END_IF

underrange := Inputs.Status.0;
overrange := Inputs.Status.1;
error := Inputs.Status.2;

errorTrigger(CLK := error);
IF errorTrigger.Q THEN
    // Log the events, this is just an example of how I use logging, TcEventLogger is probably the more used way
    IF underrange THEN
        _logger.LogError(CONCAT('An error occurred (underrange) at ', THIS^.InstanceName));
    ELSIF overrange THEN
        _logger.LogError(CONCAT('An error occurred (overrange) at ', THIS^.InstanceName));
    ELSE
        _logger.LogError(CONCAT('An error occurred (unspecified) at ', THIS^.InstanceName));
    END_IF
END_IF

您的 MAIN 或您希望实例化这些 FB 的任何地方将减少到只有几行代码:

PROGRAM MAIN
VAR
    EL3314_Ch1_TcGeneratedData  : MDP5001_330_56D5BDE3;
    MyTcFunctionBlocks          : ARRAY[0..7] OF FB_TcHanlder;
    i                           : INT;
END_VAR

FOR i := 0 TO 7 BY 1 DO
    MyTcFunctionBlocks[i](scalingFactor := 10);
END_FOR

归根结底,这都是主观的。我从一个项目到另一个项目改变我的方法,也许我看到了别人做事的方式,我喜欢它并想尝试它。这只是我的看法,希望我没有让事情变得过于复杂,但恕我直言,这是一个非常广泛且基于意见的主题。

© www.soinside.com 2019 - 2024. All rights reserved.