inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">上个月刚接触西门子OMAC的PACLML示例,我试着做了个程序来验证,效果不错。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">先来说说示例的观感,个人认为这仅仅是西门子为了实现模式状态机的一个小示例,不算可以直接使用的东西,当然离库很远。示例设计得没有什么章法,仅仅实现了而已,设计细节没有多少值得借鉴得地方。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">大的用处是让我了解了什么是模式状态机,当然了,肯定也只是PACKML的一部分内容。我不了解PACLML,只是从一些资料知道PACKML其实是涵盖了整个项目结构的内容,不光是模式状态机了。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">以前也做过状态机,使用Case对不同状态进行处理和转移。大问题是入口case比较难以把握,稍不留神就会错误触发。状态的转移也完全依赖现有状态里面的判断。具体如何不便不好描述。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">说示例没有多少借鉴的地方其实有点昧良心了,给我大的启示是状态转移和状态处理是分离的。也许复杂的部分是状态的收集和处理,示例没有这方面的内容。我本人项目中也没有做专门的工作,只是使用了原有底层模块的状态简单处理。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">容易实现的是状态转移了,所以我就做了容易的部分。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">并且实现后发现其实是完全可以适用于很多离散行业场景的。这里记住,PACKML是包装行业的规范,它定义的状态并不适用于其他行业。其他行业有各自的状态定义,这个自己来。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">示例对于状态的记录采用字符串,包括命令、SC,这个我觉得使用数值更好,占用空间少,易于编程。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">至于诊断信息则用于调试过程,我把诊断和状态转移块分离了,需要诊断信息可以用单独的块接住状态机传出的诊断信息即可,多少条任意。但状态机只传出当前的信息,并不保存之前的信息,并且都是编码信息,需要诊断块自行解码。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">当调试好后,诊断块都可以在项目中删除不用。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">先记到这,有时间再写具体实现。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">------------------------------------------------------
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">2024.01.23
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">本来已经意兴阑珊了,可偏偏是个精,都还没开始呢。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">好吧,只能继续了。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">资料里面大量篇幅关于高层设备如何划分之类的,看看就可以了。有机会从整体来设计当然不一样了,但很多时候我们都只是一个螺丝钉,并不注重整体架构。有时是形势逼人,有时觉得自己可以整体把控了,无奈这个整体又太过渺小。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">只记得资料里有句话很有意思,大意是如果你不能正确划分设备编号的话,那就从底层开始编号吧,而不是一开始就从高层来。对,正解。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">放张图:
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">这是西门子1847里面的截图,当然我没有1847,而是从壶琰棠发布的视频解的图。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">具体我就不分析了,只看我的结论:
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">1、有一个全集,包括了所有的状态。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">2、全集不一定非得有一个模式对应,可能有也可能没有。
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">3、模式1向模式2转移需要的条件:模式2里面存在当前模式1的当前状态A.
inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">4、状态是有等级的,L0 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">5、命令和SC其实没有区别,我一律称作SC。资料里面SC叫做状态完成state complete,我叫做状态改变 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">state change. inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">6、...... inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">如何设计: inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">仔细观察Excute状态: inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">1、有三个出口、三个入口。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">2、如果用链表表示,则入口可以不用关心,只需要出口。不过博途不支持链表(指针......),改用数组,一样的道理。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">3、数组的单元是个结构:状态本体、出口。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">4、状态是个整数,表示状态标识,出口也是个整数(后来改用word)。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">看级别,把级别也看做状态,则和普通状态没有区别。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">只是级别另外做成单独的数组,单元类型和普通状态是同一个类型。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">如果这样,如何表示从一个级别的状态转移到另一个级别的状态呢? inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">后来设计成处理出口SC编码,做成Word类型,高字节表示级别,低字节表示SC标识。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">范围是不是够呢?一个字节表示256种状态,应该够了吧。特别是级别。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">预定义四个出口够了吧?做成符号常量不是更方便些。这样,模式数量、状态数量、级别数量、SC数量等等都如此定义。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">这样,答题设计就有了,总体上变成了填表了。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">逻辑设计很简单,不需要多少代码。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">但是工作量大的是诊断工作。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">如何定义呢?我也是边实现边定义,没有事先定义。现在还没有机会整理诊断编码。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">但是有一点是肯定的,就是诊断大多是给调试使用,给人看的,大量的文本占用空间,就不集成在模式状态机里面了,模式状态机仅输出诊断信息,只当前诊断,不存之前的信息。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">如果需要就用单独的块接住往诊断缓冲区放。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">工作流程就是画出状态图:不同模式的状态图,模式少的话就用一张图。然后填数字,然后填表。需要把SC编码变成16进制码,借助Excel来做容易些。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">放张我设计过程中的截图,上面的SC编码没有级别编码,需要进一步转换。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">配置表: inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">1、诊断文本列表,可以在PLC,也可以在HMI中处理,随便,其实调试后可以不用。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">2、模式状态机配置表 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">3、状态或级别配置表内容: inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">上图以级别表为例,状态表类似。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">当处于某个状态时,需要和配置表中SCCode一致的SC才能使状态发生转移,不符合则会被拒绝。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">逻辑处理部分,初始化检查表内容是否适合,我只设计了检查SCCode和Next是否配套,接着生成模式Pattern,也即各个模式下存在全集状态的一个记录,是个位域,DWord。对了,我都忘了我设计的项目状态超过32个了,这个咋整? inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">初始化后根据传入的SCCode先在级别表里面检查是否有合适当前级别的SC,从别开始到当前级别终止检查。如果有则直接转入Next状态,没有则继续在当前State里面检查。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">都没有则拒绝执行转移。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">代码简单就不放了。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">现在的重点是如何设计好的状态收集、如何处理才能使SCCode不会被错误覆盖造成状态不能转移。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">------------------------ inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">后记: inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">如果一个项目里有多个状态机,使用全局UDT和全局常量就不合适了。比如说一个状态机比较小,就需要和大的状态机一样大的配置表,比较占空间。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);"> inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">我的做法是把状态机集成到模块中,不是单独模块。配置表也集成到模块中,全局常量变成了局部常量了,UDT也变成匿名结构。 inkMacSystemFont, "segoe ui", Roboto; padding: 0px; margin-top: 0px; margin-bottom: 0px; color: rgb(51, 51, 51);">