【问题标题】:Beckhoff-PLC: Declaring an array as remanent inside a Function BlockBeckhoff-PLC:将数组声明为功能块内的剩余数组
【发布时间】:2022-10-06 17:49:14
【问题描述】:

这是我在 * 上的第一个问题,所以请随时给我有关问题的反馈 :)

我是使用 Beckhoff 控制器的新手,我正在尝试编写一个程序块来将机器数据传送到 PC。为了存储不同类型的数据,我在功能块 \"Communication\" 中使用了一个 T_ARG 数组,该数组在 \"MAIN\" 中实例化。每次重新启动时,它的数据都会被重置,这导致我必须在开始时总是再次将信息加载到阵列中,这样我就会在系统上获得两次数据。

FB“通讯”内的代码:

VAR
    Values : ARRAY[DataArrayLow..DataArrayHigh] OF T_ARG;
    ValueChanged : ARRAY[DataArrayLow..DataArrayHigh] OF BOOL;
END_VAR

我正在使用数组“ValueChanged”通过使用 setvalue 方法来跟踪数据的变化,该方法标记了要传输的“Values”中的索引。

现在我像往常一样调用“MAIN”中的功能块:

VAR
    Communication : FB_Comm;
END_VAR
__________________________________________________________________________
Communication();

我已经尝试将变量标记为持久性,但这不起作用。

我真的不会创建一个外部全局变量并将其作为输入提供给功能块,因为它违背了封装的目的并且会变得混乱。

    标签: arrays plc twincat st


    【解决方案1】:

    我不深入了解Beckoff,但它与Codesys非常相似,并且从文档here来看,它遵循相同的原理:

    在函数中将局部变量声明为 PERSISTENT 无效。不能以这种方式使用数据持久性。

    从您看来正确的方法是使用 Globals,也许您可​​以研究一种模块化变量结构的方法,以便将其作为 VAR_IN_OUT 传递给您的块,可能是 STRUCTSARRAY 可以帮助您实现这一点。

    【讨论】:

      【解决方案2】:

      通常,持久变量应在 TwinCAT 正确关闭或重新启动期间自动保存。因此,如果您只是断电(没有 UPS),通常不会保存持久数据。

      您可以使用WritePersistentData 功能块来确保存储持久数据。 在你的情况下,你不应该一直调用这个函数块,而是只在你的任何变量发生变化时才这样做。

      【讨论】:

      • 我现在尝试这样做,并将函数对象和其中的数组标记为剩余。但即使在没有关机的情况下重新启动 TwinCat 也不起作用。
      • 您是否尝试将变量作为 VAR_PERSISTENT 放入功能块中?
      • 我将 FB 本身和其中的数组标记为 PERSISTENT。我在两个变量上都使用了它。 wiki 还说:“在函数中将局部变量声明为 PERSISTENT 无效。不能以这种方式使用数据持久性”。
      • wiki 说您不能在函数中使用 PERSISTENT 的原因是因为函数的数据在每次调用之间都会重新设置。一旦在函数调用之外,数据就会丢失。您需要使用功能块而不是功能。将您的功能更改为功能块。此外,请确保对 WritePersistentData 的调用成功。
      • 使用 PLC 的 UPS 功能块是确保数据在关机时保存的好方法。通常我只是将 FB 的参数设置为 IN OUT 并将参数保存为专用区域中的持久结构。但正如雅各布所说,没有效果的记忆适用于功能。我记得和 beckhoff 支持人员聊天时说 FB 中的数据可以是持久的,我可能以前使用过它,但我不记得了。
      【解决方案3】:

      这是一个简单的项目,可以向您展示功能块内的 PERSISTENT 数据确实可以保存。

      声明一个测试结构:

      TYPE ST_DataToBePersistent :
      STRUCT
          bVar    : BOOL;
          nVar    : INT;
          fVar    : REAL;
      END_STRUCT
      END_TYPE
      

      现在声明一个功能块,FB_Test 使用该结构作为内部参数集。将 FB_WritePersistentData 添加为 VAR_IN_OUT。我们需要调用它来保存这个功能块内的持久数据。

      FUNCTION_BLOCK FB_Test
      
      VAR PERSISTENT
          arrPersistentParameterStruct    : ARRAY [0..10] OF ST_DataToBePersistent;
      END_VAR
      
      VAR_IN_OUT
          fbWritePersistentData   : FB_WritePersistentData;
      END_VAR
      
      VAR
          bSavePersistentData : BOOL;
      END_VAR
      

      FB的主体:

      IF bSavePersistentData THEN
          bSavePersistentData := FALSE;
          fbWritePersistentData.START := TRUE;
      END_IF
      

      设置内部结构值的简单方法:

      METHOD PUBLIC WriteToStruct
      VAR_INPUT
          arrPersistentParameterStruct : ARRAY[0..10] OF ST_DataToBePersistent;
      END_VAR
      

      而且是身体。当调用内部结构数组时,我们还设置了一个标志来调用传递的 FB_WritePersistentData,它将所有持久数据保存在专用端口(本地)上:

      THIS^.arrPersistentParameterStruct := arrPersistentParameterStruct;
      bSavePersistentData := TRUE;
      

      实例化 2 个实例,只是为了设置数组的值并添加将在调用方法 FB_Test.WriteToStruct 时调用的 FB_WritePersistentData。还为诊断目的添加一些变量并触发方法:

      PROGRAM MAIN
      VAR
          fbTestInstance1 : FB_Test;
          fbTestInstance2 : FB_Test;
          fbWritePersistentData   : FB_WritePersistentData;
          bSetData1   : BOOL;
          bSetData2   : BOOL;
          arrDataToSet    : ARRAY[0..10] OF ST_DataToBePersistent;
          TofPersistentDataSaved  : TOF;
          FtrigDataSaveComplete   : F_TRIG;
          bDataSaveComplete       : BOOL;
      END_VAR
      

      在主体中,循环调用 fbs 和持久化数据 FB。在在线模式下将 arrDataToSet 的值设置为您想要的任何值,并触发您想要更改的功能块。保存完成后观察 bDataSaveComlete 设置为 2 秒。

      fbTestInstance1(fbWritePersistentData := fbWritePersistentData);
      fbTestInstance2(fbWritePersistentData := fbWritePersistentData);
      
      IF bSetData1 THEN
          bSetData1 := FALSE;
          fbTestInstance1.WriteToStruct(arrPersistentParameterStruct := arrDataToSet);
      END_IF
      
      IF bSetData2 THEN
          bSetData2 := FALSE;
          fbTestInstance2.WriteToStruct(arrPersistentParameterStruct := arrDataToSet);
      END_IF
      
      fbWritePersistentData(NETID := '', PORT := 851);
      
      FtrigDataSaveComplete(CLK := fbWritePersistentData.BUSY);
      TofPersistentDataSaved(IN := FtrigDataSaveComplete.Q, PT := T#2S);
      bDataSaveComplete := TofPersistentDataSaved.Q;
      
      IF fbWritePersistentData.BUSY THEN
          fbWritePersistentData.START := FALSE;
      END_IF
      

      例子:

      fbTestInstance1 的初始状态:

      现在我设置结构:

      我将通过设置 bSetData1 写入 fbTestInstance:

      我将为第二个 fb 设置不同的值:

      现在我将启动目标机器的 TwinCAT 的重启:

      重新登录,数据还是一样:

      重启目标机器:

      持久性数据始终正确加载到 TwinCAT 上,无论是重新启动运行时还是操作系统。

      希望这能回答你的问题。正如 Jakob 已经提到的,dwpessoa 所说的仅适用于函数,因为它们占用的所有内存在释放时都会被丢弃。

      【讨论】: