我正在遵循有关使用CIP进行控制器数据访问的Allen-Bradley文档,特别是读标签服务,写标签服务以及有关读/写整个UDT的详细信息:https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf。我正在使用EIP库来执行读/写标签服务和多服务请求。
我想澄清的是,读取或写入整个UDT是否是一项原子操作(使用手册中概述的方法在一个服务请求中执行读取/写入操作并了解将其拆包的元数据)?也就是说,在整体上成功读取/写入时,PLC或软件方面是否永远不会看到部分更新的UDT值?
一个相关的问题是:如果我想通过在一个多服务请求中发送多个读/写标签服务请求来读取/写入多个标签,那么我对这些标签集的同步读/写是否有保证?我认为没有,但是我似乎找不到关于该主题的任何权威性文档。尤其是如果请求分散在多个CIP数据包中。
答案 0 :(得分:1)
在工作中,我们发现确实存在这样的情况:对DINT进行的任何读/写操作(我们没有尝试较小的数据)绝对不是原子的。
我们努力寻找一种方法来确定读取何时返回“残缺”数据。我们最终发现的是,“撕裂”始终是连续的。读/写值的第一部分是最新的,而下一部分不是。
因此,我们使用了一组哨兵值。在要读取或写入的任何标签的开头都有一个DINT,在结尾有一个DINT。我们将第一个前哨设置为一个值,然后更新标签的其余部分。然后,我们将设置最后一个哨兵。我们对哨兵使用单调递增的值,并使用强制换行。
在读取类似这样的标签时,我们将比较标记值。如果它们相同,那么我们将获得很好的阅读。如果不是,我们再读一遍。
sentinel X header
<data>
sentinel X footer
如果数据在传输过程中被“破坏”,我们将看到:
sentinel X header
<data>
sentinel X-1 footer
我对此进行了大量测试(我创建并维护了一个用于与Allen-Bradley PLC通信的C库),并且能够通过两个DINT的简单数组显示“撕裂”。我没有尝试使用较小值的数组。
根据我们的经验,UDT与DINT数组没有什么不同。如果该值大于DINT,则对于程序扫描可以部分读取或写入。
答案 1 :(得分:0)
我们通常检查“消息响应”字段中的“常规状态”,以确定CIP消息成功(完成?)还是失败。但是,如果要求PLC在使用任何数据之前先接收整个数据,则我将添加某种类型的计时器逻辑,以确保在(确信)使用数据之前(发出消息后)已经传输了足够的时间。懒?是。但这有效。
特定于您有关通过读/写服务的原子性的问题。一般的经验法则是不要依赖任何原子的消息数据(尤其是大数据包)。您必须等待服务请求的反馈/响应。
希望这会有所帮助。
答案 2 :(得分:0)
我能够对此进行测试,并确认对于单个UDT或数组,读/写标签CIP服务不是原子的。我最初关心的是我是否可以安全地写入整个UDT或数组,并确保处理该数据的PLC将看到该数据处于“写入前”或“写入后”状态,而不是部分写入状态。我进行了一些测试,这些测试从CIP写标记服务编写了一个10个元素的DINT数组。在PLC上,我执行同步复制(CPS)将阵列复制到另一个标签中,然后检查它是否与原子复制的数据一致。我看到数据偶尔处于部分写入状态,这意味着写标记服务未与同步复制指令同步。请注意,我只使用一个CIP服务请求来编写数组,而不是每个元素都使用多个请求。这并不是完全出乎意料,但是最好知道,以便从CIP服务读取/写入多个值的任何人都知道缺乏同步。我可以在需要时添加自己的同步机制。