1、代码
REGION 初始化值和确认状态
FOR #I := 1 TO 32 DO
#ST_Type[#I] := #EmptyType;
#ST_CS[#I] := #EmptyCS;
END_FOR;
FOR #I := 1 TO 64 DO
#RBT_Type[#I] := #EmptyType;
#RBT_CS[#I] := #EmptyCS;
END_FOR;
//初始化工位和机器人的车型和状态
IF #CFG_STNum < 0 OR #CFG_STNum > 32 OR #CFG_RbtNum < 0 OR #CFG_RbtNum > 64 THEN
#Err := 1;
GOTO Lable1 ;//工位和机器人数量设置超限
END_IF;
IF #CFG_MAX_P <= 0 OR #CFG_MAX_P >= 99 THEN
#CFG_MAX_P := #CFG_STNum * 2
;
END_IF;//最大指针数默认为工位数的两倍
IF #CFG_STNum>0 THEN
FOR #I := 1 TO #CFG_STNum DO
IF #HMI.ST_P[#I] = 0 THEN
#HMI.ST_P[#I] := 1
;
END_IF;
IF #HMI.ST_P[#I] > #CFG_MAX_P THEN
#Err := 1;
GOTO Lable1; //指针数值超限
END_IF;
END_FOR;
;
END_IF;
IF #CFG_RbtNum>0 THEN
FOR #I := 1 TO #CFG_RbtNum DO
IF #HMI.RBT_P[#I] = 0 THEN
#HMI.RBT_P[#I] := 1
;//初始化
END_IF;
IF #HMI.RBT_P[#I] > #CFG_MAX_P THEN
#Err := 1;
GOTO Lable1; //指针数值超限
END_IF;
END_FOR;
;
END_IF;
#Err := 0;
END_REGION
REGION 流水号计算
#RET:=RD_LOC_T(#SYS_Time); //系统时间
#SYS_Year := UINT_TO_DINT(#SYS_Time.YEAR);
#SYS_Month := USINT_TO_DINT(#SYS_Time.MONTH);
#SYS_Day := USINT_TO_DINT(#SYS_Time.DAY);
IF (#SYS_Time.HOUR = 0 AND #SYS_Time.MINUTE = 0 AND #SYS_Time.SECOND = 0)AND #SYS_Time.DAY <> 0 THEN
#Set_Type.Type.SN:= ( #SYS_Month * 100 + #SYS_Day)* 10000 ;
//计算每日流水号年月日信息(月*100+日)*10000
END_IF;
IF #Type_Real[100].Type.SN<>0 THEN
#Set_Type.Type.SN := #Type_Real[100].Type.SN; //启用MSE后 记录最后一次MES写入的流水号
END_IF;
END_REGION
REGION 指针查询,在最小指针大于1的时候集体减1
#Min := 99;
#Max := 0;
IF #CFG_STNum > 0 AND #CFG_STNum <= 32 THEN
FOR #I := 1 TO #CFG_STNum DO
IF #HMI.ST_P[#I] < #Min THEN
#Min := #HMI.ST_P[#I];
END_IF;
IF #HMI.ST_P[#I] > #Max THEN
#Max := #HMI.ST_P[#I];
END_IF;
END_FOR;
END_IF;
IF #CFG_RbtNum > 0 AND #CFG_RbtNum <= 64 THEN
FOR #I := 1 TO #CFG_RbtNum DO
IF #HMI.RBT_P[#I] < #Min THEN
#Min := #HMI.RBT_P[#I];
END_IF;
IF #HMI.RBT_P[#I] > #Max THEN
#Max := #HMI.RBT_P[#I];
END_IF;
END_FOR; //查询最大指针,最小指针
;
END_IF;
IF #Min >= 2 THEN
#Type_Real[1] := #EmptyType;
IF #CFG_STNum>0 THEN
FOR #I := 1 TO #CFG_STNum DO
#HMI.ST_P[#I] := #HMI.ST_P[#I] - 1;
END_FOR;
;
END_IF;
IF #CFG_RbtNum>0 THEN
FOR #I := 1 TO #CFG_RbtNum DO
#HMI.RBT_P[#I] := #HMI.RBT_P[#I] - 1;
END_FOR;
;
END_IF;
END_IF; //最小指针大于1时,清除第一个车型,指针全部减一
FOR #I := 1 TO 100 DO
IF #Type_Real[#I].Type.SN <> 0 OR #Type_Real[#I].Type.CT <> 0 THEN
#Num := #Num + 1;
END_IF;
END_FOR; //查询堆栈内共有多少数据
#Min_P := #Min;
#Max_P := #Max;
#Out_Num := #Num;
END_REGION
REGION 车型画面显示
IF #HMI.Page < 1 THEN
#HMI.Page := 1;
END_IF;
IF #HMI.Page > 10 THEN
#HMI.Page := 10;
END_IF; //翻页处理
FOR #I := 1 TO 10 DO
#HMI.Type_View[#I] := #Type_Real[#I + (#HMI.Page - 1) * 10];
END_FOR;
END_REGION
REGION 车型修改 指针在需要的时候减1
#Enable[2] := #Set_Type.Enable AND NOT #Enable[3];
#Enable[3] := #Set_Type.Enable;
IF #Enable[2] AND #HMI.Select > 0 AND NOT #PB_Insert AND #Set_Type.Type.Num = 0 THEN
#SelectNum := (#HMI.Page - 1) * 10 + #HMI.Select;
#Type_Real[#SelectNum] := #Set_Type; //车型修改
IF #Set_Type.Type.SN <> 0 AND #Set_Type.Type.CS <> 0 AND #Set_Type.Type.CT <> 0 THEN
#Set_Type.Type.SN += 1; //有效车型每次写入后流水号+1;
END_IF;
IF #Type_Real[#SelectNum].Type.SN = 0 THEN
FOR #I := 1 TO #CFG_STNum DO
IF #HMI.ST_P[#I] > #SelectNum THEN
#HMI.ST_P[#I] := #HMI.ST_P[#I] - 1;
END_IF;
END_FOR;
FOR #I := 1 TO #CFG_RbtNum DO
IF #HMI.RBT_P[#I] > #SelectNum THEN
#HMI.RBT_P[#I] := #HMI.RBT_P[#I] - 1;
END_IF;
END_FOR;
END_IF; //清除车型后,将指针大于当前被清除车型编号的工位指针和机器人指针减1
END_IF;
END_REGION
REGION 车型插入,指针在需要的时候加1
IF #Enable[2] AND #HMI.Select > 0 AND #PB_Insert AND #Set_Type.Type.Num = 0 AND #Type_Real[100]=#EmptyType
AND #Set_Type.Type.SN <> 0 AND #Set_Type.Type.CS <> 0 AND #Set_Type.Type.CT <> 0//选择插入车型,且插入车型信息完整
THEN
#SelectNum := (#HMI.Page - 1) * 10 + #HMI.Select;
FOR #I := 99 TO #SelectNum BY -1 DO
#Type_Real[#I + 1] := #Type_Real[#I];//车型后移
END_FOR;
#Type_Real[#SelectNum] := #Set_Type; //车型插入
#Set_Type.Type.SN += 1; //有效车型每次写入后流水号+1;
FOR #I := 1 TO #CFG_STNum DO
IF #HMI.ST_P[#I] >= #SelectNum THEN
#HMI.ST_P[#I] := #HMI.ST_P[#I] + 1;
END_IF;
END_FOR;
FOR #I := 1 TO #CFG_RbtNum DO
IF #HMI.RBT_P[#I] >= #SelectNum THEN
#HMI.RBT_P[#I] := #HMI.RBT_P[#I] + 1;
END_IF;
END_FOR;
//插入车型后,将指针大于等于当前被插入车型编号的工位指针和机器人指针加1
#PB_Insert := 0;
END_IF;
END_REGION
REGION 批量输入车型
(*此段程序只能从后面插入车型,不能实现批量删除或修改车型,如果启用此段程序则需要删除此区域下一段程序
IF #Set_Type.Enable THEN
#Enable[3] := 1;
;
END_IF;
IF NOT #Use_MES AND #HMI.Select = 0 AND #Enable[3] AND #Set_Type.Type.Num>0 AND #Set_Type.Type.SN>0 AND #Type_Real[100].Type.SN=0 THEN
#Type_Real[100] := #Set_Type;
#Set_Type.Type.SN +=1;
#Set_Type.Type.Num -= 1;
END_IF;
IF #Num=100 THEN
#Set_Type.Type.Num := 0;// 车型输入满后 设置车型数量清零
END_IF;
IF #Set_Type.Type.Num = 0 THEN
#Enable[3] := 0;
END_IF;
*)
IF #Set_Type.Enable THEN
#Enable[1] := 1;
;
END_IF;
WHILE #Set_Type.Type.Num > 0 AND #Set_Type.Type.Num <= 100 AND #Enable[1] AND #HMI.Select = 0 DO
#Type_Real[101 - #Set_Type.Type.Num].Type := #Set_Type.Type;
#Set_Type.Type.Num -= 1; //车型每次写入后NUM-1
IF #Set_Type.Type.SN <> 0 AND #Set_Type.Type.CS <> 0 AND #Set_Type.Type.CT <> 0 THEN
#Set_Type.Type.SN += 1; //有效车型每次写入后流水号+1;
END_IF;
END_WHILE;
#Enable[1] := 0;
END_REGION
REGION 空车型或异常车型清除 车型移动
FOR #I := 1 TO 99 DO
IF #Type_Real[#I].Type.SN = 0 OR (#Type_Real[#I].Type.CT = 0 AND #Type_Real[#I].Type.CS = 0) THEN
#Type_Real[#I] := #EmptyType;
;
END_IF; //异常车型清除
IF #Type_Real[#I].Type.SN = 0 AND #Type_Real[#I + 1].Type.SN <> 0 THEN
#Type_Real[#I] := #Type_Real[#I + 1];
#Type_Real[#I + 1] := #EmptyType;
END_IF; //车型移动
END_FOR;
END_REGION
REGION 清除Enable信号
IF #Out_Num > 0 THEN
FOR #I := 1 TO #Out_Num DO
#Type_Real[#I].Enable := 0
;
END_FOR;
;
END_IF;
END_REGION
REGION 通过指针寻车型
IF #CFG_STNum>0 THEN
FOR #I := 1 TO #CFG_STNum DO
IF #HMI.ST_P[#I] > 0 AND #HMI.ST_P[#I] < #CFG_MAX_P THEN
#ST_Type[#I] := #Type_Real[#HMI.ST_P[#I]];
#ST_CS[#I].NotDo := #ST_Type[#I].Type.CS = 1; //空过
#ST_CS[#I].Normal := #ST_Type[#I].Type.CS = 2; //正常
#ST_CS[#I].CheckPartOut := #ST_Type[#I].Type.CS = 3;//检测下线
#ST_CS[#I].CheckPartIn := #ST_Type[#I].Type.CS = 4;//检测上线
#ST_CS[#I].Bad := #ST_Type[#I].Type.CS = 5;//不良品
#ST_CS[#I].KD := #ST_Type[#I].Type.CS = 6;//KD件
#ST_CS[#I].TryOn := #ST_Type[#I].Type.CS = 16;//空循环
END_IF;
END_FOR;
;
END_IF;
IF #CFG_RbtNum>0 THEN
FOR #I := 1 TO #CFG_RbtNum DO
IF #HMI.RBT_P[#I] > 0 AND #HMI.RBT_P[#I] < #CFG_MAX_P THEN
#RBT_Type[#I] := #Type_Real[#HMI.RBT_P[#I]];
#RBT_CS[#I].NotDo := #RBT_Type[#I].Type.CS = 1; //空过
#RBT_CS[#I].Normal := #RBT_Type[#I].Type.CS = 2; //正常
#RBT_CS[#I].CheckPartOut := #RBT_Type[#I].Type.CS = 3;//检测下线
#RBT_CS[#I].CheckPartIn := #RBT_Type[#I].Type.CS = 4;//检测上线
#RBT_CS[#I].Bad := #RBT_Type[#I].Type.CS = 5;//不良品
#RBT_CS[#I].KD := #RBT_Type[#I].Type.CS = 6;//KD件
#RBT_CS[#I].TryOn := #RBT_Type[#I].Type.CS = 16;//空循环
END_IF;
END_FOR;
;
END_IF;
END_REGION
Lable1:
REGION 画面显示
FOR #I := 1 TO 10 DO
#HMI.NUM[#I] :=(#HMI.Page - 1) * 10 +#I ; //车型列表编号
END_FOR;
#HMI.ST_Num := #CFG_STNum;
#HMI.RBT_Num := #CFG_RbtNum;
#HMI.Min_P := #Min_P;
#HMI.Max_P := #Max_P;
#HMI.Out_Num := #Out_Num;
#HMI.Err[1] := #Err;
#TON(IN := #HMI.Enable,
PT := T#60S);
IF #TON.Q THEN
#HMI.Enable := 0
;
END_IF;
END_REGION
2、程序解释:
这段代码是用 PLC 编程语言(IEC 61131 - 3 标准语言)编写的,主要用于工业自动化场景中对工位、机器人以及车型相关信息的管理和处理。以下是对代码各部分的详细解释:
1、初始化值和确认状态
- 数组初始化:
- 两个
FOR
循环分别对#ST_Type
、#ST_CS
(共 32 个元素 )和#RBT_Type
、#RBT_CS
(共 64 个元素 )数组进行初始化,将每个元素赋值为#EmptyType
和#EmptyCS
,清空工位和机器人相关的车型和状态信息。
- 两个
- 参数合法性检查:
- 检查
#CFG_STNum
(工位数量配置 )和#CFG_RbtNum
(机器人数量配置 )是否在合理范围(0 - 32 和 0 - 64 )内,若超出范围则设置错误标志#Err
为 1,并跳转到Lable1
。 - 检查
#CFG_MAX_P
(最大指针数 ),若不在 0 - 99 范围,将其设置为#CFG_STNum
的两倍。
- 检查
- 指针初始化与检查:
- 对于工位和机器人的指针数组
#HMI.ST_P
和#HMI.RBT_P
,如果指针值为 0 则初始化为 1;若指针值超过#CFG_MAX_P
,则设置错误标志并跳转。最后将错误标志#Err
清零。
- 对于工位和机器人的指针数组
2、流水号计算
- 获取系统时间并转换:使用
RD_LOC_T
函数获取系统时间#SYS_Time
,并将其中的年、月、日转换为合适的数据类型存储在#SYS_Year
、#SYS_Month
、#SYS_Day
中。 - 流水号计算逻辑:
- 当系统时间为凌晨 0 点 0 分 0 秒且日期不为 0 时,根据月和日计算每日流水号的年月日部分,公式为
(#SYS_Month * 100 + #SYS_Day)* 10000
。 - 若
#Type_Real[100].Type.SN
(可能是某种真实车型记录的流水号 )不为 0,则使用该值作为流水号,用于记录 MES(制造执行系统)最后一次写入的流水号。
- 当系统时间为凌晨 0 点 0 分 0 秒且日期不为 0 时,根据月和日计算每日流水号的年月日部分,公式为
3、指针查询,在最小指针大于 1 的时候集体减 1
- 查找最大最小指针:通过
FOR
循环分别在工位指针数组#HMI.ST_P
和机器人指针数组#HMI.RBT_P
中查找最小和最大指针值,记录在#Min
和#Max
中。 - 指针调整:若最小指针
#Min
大于等于 2,将#Type_Real[1]
清空(赋值为#EmptyType
),然后将所有工位和机器人指针值减 1。最后统计#Type_Real
数组中有效数据(车型信息 )的数量存储在#Num
中,并记录最小、最大指针和有效数据数量到#Min_P
、#Max_P
、#Out_Num
。
4、车型画面显示
- 翻页处理:限制
#HMI.Page
(人机界面页码 )在 1 - 10 范围内,若超出则修正。 - 车型视图更新:通过
FOR
循环根据当前页码#HMI.Page
,将#Type_Real
数组中对应位置的车型信息赋值给#HMI.Type_View
数组,用于在人机界面显示当前页的车型信息。
5、车型修改 指针在需要的时候减 1
- 使能条件判断:根据
#Set_Type.Enable
(车型设置使能 )等条件计算#Enable[2]
和#Enable[3]
。 - 车型修改逻辑:当满足使能条件、有车型选择(
#HMI.Select > 0
)、非插入操作(NOT #PB_Insert
)且车型编号为 0 时,进行车型修改操作。将选中车型位置的#Type_Real
数组元素设置为#Set_Type
,若车型信息有效则流水号加 1。若修改后车型流水号为 0,将大于该车型编号的工位和机器人指针减 1。
6、车型插入,指针在需要的时候加 1
- 插入条件判断:当满足使能条件、有车型选择、是插入操作(
#PB_Insert
)、车型编号为 0、目标位置为空且车型信息完整时,执行车型插入操作。 - 车型插入逻辑:将插入位置及之后的车型后移,插入新车型并将流水号加 1。然后将大于等于插入位置编号的工位和机器人指针加 1,最后将插入按钮信号
#PB_Insert
清零。
7、批量输入车型
- 使能处理:根据
#Set_Type.Enable
设置#Enable[1]
。 - 批量输入逻辑:当车型数量配置
#Set_Type.Type.Num
在合理范围(1 - 100 )、使能且无车型选择时,通过WHILE
循环从后往前将车型信息依次写入#Type_Real
数组,每次写入后车型数量减 1,若车型信息有效则流水号加 1,最后将#Enable[1]
清零。
8、空车型或异常车型清除 车型移动
- 异常车型清除:通过
FOR
循环遍历#Type_Real
数组,若车型流水号为 0 或车型类型和状态都为 0,则将该车型元素赋值为#EmptyType
。 - 车型移动:若当前车型流水号为 0 且下一个车型流水号不为 0,则将下一个车型信息前移,清空原位置车型信息。
9、清除 Enable 信号
若有效车型数量 #Out_Num
大于 0,通过 FOR
循环将 #Type_Real
数组中所有有效车型的使能信号 Enable
清零。
10、通过指针寻车型
- 工位车型查找:当有工位配置(
#CFG_STNum > 0
)时,通过FOR
循环遍历工位指针数组#HMI.ST_P
,若指针值在有效范围(大于 0 小于#CFG_MAX_P
),则根据指针值从#Type_Real
数组获取对应车型信息赋值给#ST_Type
,并根据车型状态字段设置#ST_CS
数组中各状态标志。 - 机器人车型查找:类似地,当有机器人配置(
#CFG_RbtNum > 0
)时,对机器人指针数组#HMI.RBT_P
进行相同操作,获取车型信息并设置状态标志。
11、画面显示
- 车型列表编号设置:通过
FOR
循环根据当前页码#HMI.Page
计算并设置人机界面车型列表编号#HMI.NUM
数组。 - 界面参数更新:将工位数量、机器人数量、最小指针、最大指针、有效数据数量和错误标志等信息更新到人机界面相关变量中。
- 定时器处理:使用定时器
#TON
,当使能信号#HMI.Enable
为ON
持续 60 秒后,将其清零。