PLC有三种编程方法:线性化编程、模块化编程和结构化编程。
线性化编程是将整个用户程序放在主程序OB1中,利用PLC的循环扫描方式执行主程序中的全部指令。其特点是结构简单,但效率低下。当某些相同或相近的操作需要多次执行时,需要重复编写程序从而造成不必要的重复工作;再者,这种方式的程序结构不清晰,给管理和调试带来不便。所以在编写大型程序时,应避免线性化编程。
模块化编程是将程序根据功能分为不同的逻辑块,对每一逻辑块分别编写子程序,然后在OB1中根据不同的条件调用不同的子程序。这种方式的特点是可以将大程序进行合理的分解,利于多人分工合作,并方便调试。由于各逻辑块是有条件地调用的,所以可以提高CPU的利用率。
结构化编程是将过程要求类似或相关的任务进行归类,利用接口参数进行程序的封装,并利用功能FC或功能块FB进行编程,以形成通用性的解决方案。通过不同的参数调用同一功能FC,或通过不同的背景数据块调用同一功能块FB,以实现不同的控制目的。这种方式的特点是接口统一,代码的复用率高,方便用户使用,但要求程序员对系统功能进行合理分析、分解和综合,对设计人员的要求较高。
1.模块化编程
模块化编程中OB1起着主程序的作用,不同的功能(FC)或功能块(FB)用于实现不同的功能任务,并在主程序中被调用,且这些功能模块即子程序不需要向调用块返回数据。
【例8-5】有两台电动机,控制模式是相同的:按下起动按钮(电动机l对应I0.0,电动机2对应I0.2),电动机起动运行(电动机1对应Q0.0,电动机2对应Q0.1),按下停止按钮(电动机1对应I0.1,电动机2对应I0.3),电动机停止运行。
根据模块化编程的思想,分别在FC1和FC2两个子程序中利用起保停电路设计不同电机的控制程序,如图8.8(a)和图8.8(b)所示,最后在主程序OB1中调用这两段程序。
图8.8 电动机控制的模块化编程例子
【例8-6】采用模块化编程思想实现公式:。
首先建立一个子程序FC3,实现上式的功能,然后在主程序OB1中进行调用,这就是模块化程序设计的思想。
假设整数a存放于MW0,整数b存放于MW2中,c为实数存放于MD4,建立DB3及相应的存储区域,在FC3中编写程序如图8.9(a)所示,图8.9(b)为在主程序OB1中调用FC3。
图8.9 功能函数模块化编程
由图8.9可以看出,尽管程序的最终目的是获得平方根而不在乎a的立方、b的平方及它们的和,但是仍然需要填写全局地址来存储相应的中间结果,这会浪费全局存储空间的使用。这种情况下可以使用临时变量。
2.临时变量
临时变量可以用于所有块(OB、FC、FB)中。当块执行的时候,它们被用来存储临时数据,退出该块时,这些数据将丢失。
临时变量在块的变量声明表中定义。点击程序编辑器工具栏间的上下箭头,可以收缩或展开块的变量声明表,其中Input为输入参数,Output为输出参数,InOut为输入/输出参数,Temp为临时工作变量。在此程序设计中,定义了整型临时变量a3,b2和sum_i,以及实型临时变量sum_r,分别存储变量的立方、平方,以及它们的和。程序相对简单,在此不再赘述。定义好临时变量后,在子程序中就能使用所定义的临时变量和全局变量,临时变量的标识是在前面加#,全局变量的标识是在前面加%,当两者同名时,优先使用临时变量,除非设计人员人为选择全局变量。定义临时变量编程如图8.10所示。
图8.10 定义临时变量编程
3.结构化编程
当任务要求中出现多个类似的功能时,采用模块化编程方法将不可避免地出现大量的重复代码,这时可以利用结构化编程方法对其进行优化,即对功能块的输入/输出进行封装,当采用不同的参数进行功能(FC、FB)调用时,程序实现对不同对象的控制,这就是结构化编程的意义所在。
结构化编程有如下优点:
(1)程序只需生成一次,减少了编程时间;
(2)该块只在用户存储器中保存一次,降低了存储容量;
(3)该块可以利用不同的参数多次调用,完成性质相同的功能。
结构化编程会涉及FC和FB的局部存储区,局部变量的名字和大小必须在块的声明部分确定,每一参数占一行,如果需要定义多个参数,可以用回车键来增加新的参数定义行,也可以选中一个定义行后,通过菜单命令“插入”→“声明行”来插入一个新的参数定义行。当块已被调用后,再插入或删除定义行,属于改变了程序结构,这时必须重新编写调用指令,否则会报块的一致性错误。此时可以通过程序编辑器手动或自动地更新调用,自动方式是选择“选项”→“块调用”→“更新所有块调用”,就可以解决这个问题。
形式参数的类型及作用如表8.7所示。
表8.7 形式参数的类型及作用
【例8-7】用结构化编程方法重新编写前述电动机的控制电路程序。
新建块Calc,其形式参数定义和程序设计如图8.11、图8.`12所示。
(www.daowen.com)
图8.11 结构化编程中的参数定义
图8.12 结构化编程中的程序设计
在编写此控制电路程序时要注意以下几个问题。
(1)如果在编辑一个块的程序时使用符号名,编辑器将在该块的变量声明中查找该符号名。如果该符号名存在,编辑器将把它当作局部变量,并在符号名前加“#”号。
(2)如果它不属于局部变量,则编辑器将在全局符号表中搜索。如果找到该符号名,编辑器将把它当作全局变量,并在符号名上加引号。
(3)如果在全局变量表和变量声明表中使用了相同的符号名,编辑器将始终把它当作局部变量。然而,如果输入该符号名时加了引号,则可成为全局变量。
与模块化方法在使用上的不同就是,结构化编程中的输入/输出参数是可以根据需要进行改变的,因而程序可以重用。如图8.13所示为在OB1中调用函数FC4:Motor控制2台电动机。
图8.13 结构化程序设计中的程序调用
【例8-8】在工业生产中,经常需要对采集的模拟量进行滤波处理。本例将最近采集的三个采样值进行均值滤波,即将三个采样值求和,然后除以3。假设最新采集的模拟量工程值存储在MD0中,处理结果存储在MD16中,所有数据均为浮点型。
编程思路:利用堆栈概念,将最近采集的三个数保存在固定的全局地址中,并在每个控制周期进行数据更新,以确保参与运算的数据是最新的,因而此子程序FC5可以在循环中断处理程序中调用。
首先如图8.14所示定义FC5的形式参数。三个采集值Value1、Value2和Value3的参数类型均为INOUT型,不能为TEMP型,否则将无法保存该数值。
在FC5中编写程序。“程序段3”的含义是按顺序将三个最近时间的采集值保存,丢弃最早采集的数据,注意这三个MOVE指令的次序不能改变;“程序段4”的含义是利用实数运算的函数,将三个采样值相加后除以3,得到平均值。
图8.14(b)示意了调用FC5并赋值实际参数,将平均值存放在MD16中。这样,通过不同的实际参数可以重复调用FC5进行均值滤波。
图8.14 程序例子
但是,通过此例也可以看出一个问题:我们关心的只是三个数的平均值,而调用FC5子程序时,却需要为三个采集值寻找全局地址进行保存,麻烦且容易造成地址重叠,能不能既不用人为寻找全局地址而又能保存数值呢?方法是通过FB(Functlon Blocks:函数块)实现。
4.FB的使用
FB不同于FC之处是它带有一个存储区,也就是说,有一个局部数据块被分配给FB,这个数据块称为背景数据块(Instance Data Block)。当调用FB时,必须明确指定背景数据块,该数据块将自动打开。背景数据块可以保存静态变量,可在其变量声明表中定义。当FB块退出时,静态变量的值得以保持。当FB被调用时,实际参数的值被存储在它的背景数据块中。如果在块调用时,没有实际参数分配给形式参数,在程序执行中将采用上一次存储在背景数据块中的参数值。
每次调用FB时可以指定不同的实际参数。当块退出时,背景数据块中的数据仍然保持。可以看到,FB具有以下优点:
(1)当编写FC程序时,必须寻找空的标志区或数据区来存储需保持的数据,并且要自己编写程序来保存,而FB中的静态变量可由系统自动保存。
(2)使用静态变量可避免两次分配同一存储区的危险。
结合前面例子,如果用FB块实现FC1的功能,并用静态变量EarlyValue、LastValue和LatestValue来代替原来的形式参数,如表8.8所示,将可省略这三个形式参数,简化了块的调用。在FB1中定义形式参数,编写程序同图8.14(a),如图8.15所示为调用FB1子程序,其中DB10为FB1的背景数据块,在输入时若DB10不存在,则将自动生成该背景数据块。双击打开背景数据块DB10,可以看到DB10中保存的正是在FB的接口中定义的形式参数,如图8.16所示。对于背景数据块,无法进行编辑修改,而只能读写其中的数据。
表8.8 定义FB的形式参数
图8.15 调用FB1子程序
图8.16 背景数据块
调用FB块时需要为其指定背景数据块,这称为FB背景化,类似于C语言等高级语言中的背景化,即在变量名称和数据类型下面建立一个变量。只有通过用于存储块参数值和静态变量的“自有”数据区,FB才能成为可执行的单元。
5.检查块的一致性
如果在程序生成期间或之后调整或增加某个块(FC或FB)的接口或代码,可能导致时间标签冲突。反过来,时间标签冲突可能导致在调用的和被调用的或有关的块之间不一致。针对这种情况,当一个块已在程序中被调用之后,再增加或删除块的参数,必须更新其他块中该块的调用。否则,CPU会进入STOP状态或者块的功能不能实现。在项目视图中打开程序编辑器,通过菜单命令“选项”→“块调用”,点击“更新所有块调用”,可以更新所有块的时间标签冲突和块不一致的调用。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。