200Smart是日式风格的小型PLC,其函数用子程序来实现,叫做SBR。SBR类似于TIA平台1200的FC,没有自己的私有数据。
SBR的用来实现一些不需要保留私有数据的一次调用函数功能,比如一次性的数学计算,如果需要使用前几次的计算结果,通常可以使用几种方式传入SRB,一种是使用接口的InOut,另一种是不使用接口而是直接使用全局变量。但直接使用全局变量的缺点除了不能模块化,还有不能被重复调用(无法实现多个实例)。
常规意义上来讲SBR多次调用需要注意很多问题。我们与1200比较,1200有DB,1200的FC可以使用DB来区分不同的实例。而200Smart的子程序就只能靠设计者自己来规划不同的V区来区分不同的实例。
多次调用还有很多和语法特点有关的注意事项,比如沿指令,在SBR多次调用中就不能使用。其他更让人头痛的指令是定时器,当然定时器不论是SBR中还是在主程序里都不能多次调用,这个不是SBR的问题,但通常也会伴随子程序多次调用出现更多问题,例如:
1,将使用了实际软元件的FB程序在OUT指令中的多个位置使用时,将变为双重线圈。
2,使用了实际的软元件的FB程序在多个位置被调用时,有可能无法正常动作。
归根到底,200Smart子程序的问题就是V区变量规划问题,它给设计者带来了更多和编程无关的管理工作。通常你需要准备几张纸来手动规划V区。无论是采用电子表格还是纸,随着设计的推进,修改V区修改已经调试好的模块是初学者面临的棘手而繁琐的工作。
在论坛上有篇帖子给我带来了一些解决200Smart如何才能让SBR具有类似FB背景数据块的实现方案思路。
具体来说就是分配出不同尺寸的连续的V区域,每个区域由一个索引来唯一定位,这样只要知道了索引就能定位这个区域。每个区域就是一个背景数据块,可以被SBR分配使用。
以ST20来说,V区共计8190个字节,如果背景DB需要使用3000个字节,那么开始地址大约是从VB5000开始的。这里面包括了之后要设计的管理段,实际分配给SBR使用的背景DB容量小于这个数量。这些关于DB开始位置、容量、以及适配不同型号PLC的V区*后地址的参数可以被修改而无需修改管理程序。
有解决思路,那如何知道子程序要使用哪个DB呢?
工作中我见过德国人的解决思路,需要在每次扫描过程中保证每个子程序按照既定的顺序来执行,不能出现条件调用子程序的情况存在。说白了就是在调用程序之前规划好的V区地址(假设VB800-VB900)存入FC中对应的临时变量中,FC中都使用该临时变量来进行逻辑运算或存储结果数据,*后再将携带着结果数据的临时变量写入到规划好的V区变量中(VB800-VB900)中,接下来的子程序使用的VB800-VB900也就是刚才调用子程序所使用的DB块了,接下来进行详细说明。
FC第一行Load Data
FC*后一行Save Data
FC中使用DB
SBR如何知道要使用哪个DB?需要在SBR接口的InOut处设计一个索引参数(DB_Index),这个索引定位了DB。如果该子程序是第一次被执行,索引接口变量就从索引资源变量(IndexSource)处取得当前可以使用的索引,索引资源自加一,以便下个SBR分配索引。如果不是第一次被调用,则不会再分配索引,而是使用原来的索引值,也就定位了同一个DB。
SBR内已经定位了DB,要怎么使用该DB呢?可以有两种使用方式:
一种是复制DB数据到SBR临时变量区,在Temp区使用的好处是可以用符号变量操作。使用完毕在退出子程序前把同一个Temp内容复制回DB区就实现了犹如在DB区中使用数据一样的效果。
第二种使用方式是直接在DB上操作数据,由于并不知道该SBR使用的DB地址,也就不能开始就设计好符号变量(事实上可以开始就设计好符号变量,后面有叙述。),所以直接使用就是用指针操作数据。由于指针操作存在很多不便性,所以这种方式主要用于使用指针显得很方便的场合,比如数组操作之类。
随着背景DB实现程序的设计推进,使用DB的方式这两种都有采用,针对不同的应用场景有不同的使用方式。比如,如果子程序的Temp区足以容纳需要的数据,就使用Temp操作;如果SBR的Temp容量小需要更多的存储区,就把多余的部分使用直接在DB中操作。如果接口比较多,需要使用更多的接口数量,就使用事先设计好DB中的符号变量,直接操作符号变量的方式,在遵循一定的设计顺序后就可以在该方式下也实现多个实例化。
实现的代价
要想实现上述功能,牺牲V区的一些空间和增加程序代码的数量、增加扫描时间是必然的代价,其中,牺牲V区空间其实是谈不上的,V区通常足够大,一般来说不用白不用,用了不白用。*主要的增加了代码体积和增加了扫描时间。在不增加其他功能,单纯一个做好的具有背景DB功能的空白模板,编译后块大小是2657字节。
200Smart的接口数量是有限的,只有16个IO接口,超出限制将不能正常添加形参。有人说可以把多个bit形参组合成Byte、Word、DWord之类,确实有效,但这个不是讨论的重点,所谓曲线救国毕竟是曲线呀。要怎么做呢?当然是使用指针了,也就是全局V区作为SBR的形参,可这还是需要人工规划不同的V区来适用不同的实例,没有解决根本问题。
既然已经有了可以自动分配和定位的DB,那么规划出几处特殊的DB来作为扩展接口的数据块。同一种类型的实例使用同一个DB,在DB中事先设计适用于同一个类型的接口变量形参,这样SBR内部直接使用DB内的变量形参,不用更改。那如何才能适用于同一类型的多个实例呢?我想到了子程序内部使用的Temp变量运行机制。200Smart子程序的临时变量区其实只有一个,是公共使用的。也有资料表明200Smart的Temp区一共14个,这涉及到200Smart的嵌套层级,这个和我想到的实现无关,只要想到这些就足够了。
我的实现方案是设计14个特殊用途的DB,用来作为Temp区使用,命名和子程序内的Temp冲突,但只要知道这个和子程序Temp是不同的概念就可以了。为了区别,以下暂且称为DBTemp吧。DBTemp的用途一方面是由于SBR内部还是有需要使用全局变量的情况出现无可避免,比如......(想不起来了,大概跟指针反引用有关),如果需要,则把这些数据用某个DBTemp内的预先定义的变量替代,只要使用前后让这个DBTemp进行FIFO操作,这样无论SBR何时执行都能够正确操作。这样就需要设计DBTemp的FIFO算法。设计14个DBTemp也和之前提到的嵌套有关,其实加入背景数据块后会降低嵌套深度,因为背景数据块管理程序需要调用一级子程序,如果需要使用背景DB则留给用户的嵌套深度是7级主循环嵌套调用。
考虑到其实实际项目中很少有需要使用全部14层级的情况,所以我安排用*后4个DBTemp作为SBR扩展IO接口。4个也就是只有4类子程序需要扩展接口。之所以是4个,主要是考虑到可能需要扩展的类型有限,使用原来的16个接口就可解决大多数类型的设计,这也是实验阶段目标所导致的,如果需要可以修改少量代码就可适配。
使用时首先按照FIFO原则先指定需要使用的DBTemp编号入队,以保护前面使用者的数据不丢失,然后给DBTemp内的SBR形参赋实际参数值,然后调用SBR。调用完毕处理DBTemp内的需要输出的参数,*后出队,恢复前面使用者的数据。这里涉及到接口类型,作为扩展接口的参数全部类同于InOut类型,Out和InOut需要调用完毕及时转存,而In需要设计者自己保证不会破坏原有数据。
那么DBTemp每个的容量选择多少合适呢?我设计了50个字节长度,这个可以在DBInit模块使用参数进行调整。
而背景数据块设计了255个DB可以使用,也是可以在DBInit模块使用参数进行调整。
管理模块的设计
管理堆表头设计
在V中分配的背景DB需要有一些空间来容纳管理变量,我把这些变量放置到了开头,称作管理DB的表头。
这些表头信息是:
pHeapHead 指向自身的堆指针,也是Heap首地址。
HeapStatus 堆状态信息。
DBCap 数据块预置容量
DBLen 数据块实际使用长度
pDBTerminal 数据块终点地址
pDBVector 数据块头指针
IndexSource 索引资源
指定数量的全局数据块索引
表头和DB之间的分隔符"#"
这些变量的作用涉及到许多技术实现细节,以后慢慢添加。
之后是数据块,不过头两个DB块是特殊用途DB的管理块,本质上这两个DB和之后的几个特殊用途DB都是数据块,只不过由管理程序使用,分配用户DB也不会用这几个块空间来分配。
1,数据块的结构
每个数据块的第一个字是DB容量,这个由DB分配程序来读写,用户不用操心。
之后是一个字节的DB标志符"FF",这个是方便调试而设计的,并无多大作用,也是设计遗留下来的东西,唯一的作用是可以帮助分辨DB开始。
这个标识符唯一不存在于接下来的一个DB。
然后才是真正的DB数据。
2,Temp块管理DB的设计
Temp块管理DB管理的其实不只Temp块,还硬塞进来了FIFO队列。 FIFO队列后是14个存放DBTemp的指针向量。DBTemp动态分配,这些指针表在DBTemp初始化时自动生成。由于设计也是逐步推进的,这里采用直接存放4字节的指针,而不是像接下来的用户DB指针表存放的是V编号,也就是指针的低字数据。
3,用户DB指针表(用户DB管理表)的设计
用户DB的定位采用的是遍历定位方式,但考虑许久还是专门设计出一个DB来存放用户DB开始的指针数据,这样DBIndex不是直接定位用户DB,而是首先定位这个表的数据,然后提取数据作为指针来直接定位用户DB。好处是代码量少些,也可能执行起来快速些。
用户DB不是一开始就规划好的,而是动态分配的,位置、尺寸都是动态由子程序自己所需DB尺寸自动生成的。
4,DBTemp块的设计
DBTemp共计14个,每个都具有用户指定的大小,比如50个字节。没有内部特殊结构,和普通DB没有区别。
用户可以使用的普通数据块
共计255个容量,每个的大小不同,由用户子程序决定
- 西门子1200/1500PLC不定长数组选择排序的运用编程 2024-11-14
- 别人想不到,PLC加密我用这一招 2024-11-14
- PLC输出点坏了怎么办,这几个方法都可以解决 2024-11-14
- 都说自己是PLC编程高手,这6个标准达到了吗?(附老工程师12条编程建议) 2024-11-14
- 电机坏的快,变频器在作妖?一文搞懂电机与变频器之间的关系 2024-11-14
- 分分钟教你S7-1200PLC定时器的使用 2024-11-14
- 触摸屏不通过PLC,直接控制变频器!老司机手把手教你如何实现 2024-11-14
- 西门子SCL编程实例:1200/1500PLC不定长数组选择排序的运用编程 2024-11-14
- 还搞不懂西门子PLC模拟量的接线?*全的解答都在这了 2024-11-14
- 图解PLC与变频器通讯接线,立马学会用PLC控制变频器 2024-11-14