很多时候大家会遇到多台设备的启停,想根据设备的运行时间来启停设备的需求,前面我发了一个讨论贴,现在我已经写了部分代码 我写了后面编程的思路和算法 只是程序还没有时间去完善,我会在该贴不停的更新程序请大家留意。若测试有什么问题和BUG请后面留言。
20170102:修改了时间累计部分程序,原来的寻址有点问题,并增加了个冒泡程序
20170119:把原来的程序修改了一下 排序需要有条件才排序,为了提高FOR循环的效率 只用秒来
累计运行时间,因为每个指令都有指令执行时长,故需要注意设备的总数。
程序我会继续空了再更新,欢迎测试
源代码如下:
//######################################################
//设备根据运行时间的长短进行启停
//该程序支持多个设备可修改参数来决定
//EBC-LW 20170119
//#####################################################
FUNCTION_BLOCK FB14
TITLE = 'DRUN'
//
// Block Comment...
//
VERSION: '1.0'
AUTHOR: EBC_LW
NAME: DRUN
FAMILY: EBC
// -------输入------------------------------
VAR_INPUT
RUN_DB:BLOCK_DB; //设备的运行状态的数据块
(*DB块数据格式
tag1 bool
tag2 bool
tag3 bool
.
.
.
*)
NUM:DINT:=10;//初始化设备的数量为10台
ST:BOOL;//开启时间最短的设备
STO:BOOL;//关闭时间最长的设备
START_PX:BOOL:=0;//开始排序使能
REST:BOOL;//复位但不对时间进行复位
END_VAR
// -------输出------------------------------
VAR_OUTPUT
//START_P:ARRAY[1..NUM_ALL] OF BOOL;//启动脉冲
//STOP_P:ARRAY[1..NUM_ALL] OF BOOL;//停止脉冲
//START:ARRAY[1..NUM_ALL] OF BOOL;//启动停止
END_VAR
// -------输入输出------------------------------
VAR_IN_OUT
END_VAR
// -------常量------------------------------
CONST
NUM_ALL:=20;//默认20台设备
END_CONST
// -------临时------------------------------
VAR_TEMP
PN:BOOL;//
START_PX_PN:BOOL;//开始排序使能脉冲
FLAG:BOOL;
PX_TEMP1:DINT;
PX_TEMP2:DINT;
I:DINT;//设备循环
J:INT;
K:INT;
L:INT;
M:DINT;
N:DINT;
S:INT;//复位使用
X:INT;//复位使用
Z:INT;
NUMBER:DINT;//用于初始化设备编号
HH_TEMP:REAL;
MM_TEMP:REAL;
END_VAR
// -------静态变量------------------------------
VAR
REMOVE:ARRAY[1..NUM_ALL]OF BOOL;//设定要排除进行排序的设备
CLE_TIME:ARRAY[1..NUM_ALL]OF BOOL;//清除时间累计
DEVICE:
ARRAY[1..NUM_ALL] OF STRUCT//存放设备运行时间的DB块
ID:DINT;//设备编号
SS: DINT;//秒 设备运行的总秒数 使用DINT 数据范围 -2_147_483_648 to 2_147_483_647
END_STRUCT;
TB:ARRAY[1..2,1..NUM_ALL] OF DINT;//排序用的表格
OLD_VAL:BOOL;//边沿检测的上一次的值
OLD_START_PX:BOOL;//排序使能的上一次的值
NUMBER_INITIALIZE:BOOL:=1;//用于初始化设备编号,程序第一次时默认为1,执行后不在进行。
START_P:ARRAY[1..NUM_ALL] OF STRUCT
START:BOOL;//启动脉冲
STOP:BOOL;//停止脉冲
END_STRUCT;
END_VAR
//#######################################脉冲及初始化#######################################
PN:=M2.5&(NOT OLD_VAL);//设置CPU时间存储器时间存储器为2,获得秒脉冲
OLD_VAL:=M2.5;
START_PX_PN:=START_PX&(NOT OLD_START_PX);//排序使能脉冲
OLD_START_PX:=START_PX;
//初始化设备编号
IF NUMBER_INITIALIZE THEN
FOR NUMBER:=1 TO NUM BY 1 DO
DEVICE[NUMBER].ID:=NUMBER;
END_FOR;
END_IF;
NUMBER_INITIALIZE:=0;//初始化设备编号后复位不再进行对设备编号再次执行初始化工作
//###############################设备的运行时间累计##########################################
// 运行时间累计可单独对设备进行时间复位
//运行时间累计
I:=0;//循环体循环次数
J:=0;//数据表中的位
K:=0;//数据表中的字节
L:=0;
M:=0;
N:=0;
IF PN THEN
FOR I:= 1 TO NUM BY 1 DO
J:=J+1;
IF J>7 THEN
J:=0;
K:=K+1;
END_IF;
IF RUN_DB.DX[K,(J-1)] THEN//读取设备运行状态 若为1则进行累计时间
//时间累计 采用秒
DEVICE[I].SS:=DEVICE[I].SS+1;
END_IF;
//如果秒数达到2147483648避免溢出或人工清零自动清零
IF DEVICE[I].SS >=2147483647 OR CLE_TIME[I] THEN
DEVICE[I].SS:=0;
END_IF;
END_FOR;
END_IF;
//###################################排序程序###########################################
//将设备编号和设备的运行时间写入二维数组准备进行排序
//当排序条件满足时才进行排序(脉冲)
IF START_PX_PN THEN
FOR L:= 1 TO 2 BY 1 DO
FOR M:= 1 TO NUM BY 1 DO
CASE L OF
1://将设备编号写到第一行
TB[L,M]:=DEVICE[M].ID;//
2://将设备运行时间写到第二行
TB[L,M]:=DEVICE[M].SS;
ELSE:
EXIT ;//其他值则退出
END_CASE;
END_FOR;
END_FOR;
//这里采用冒泡算法进行对二维数组排序
REPEAT
FLAG:=FALSE;
FOR N:= NUM TO 1 BY -1 DO
IF TB[2,N-1]>TB[2,N] THEN
//对时间进行排序
PX_TEMP1:=TB[2,N];
TB[2,N]:=TB[2,N-1];
TB[2,N-1]:=PX_TEMP1;
//交换设备编号的位置和排序的时间一致
PX_TEMP2:=TB[1,N];
TB[1,N]:=TB[1,N-1];
TB[1,N-1]:=PX_TEMP2;
FLAG:=TRUE;
END_IF;
END_FOR;
UNTIL NOT FLAG
END_REPEAT;
END_IF;
//#######################复位(设备编号机排序用表格)##################################
IF REST THEN
FOR S:= 1 TO NUM_ALL BY 1 DO
//设备编号初始重新初始化
DEVICE[S].ID:=S;
//对排序用表格清零操作
FOR X:= 1 TO 2 BY 1 DO
TB[X,S]:=0;
END_FOR;
END_FOR;
END_IF;
//#########################################################################
//根据表格读取出来的位置出来的编号就能知道哪一台运行时间最长,次长,运行时间最短,次短的是那一台。
//这里取时间的设备出来
(*
时间最长的设备编号 应该是TB[1,NUM]
时间次长的设备编号 应该是TB[1,NUM-1]
.
.
.
时间次短的设备编号 应该是TB[1,2]
时间最短的设备编号 应该是TB[1,1]
这里根据自己的需求编写代码
*)
//这里以停止运行时间最长的,开启时间最短的为例
END_FUNCTION_BLOCK