【问题标题】:Iterating over structures in Twincat PLC (Structured text)迭代 Twincat PLC 中的结构(结构化文本)
【发布时间】:2017-11-20 02:48:05
【问题描述】:

假设我有以下结构,其中包含有关轴的信息:

TYPE AxisInfo :
STRUCT
    AxisStatus : ARRAY [0..3] OF BYTE;
    DriveStatis : ARRAY [0..3] OF BYTE;
    FeedRate : ARRAY [0..3] OF BYTE;
    Inputs : BYTE;
    Outputs : BYTE;
    Extra : BYTE;
    CurPosW: UDINT;             
    CurPosX: UDINT;
    CurPosY: UDINT;
    CurPosZ: UDINT;
    CurVelX: UDINT;
    CurVelY: UDINT;
    CurVelZ: UDINT;
    ComPos : UDINT;
    SetVel : UDINT;
    DacVel : UDINT;
    WinchErrPos : UDINT;
    XYZErrPos : UDINT;
    EnFaults : UDINT;
    ActFaults : UDINT; 
    BpFaults : UDINT;
    BpTimeLeft : UDINT;

这个结构总共包含 82 个字节。我将有 8 这些结构始终运行(因为我有 8 个轴)。这相当于 656 字节 加上所有结构。

现在,我有一个名为 Buffer 的变量:

Buffer: ARRAY [0..1023] OF BYTE;

我希望能够按顺序用 8 个结构中的每一个来填充这个缓冲区。例如:

Buffer[0] := AxisStatus[0]; //this is for the 1st axis
Buffer[1] := AxisStatus[1]; //this is for the 1st axis
….
Buffer[78] := BpTimeLeft; //this is for the 1st axis
…
Buffer[648] := BpFaults;
Buffer[652] := BpTimeLeft; //this is for the 8th axis

在 PLC 上的 ST 中是否有办法遍历结构的成员,然后将这些成员放入缓冲区并确保它们位于正确的位置?你知道有什么技巧可以做到这一点吗?

我问这个是因为我可以通过以下方法做到这一点,

For axisIndex:=1 to 8 DO
    Buffer[0] := AxisStatus[0];
    Buffer[1] := AxisStatus[1];
    …
   Buffer[78] := BpTimeLeft; this is for the 1st axis
END_FOR

但是我必须输入需要为其分配缓冲区的每一行,然后在我用第一个轴填充缓冲区后必须做一些技巧以避免它覆盖前 82 个字节。必须有某种方法可以自动执行,以防我将来更改结构的成员。?

【问题讨论】:

  • 提示:指针、Sizeof 和 Memcpy

标签: automation plc twincat structured-text


【解决方案1】:

您是否尝试使用 MEMCPY 函数?那应该少很多努力... 您可以通过两种方式复制结构和字节数组。带有一些索引和偏移量指针。

【讨论】:

【解决方案2】:

我建议在结构声明中使用{attribute 'pack_mode' := '1'},然后您可以使用MEMCPY轻松复制数据。

结构声明:

{attribute 'pack_mode' := '1'}
TYPE AxisInfo :
STRUCT

现在您可以将整个结构复制到字节数组中,或者只是一些变量。例如,要将Inputs从结构复制到字节数组,您可以使用类似

MEMCPY(ADR(Buffer[2]), ADR(AxisStatus) + 12, 1)

将一个字节从(AxisStatus 的地址 + 12 个字节,等于Inputs)复制到缓冲区[2]。如果你复制多个字节,它会将它们复制到缓冲区[2]、缓冲区[3]、缓冲区[4]等等。

memcpy 在这种情况下非常有用。

要将整个结构复制到缓冲区的开头,您可以 MEMCPY(ADR(Buffer), ADR(AxisStatus), SIZEOF(AxisStatus))

复制下一个结构体 MEMCPY(ADR(Buffer) + SIZEOF(AxisStatus), ADR(AxisStatus), SIZEOF(AxisStatus))

【讨论】:

    【解决方案3】:

    老实说,我会避免为了检索您需要的状态信息而遍历结构。如果你有 100 轴呢?

    它不能很好地扩展。

    如果您改为更改程序的设计会怎样?

    您可以设计一个功能块(我们称之为 AxisDevice)来模拟一个轴。

    AxisDevice 将包含操作 axis 所需的所有功能块。然后,您将通过一个属性将AXIS_REF 传递给AxisDevice,并可以检索axis 的状态信息(例如:getStatus := AxisStatusStruct)。

    通过这样做,您只需决定并实施关于轴的哪些信息是“公开的”。

    您所有的8 axis 都可以是AxisDevice 类型,并在需要时在运行时提供信息。

    【讨论】:

      【解决方案4】:

      您无法保证字节位置和元素位置,因为编译器会根据硬件目标优化空间。你无法赢得这场战斗——你要对抗结构的全部意义。

      1)。您可以手动打包自己的字节数组以保证位置而不是使用结构(但是您也可以使用机器语言进行编程,因为您正在击败高级编程......

      BUFFER := ARRAY[0..7] OF AxisInfo;

      BUFFER[0] 将是轴 0, BUFFER[1] 将是轴 1, 等等

      2)。您可以将缓冲区定义为结构数组并停止访问特定的内存位置(这取决于硬件/平台!)

      3)。如果您将数据发送到 HMI 或某些不知道结构但只知道字节的设备,那么您将无法手动将结构元素映射到字节数组中的位置。这是 ModbusTCP 等现场总线通信的常规解决方案。

      【讨论】:

      • 您可以保证结构中的字节位置。编译器没有对硬件进行优化。只有一个属性“打包模式”。你可以看到它就像一个规则集,结构内的变量是如何排列的
      • 如果您从摩托罗拉平台切换到英特尔平台,您可以进行字节交换。此外,编译器将对齐您的字节,并可能根据您定义结构的方式引入死字节(DWORDS 必须对齐可被 4 整除的内存位置等)。
      • 是的,这就是 TwinCat 中的打包模式。
      猜你喜欢
      • 2014-10-30
      • 1970-01-01
      • 2014-12-29
      • 1970-01-01
      • 2016-03-07
      • 2011-08-18
      • 1970-01-01
      • 2011-03-10
      • 2014-02-21
      相关资源
      最近更新 更多