#使用HMI界面更改PLC中IO控制地址转换的方法#
开发背景:
多年前,我在使用KUKA机器人控制系统时,发现他们的变量系统设计的非常巧妙,当然很多软件也支持这种功能,只是他们的软件做的更加得心应手,只需要在IO变量界面的后面修改变量地址即可,比如如$变量—1000,修改为$变量—1001(仅举例),把这种变量的本身不变,只是接口发生改变的形式,在项目场景中有很大的应用。以此类推,比如PLC的IO端口不变(物理地址),那么给IO端口附上变量地址,通过变量间的关系分别控制输入输出,当改变输入或输出端口变量的地址时,根据规定的逻辑关系,相应地址的联系保持不变,端口输入输出发生改变。这种形式类似于指针寻址的方式,只不过用的是PEEK和POKE的存储地址方式。
仿真结果如下:
为了便于理解这种方法,我事先做了一个简单的控制界面,由于西门子的I区变量不能直接被界面访问控制,为此,程序内部我做了一个中间变量作为转换,实际效果不影响理解。
PLC地址转换
关键语句如下:
本程序通过PEEK和POKE的用法,仅需不到50行的程序代码,其中还加入了检测代码,即完成了IO控制地址的转换,有关PEEK和POKE存储地址的讲解摘抄如下,如需详细说明,可参考官方手册。
程序分析说明:
本次实现的假想控制关系如图:
基于以上控制关系,假如输入I0.0(启动按钮),控制输出Q0.0(启动按钮灯),现将I0.0接线至I0.1,但输出逻辑不变。正常的操作方式是,打开PLC程序,修改IO点位控制程序。但加入自定义变量后,在界面中,修改变量的地址(默认I0.0:0,I0.1:1→修改后I0.0:1,I0.1:0),仍然输出Q0.0的值,是不是方便很多?同理可得,当项目需求由I0.1控制Q0.0,改为I0.1控制Q0.1时,改变输出区的自定义值即可。
那么如何通过程序实现这种控制需求呢?当然有很多编程方式,只是当年在思考的时候,使用了PEEK和POKE的用法,如今在梳理文章的时候,我又进一步完善了当年的程序(自己写的差点没看懂,还好有注释^_^)。
直接附源码了,主打的就是一个无私奉献。
//初始化赋值
IF "PublicVar".Init THEN
FOR #i := 0 TO "MaxPoint" DO
"PublicVar".SetSI_No[#i] := #i;//先给仿真区地址编号
"PublicVar".SetSQ_No[#i] := #i;//先给仿真区地址编号
END_FOR;
"PublicVar".Init := FALSE;
END_IF;
//小提示复位
"PublicVar".InTip := '';
"PublicVar".OutTip := '';
//检测重复性
FOR #i := 0 TO "MaxPoint" DO
IF "PublicVar".GetSI_No[#i] > "MaxPoint" THEN
"PublicVar".InTip := 'The input address data MoreLen!';
END_IF;
IF "PublicVar".GetSQ_No[#i] > "MaxPoint" THEN
"PublicVar".OutTip := 'The Output address data MoreLen!';
END_IF;
FOR #j := 1 TO "MaxPoint" - #i DO
IF "PublicVar".GetSI_No[#i] = "PublicVar".GetSI_No[#i + #j] THEN
"PublicVar".InTip := 'The input address data REPEAT!';
END_IF;
IF "PublicVar".GetSQ_No[#i] = "PublicVar".GetSQ_No[#i + #j] THEN
"PublicVar".OutTip := 'The Output address data REPEAT!';
END_IF;
END_FOR;
END_FOR;
//循环赋值
FOR #i := 0 TO "MaxPoint" DO
//地址赋值
"PublicVar".GetSI_No[#i] := "PublicVar".SetSI_No[#i];
"PublicVar".GetSQ_No[#i] := "PublicVar".SetSQ_No[#i];
//读取仿真I区的状态,给中间变量I区;
"PublicVar".MI_No["PublicVar".GetSI_No[#i]] := PEEK_BOOL(area := 16#84, dbNumber := 3, byteOffset := #i / 8, bitOffset := #i MOD 8);
//将中间变量I区状态返回给物理I区;
POKE_BOOL(area := 16#81,dbNumber := 0,byteOffset := "PublicVar".GetSI_No[#i] / 8,bitOffset := "PublicVar".GetSI_No[#i] MOD 8,value := "PublicVar".MI_No["PublicVar".GetSI_No[#i]]);
//读取中间变量I区(物理I区),给中间变量MQ区;
IF "PublicVar".InTip = '' AND "PublicVar".OutTip = '' THEN
"PublicVar".MQ_No := "PublicVar".MI_No;
END_IF;
//将中间变量MQ区的状态,输出信号给物理Q区;
POKE_BOOL(area := 16#82,dbNumber := 0,byteOffset := #i / 8,bitOffset := #i MOD 8,value := "PublicVar".MQ_No["PublicVar".GetSQ_No[#i]]);
END_FOR;
#写在最后#
刚刚已经说过I区的问题,实际上,能看懂这块程序的话,不加仿真I区还稍微简单点,直白点说,就是获取I区的物理状态,将对应的I区点位的值,给到相应的变量地址里面,整个过程还是比较简单的,当然,本程序仅是提供一个解决案例,在实际在应用的过程中,要完善检测程序,避免因交换地址出现的编程错误等控制风险。
希望大家多多评论,支持,如有疑问,或工作中出现的疑难杂症,都可以在下方评论交流,谢谢!