一、主程序里对通讯程序的调用
1、主程序 FBD编程
二、实例化2个容器,配置IP地址、端口
1、通讯程序内容,FBD编程
2、容器1 变量声明
PROGRAM PRG_Cell2_SetupControl_GEN2_Ass1_V2_0
(*---------------------------------------------*)
(*IN variables*)
(*---------------------------------------------*)
VAR_INPUT
sIn_CapacityNo : STRING[cCapNameLen]; //容器数量
sIn_IpAddress : STRING; //IP地址 PLC作为服务器
uiIn_Port : UINT; //端口
END_VAR
(*---------------------------------------------*)
(*OUT variables*)
(*---------------------------------------------*)
VAR_OUTPUT
bOUT_SetupComplete :BOOL;
bOUT_OrderDone :BOOL;
bOUT_Connected :BOOL;
END_VAR
(*---------------------------------------------*)
(*IN/OUT variables*)
(*---------------------------------------------*)
VAR_IN_OUT
sInOut_BarcodeScanner1 : STRING[33];
sInOut_BarcodeMachine : STRING[33];
stInOut_arst_SetupControl : ST_SetupControl_ITAC_V2_0;
stInOut_HMI_SetupControl : ST_HMI_SetupControl;
END_VAR
(*---------------------------------------------*)
(*Local Constants*)
(*---------------------------------------------*)
VAR CONSTANT
iNumFeeders : INT :=1;
END_VAR
(*---------------------------------------------*)
(*Local variables*)
(*---------------------------------------------*)
VAR
i :INT;
j :INT;
MMC_COM :FB_MMC_COM_V2_5_0;
Station_INPUT :FB_INPUT_V2_2;
Station_RemoveBIN :FB_RemoveBIN_V1_0;
afb_Station_Feeder :ARRAY[1..iNumFeeders] OF FB_FEEDER_V2_0;
ab_FeederFull :ARRAY[1..iNumFeeders] OF BOOL;
ab_Feeder_SetupControlOK :ARRAY[1..iNumFeeders] OF BOOL;
iFeeder:INT;
bTempUnlockFeeder: BOOL;
END_VAR
(*---------------------------------------------*)
(*Lokal temp variables*)
(*---------------------------------------------*)
VAR
END_VAR
3、容器1程序代码
(* Get barcode data *)
(*---------------------------------------------------------*)
IF sInOut_BarcodeScanner1 <> '' THEN
stInOut_arst_SetupControl.ScannerInput.sBarcodeRead := sInOut_BarcodeScanner1;
sInOut_BarcodeScanner1 := '';
END_IF;
(*
IF sBarcodeReadScanner2 <> '' THEN
stInOut_arst_SetupControl..ScannerInput.sBarcodeRead := sBarcodeReadScanner2;
sBarcodeReadScanner2 := '';
END_IF;*)
IF sInOut_BarcodeMachine <> '' THEN
stInOut_arst_SetupControl.ScannerInput.sBarcodeRead := sInOut_BarcodeMachine;
sInOut_BarcodeMachine := '';
END_IF;
(*---------------------------------------------*)
(* Call Input Scanner *)
(*---------------------------------------------*)
(* Parameter *)
(*Cell1_INPUT.FAMILY_FEEDER[1] := M300.FEEDER_POS[1]; (* material family positions *)*)
Station_INPUT.STATION := ADR(stInOut_arst_SetupControl); (* to main data structure *)
Station_INPUT();
(*---------------------------------------------------------*)
(* MMC communication *)
(*---------------------------------------------------------*)
MMC_COM (ptIN_STATION_ITAC := ADR(stInOut_arst_SetupControl.ITAC));
stInOut_arst_SetupControl.ITAC.sCapacityNo := sIn_CapacityNo;
stInOut_arst_SetupControl.ITAC.MMC_Comm.CONVERSION_INTERFACE.uiPort := uiIn_Port;
stInOut_arst_SetupControl.ITAC.MMC_Comm.CONVERSION_INTERFACE.sAddress := sIn_IpAddress;
bOUT_Connected := stInOut_arst_SetupControl.ITAC.MMC_Comm.CONVERSION_INTERFACE.bConnected;
(*---------------------------------------------------------*)
(*FEEDER *)
(*---------------------------------------------------------*)
actFeeder();
(*---------------------------------------------------------*)
(*HMI-Interface *)
(*---------------------------------------------------------*)
stInOut_HMI_SetupControl.bDoneFeeder := stInOut_arst_SetupControl.ScannerInput.bDoneFeeder;
stInOut_HMI_SetupControl.bDoneMaterial := stInOut_arst_SetupControl.ScannerInput.bDoneMaterial;
stInOut_HMI_SetupControl.bDoneOrder := stInOut_arst_SetupControl.ScannerInput.bDoneOrder;
stInOut_HMI_SetupControl.bSetupComplete := stInOut_arst_SetupControl.bSetupComplete;
stInOut_HMI_SetupControl.sBarcodeRead := stInOut_arst_SetupControl.ScannerInput.sBarcodeRead;
stInOut_HMI_SetupControl.sErrText := stInOut_arst_SetupControl.ScannerInput.sErrText;
stInOut_HMI_SetupControl.szBarcodeFeeder := stInOut_arst_SetupControl.ScannerInput.szLastScanBarcodeFeeder;
stInOut_HMI_SetupControl.szBarcodeMat := stInOut_arst_SetupControl.ScannerInput.szLastScanBarcodeMat;
stInOut_HMI_SetupControl.szBarcodeOrder := stInOut_arst_SetupControl.ScannerInput.szLastScanBarcodeOrder;
stInOut_HMI_SetupControl.iMaxFeederStation := cUsedFeederStation;
FOR i := 1 TO cMaxFeederStation DO
stInOut_HMI_SetupControl.FEEDER[i].bFeederON := stInOut_arst_SetupControl.FEEDER_POS[i].HandShake.bFeederON;
stInOut_HMI_SetupControl.FEEDER[i].bFeederSetupIO := stInOut_arst_SetupControl.FEEDER_POS[i].HandShake.bFeederSetupIO;
stInOut_HMI_SetupControl.FEEDER[i].bFeederSetupNIO := stInOut_arst_SetupControl.FEEDER_POS[i].HandShake.bFeederSetupNIO;
stInOut_HMI_SetupControl.FEEDER[i].sMatNo := stInOut_arst_SetupControl.FEEDER_POS[i].ACT_SETUP.sMatNo;
END_FOR;
(*---------------------------------------------------------*)
(*Setup Complete *)
(*---------------------------------------------------------*)
bOUT_SetupComplete := stInOut_arst_SetupControl.bSetupComplete;
(*---------------------------------------------------------*)
(*Order Done to machine *)
(*---------------------------------------------------------*)
bOUT_OrderDone := stInOut_arst_SetupControl.ScannerInput.bDoneOrder;
4、容器1代码解读
1. 条形码扫描处理
IF sInOut_BarcodeScanner1 <> '' THEN
stInOut_arst_SetupControl.ScannerInput.sBarcodeRead := sInOut_BarcodeScanner1;
sInOut_BarcodeScanner1 := '';
END_IF;
- 功能:检测条形码扫描仪输入,将扫描结果存入数据结构
stInOut_arst_SetupControl
,并清空输入缓冲区。 - 多扫描仪支持:代码支持多个扫描仪(Scanner1、Scanner2、Machine),但 Scanner2 被注释,实际使用 Scanner1 和 Machine。
2. 输入扫描处理
Station_INPUT.STATION := ADR(stInOut_arst_SetupControl);
Station_INPUT();
- 功能:调用
Station_INPUT
功能块,传入数据结构指针,处理扫描到的条形码数据(如解析物料、订单、供料器信息)。
3. MMC 通信控制
MMC_COM (ptIN_STATION_ITAC := ADR(stInOut_arst_SetupControl.ITAC));
- 功能:通过
MMC_COM
功能块实现与制造执行系统(MES)或上位机的通信,同步生产数据(如产能编号、IP 地址、端口)。 - 参数设置:配置 ITAC 通信模块的参数,包括容量编号、IP 地址和端口。
4. 供料器管理
actFeeder();
- 功能:调用
actFeeder()
函数,控制生产线的供料器(如激活、校准、物料分配)。
5. 人机界面(HMI)数据同步
stInOut_HMI_SetupControl.bDoneFeeder := stInOut_arst_SetupControl.ScannerInput.bDoneFeeder;
// 其他HMI变量同步...
- 功能:将核心数据结构
stInOut_arst_SetupControl
中的状态和结果同步到 HMI 专用数据结构stInOut_HMI_SetupControl
,供操作人员查看。 - 同步内容:包括条形码扫描状态、错误信息、供料器状态(如是否在线、物料编号)等。
6. 循环同步供料器数据
FOR i := 1 TO cMaxFeederStation DO
stInOut_HMI_SetupControl.FEEDER[i].bFeederON := stInOut_arst_SetupControl.FEEDER_POS[i].HandShake.bFeederON;
// 其他供料器变量同步...
END_FOR;
- 功能:遍历所有供料器(1 到最大数量),将每个供料器的状态(如是否开启、物料编号)同步到 HMI。
7. 输出状态信号
bOUT_SetupComplete := stInOut_arst_SetupControl.bSetupComplete;
bOUT_OrderDone := stInOut_arst_SetupControl.ScannerInput.bDoneOrder;
- 功能:将系统状态输出到外部信号,用于触发后续操作(如生产线启动、订单完成通知)。
三、Station_INPUT 实例
1、变量声明代码 station_INPUT 实例化 FUNCTION_BLOCK_FB_INPUT_V2_2
FUNCTION_BLOCK FB_INPUT_V2_2
VAR CONSTANT
cStepTime :TIME := t#60m;
cTimeoutMMC :TIME := t#10s;
cTimeoutError :TIME := t#10s;
cTimeoutUser :TIME := T#10S;
cTimeoutMessage :STRING := 'Timout MMC communication';
cMessageUser1 :STRING := 'Waiting for feeder scan Timout -> ABORT';
cMessageUser2 :STRING := 'Waiting for Material scan Timout -> ABORT';
cErrStep :UINT := 499;
END_VAR
VAR_INPUT
STATION :POINTER TO ST_SetupControl_ITAC_V2_0;
FAMILY_FEEDER :ARRAY[1..cMaxFamilyFeeder] OF ST_FEEDER_POS;
END_VAR
VAR_IN_OUT
END_VAR
VAR
iBCLen :INT;
uiBCtype :UINT; (*Byte 12 of the Barcode which describes the type *)
uiBCtypeMat :UINT;
bMatFound :BOOL;
rCode,i,j,k,m,n,w :INT;
feederPreSetup :INT;
iStep,iOldStep :INT;
FB_TON_StepTime :TON;
tTimeInTheStep :TIME;
(* Internal *)
arFeederBomIdx :ARRAY[1..cMaxFeederStation] OF UINT;
sArg1 : STRING[MAX_STRING_LENGTH];
sArg2 : STRING[MAX_STRING_LENGTH];
sArg3 : STRING[MAX_STRING_LENGTH];
(* used FBs *)
FormatString :FB_FormatString;
bTemp: BOOL;
btestOrderBarcode: BOOL;
bTestMaterial: BOOL;
END_VAR
2、Station_INPUT 程序代码
(*---------------------------------------------*)
(* Check Times *)
(*---------------------------------------------*)
actTimingSystem();
(*---------------------------------------------*)
(* Check Scanner *)
(*---------------------------------------------*)
actBarcodeSwitch();
actCheckSetupComplete();
(*actVerifyPreSetupAktiv;*)
IF NOT STATION^.bMoveSetupActive THEN
actCheckMoveSetupActive();
END_IF
(*---------------------------------------------*)
(* INIT indices *)
(*---------------------------------------------*)
FOR i := 1 TO cMaxFeederStation DO arFeederBomIdx[i] := 0; END_FOR;
(*---------------------------------------------*)
(* MainLoop *)
(*---------------------------------------------*)
CASE iStep OF
0: (* INIT *)
STATION^.ScannerInput.uiCodeSelect :=0;
STATION^.ScannerInput.bError :=FALSE;
STATION^.ScannerInput.sErrText :='';
STATION^.ScannerInput.sBarcodeRead :=''; (* clear scan, operator needed to start from the beginning *)
iStep := iStep+1;
(*---------------------------------------------*)
(* MAIN DISTRIBUTION HERE *) //在这儿主分配
(*---------------------------------------------*)
1: (* wait for something *)
(*IF bMove_PRE_TO_ACT_SETUP THEN
bMove_PRE_TO_ACT_SETUP := FALSE;
iStep := 400;
RETURN;
END_IF;*)
actCheckSetupComplete(); (*11.11.2018 SD add CheckSetupComplete*)
IF NOT STATION^.bMoveSetupActive THEN
actCheckMoveSetupActive();
END_IF
(*actVerifyPreSetupAktiv;*)
CASE STATION^.ScannerInput.uiCodeSelect OF
0: (* Wait *)
IF tTimeInTheStep > cTimeoutUser THEN
STATION^.ScannerInput.bPreSetup := FALSE;
END_IF;
;
1: (* BarCode = Feeder *)
STATION^.ScannerInput.sErrText := 'Warning: Scan Material FIRST!';
iStep := cErrStep;
2: (* BarCode = Order Code *)
iStep := 5;
3: (* BarCode = Material Code *)
iStep := 100;
4: (* BarCode = PreSetup Code *) (*19.11.2019 SD add PreSetup*)
STATION^.ScannerInput.bPreSetup := TRUE;
STATION^.ScannerInput.uiCodeSelect := 0; (* unlock Scanner *)
iStep := 0 ;
ELSE
STATION^.ScannerInput.sErrText := 'PROGRAM ERROR: unknown Scanner idx';
iStep := cErrStep;
END_CASE;
(*---------------------------------------------*)
(* SUB Scan Order *) //子订单码
(*---------------------------------------------*)
5:
STATION^.ScannerInput.bDoneOrder := FALSE;
STATION^.ScannerInput.szLastScanBarcodeFeeder := '';(*11.10.2018 SD add LastScan*)
STATION^.ScannerInput.szLastScanBarcodeMat := '';(*11.10.2018 SD add LastScan*)
STATION^.ScannerInput.bDoneMaterial := FALSE;
STATION^.ScannerInput.bDoneFeeder := FALSE;
actPrepareOrder();
6: (* wait for answer *)
IF STATION^.ITAC.MMC_Comm.SET_OBC.bRecACK THEN
IF STATION^.ITAC.MMC_Comm.SET_OBC.sOrderBarCodeREC <> STATION^.ITAC.MMC_Comm.SET_OBC.sOrderBarCode THEN
sArg1 := STATION^.ITAC.MMC_Comm.SET_OBC.sOrderBarCodeREC;
sArg2 := STATION^.ITAC.MMC_Comm.SET_OBC.sOrderBarCode;
FormatString( sFormat := '06| SCAN_ORDER: Recieved WTRCode [%s] is not matching with sent WTRCode [%s]',
arg1 := F_STRING (sArg1),
arg2 := F_STRING (sArg2),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
END_IF;
iStep := iStep+1; (* Order = IO -> continue *)
ELSIF STATION^.ITAC.MMC_Comm.SET_OBC.bError THEN (* Set Error *)
sArg1 := STATION^.ITAC.MMC_Comm.SET_OBC.sErrText;
FormatString( sFormat := '03| SCAN_ORDER: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
7: (* check Order data *)
actPrepareGetWBM();
8: (* Wait for ACK WBM *)
IF STATION^.ITAC.MMC_Comm.GET_WBM.bRecACK
AND NOT STATION^.ITAC.MMC_Comm.GET_WBM.bError
THEN (* Check GET WBM sucessfully done *)
(******)
(*---------------------------------------------*)
(* BOM input completed now transfer to feeder *)
(*---------------------------------------------*)
(* clear old BOB *)
(* Attention, 1. capcity is used for verification *)
IF STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[1].sCapacity = STATION^.ITAC.sCapacityNo THEN
FOR j := 1 TO cMaxFeederStation DO
FOR k := 1 TO cMaxAltMaterial DO
STATION^.FEEDER_POS[j].BOM[k].sMatNo := '';
STATION^.FEEDER_POS[j].BOM[k].sMatText := '';
STATION^.FEEDER_POS[j].BOM[k].sSupplierNumber := '';
END_FOR;
END_FOR;
ELSE
sArg1 := STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[1].sCapacity;
sArg2 := STATION^.ITAC.sCapacityNo;
FormatString(sFormat := '08| GET_WBM decoder: Capacity in BOM [%s] <> machine [%s]',
arg1 := F_STRING (sArg1),
arg2 := F_STRING (sArg2),
sOut => STATION^.ITAC.MMC_Comm.GET_WBM.sErrText);
STATION^.ITAC.MMC_Comm.GET_WBM.bError := TRUE;
RETURN;
END_IF;
(* now store material on feeder *)
FOR k := 1 TO cMAxMMC_BOM DO
(* Check Capacity *)
IF STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].sCapacity = STATION^.ITAC.sCapacityNo THEN
CASE STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder OF
1..cMaxFeederStation:
(* BOM idx!!! *)
arFeederBomIdx[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder] := arFeederBomIdx[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder] + 1; (* increase BOM index *)
IF arFeederBomIdx[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder] <= cMaxAltMaterial THEN
j := arFeederBomIdx[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder];
STATION^.FEEDER_POS[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder].BOM[j].sMatNo := STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].sMatSNR;
STATION^.FEEDER_POS[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder].BOM[j].sMatText := STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].sMatText;
(* Take over actual Order *)
STATION^.FEEDER_POS[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder].HandShake.bBOMCheckReady := TRUE;
STATION^.ITAC.sOrder := STATION^.ITAC.MMC_Comm.GET_WBM.sOrderBarCodeRecv;
ELSE
(* Error Message *)
rCode:= cMaxAltMaterial;
FormatString(sFormat := '09| GET_WBM decoder: Feeder [%d] too many materials found [%d] max [%d]',
arg1 := F_UINT (STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder),
arg2 := F_UINT (arFeederBomIdx[STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].uiFeeder]),
arg3 := F_INT (rCode),
sOut => STATION^.ITAC.MMC_Comm.GET_WBM.sErrText);
STATION^.ITAC.MMC_Comm.GET_WBM.bError := TRUE;
RETURN;
END_IF;
END_CASE;
ELSIF STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].sCapacity <>'' THEN
(* Error Message *)
sArg1 := STATION^.ITAC.MMC_Comm.GET_WBM.starBOMItems[k].sCapacity;
sArg2 := STATION^.ITAC.sCapacityNo;
FormatString(sFormat := '10| GET_WBM decoder: Capacity in BOM [%s] <> machine [%s]',
arg1 := F_STRING (sArg1),
arg2 := F_STRING (sArg2),
sOut => STATION^.ITAC.MMC_Comm.GET_WBM.sErrText);
STATION^.ITAC.MMC_Comm.GET_WBM.bError := TRUE;
RETURN;
END_IF;(* capacity check *)
END_FOR; (* k *)
(******)
STATION^.ScannerInput.bDoneOrder := TRUE;
iStep := iStep + 1;
ELSIF STATION^.ITAC.MMC_Comm.GET_WBM.bError THEN
sArg1 := STATION^.ITAC.MMC_Comm.GET_WBM.sErrText;
FormatString( sFormat := '06| SCAN_ORDER: %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
9: (* Check actual feeder setup *)
actVerifyFeederSetup();
iStep := iStep+1;
10: (* Check Setup Complete *)
(*actCheckSetupComplete;*)
IF STATION^.bSetupComplete THEN
(* Set ACT *)
STATION^.ITAC.MMC_Comm.SET_ACT.bSendRequest := TRUE; (*11.10.2018 SD add SET_ACT*)
iStep := iStep+1;
END_IF;
iStep := 0 ; (* ReLoop *)
11: (* Wait for answer from ACK ACT *)(*11.10.2018 SD add SET_ACT*)
IF STATION^.ITAC.MMC_Comm.SET_ACT.bRecACK THEN
iStep := iStep+1;
ELSIF STATION^.ITAC.MMC_Comm.SET_ACT.bError THEN (* Set Error *)
STATION^.ScannerInput.bError := TRUE;
sArg1 := STATION^.ITAC.MMC_Comm.SET_ACT.sErrText;
FormatString( sFormat := '11| SCAN_ORDER: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
12:
iStep := 0 ; (* ReLoop *)
(*---------------------------------------------*)
(* SUB Scan Material *)
(*---------------------------------------------*)
100: (* Scan MatCode *)
STATION^.ScannerInput.bDoneMaterial := FALSE;
STATION^.ScannerInput.szLastScanBarcodeFeeder := '';
STATION^.ScannerInput.bDoneFeeder := FALSE;
actPrepareMaterial();
101: (* wait for answer *)
IF STATION^.ITAC.MMC_Comm.GET_MB.bRecACK THEN
iStep := iStep+1;
ELSIF STATION^.ITAC.MMC_Comm.GET_MB.bError THEN (* Set Error *)
STATION^.ScannerInput.bError := TRUE;
sArg1 := STATION^.ITAC.MMC_Comm.GET_MB.sErrText;
FormatString( sFormat := '03| SCAN_MAT: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
102:
STATION^.ScannerInput.bDoneMaterial := TRUE;
STATION^.ScannerInput.uiCodeSelect := 0; (* unlock Scanner *)
iStep := 200 ;
(*---------------------------------------------*)
(* SUB Scan Feeder *)
(*---------------------------------------------*)
200:(* wait feeder *)
(*----------------------------------------------*)
(* standard feeder *)
(*----------------------------------------------*)
IF STATION^.ScannerInput.uiCodeSelect = 1 AND NOT STATION^.ScannerInput.bPreSetup THEN
(* Save feeder number *)
STATION^.ScannerInput.uiMaterialFeeder := STRING_TO_UINT(RIGHT(STATION^.ScannerInput.szBarcodeFeeder,3));
iStep := iStep+1;
END_IF;
(*----------------------------------------------*)
(* pre-feeder *)
(*----------------------------------------------*)
IF STATION^.ScannerInput.uiCodeSelect = 1 AND STATION^.ScannerInput.bPreSetup THEN
(* Save feeder number *)
STATION^.ScannerInput.uiMaterialFeeder := STRING_TO_UINT(RIGHT(STATION^.ScannerInput.szBarcodeFeeder,3));
iStep := 300;
END_IF;
STATION^.ScannerInput.uiCodeSelect := 0;
IF tTimeInTheStep > cTimeoutUser THEN
STATION^.ScannerInput.sErrText := cMessageUser1;
iStep := cErrStep;
END_IF;
201:
actCheckMaterial();
202: (* check feeder assigmnment, right NO *)
actFeederAssignment();
203: (* Material & Feeder IO *) (*21.11.2019 SD CheckFamiliy and Feeder not possible until now*)
actCheckFamilyAndVendor();
204: (* prepare request message *) (*16.11.2018 SD add act PrepareFeeder - Set MB)*)
actPrepareFeeder();
205: (* wait answer *)
IF STATION^.ITAC.MMC_Comm.SET_MB.bRecACK THEN
iStep := iStep+1;
ELSIF STATION^.ITAC.MMC_Comm.SET_MB.bError THEN
sArg1 := STATION^.ITAC.MMC_Comm.SET_MB.sErrText;
FormatString( sFormat := '03| SCAN_FEEDER: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
206: actCheckFeeder();
207:
(*---------------------------------------------*)
(* all prechecks passed, now accept material *)
(*---------------------------------------------*)
STATION^.FEEDER_POS[STATION^.ScannerInput.uiMaterialFeeder].ACT_SETUP := STATION^.FEEDER_POS[STATION^.ScannerInput.uiMaterialFeeder].INPUT.Material;
STATION^.ScannerInput.bDoneFeeder := TRUE;
STATION^.FEEDER_POS[STATION^.ScannerInput.uiMaterialFeeder].HandShake.bFeederSetupIO := TRUE;
STATION^.FEEDER_POS[STATION^.ScannerInput.uiMaterialFeeder].HandShake.bFeederSetupNIO := FALSE;
iStep := iStep+1;
208:(* Check Setup Complete *)
(*actCheckSetupComplete;*)
IF STATION^.bSetupComplete THEN
(* Set ACT *)
STATION^.ITAC.MMC_Comm.SET_ACT.bSendRequest := TRUE;
iStep := iStep+1;
END_IF;
iStep := 0 ; (* ReLoop *)
209: (* Wait for answer from ACK ACT *)
IF STATION^.ITAC.MMC_Comm.SET_ACT.bRecACK THEN
iStep := iStep+1;
ELSIF STATION^.ITAC.MMC_Comm.SET_ACT.bError THEN (* Set Error *)
STATION^.ScannerInput.bError := TRUE;
sArg1 := STATION^.ITAC.MMC_Comm.SET_ACT.sErrText;
FormatString( sFormat := '207| SCAN_FEEDER: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
210:
iStep := 0 ; (* ReLoop *)
RETURN;
(* -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *)
(*----------------------------------------------*)
(* Entry Point: PreFeeder *)
(*----------------------------------------------*)
300:
iStep := iStep + 1;
301:
(* Verify witch Feeder PreSetup aktiv *)
actVerifyPreSetupAktiv();
iStep := iStep+1;
302:(* Assign the Material from PreSetup *)
actPreSetupAssignmentMaterial();
303: (* no further checks, move material to presetup STRUCT *)
STATION^.ScannerInput.bDoneFeeder := TRUE;
iStep := 0 ; (* ReLoop *)
RETURN;
(* -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *)
(*----------------------------------------------*)
(* Entry Point: Move PRE_Setup to ACT_Setup *)
(*----------------------------------------------*)
400:
iStep := iStep + 1;
401:(* Material & Feeder IO *) (*21.11.2019 SD CheckFamiliy and Feeder not possible until now*)
actCheckFamilyAndVendorPRE();
402: (* prepare request message *) (*16.11.2018 SD add act PrepareFeeder - Set MB)*)
actPrepareFeederPreSetup();
403: (* wait answer *)
IF STATION^.ITAC.MMC_Comm.SET_MB.bRecACK THEN
iStep := iStep+1;
ELSIF STATION^.ITAC.MMC_Comm.SET_MB.bError THEN
sArg1 := STATION^.ITAC.MMC_Comm.SET_MB.sErrText;
FormatString( sFormat := '03| SCAN_FEEDER: >> %s',
arg1 := F_STRING (sArg1),
sOut => STATION^.ScannerInput.sErrText);
iStep := cErrStep;
ELSIF tTimeInTheStep > cTimeoutMMC THEN (* Timeout *)
STATION^.ScannerInput.sErrText := cTimeoutMessage;
iStep := cErrStep;
END_IF;
404: actCheckFeederPreSetup();
405:
(*---------------------------------------------*)
(* all prechecks passed, now accept material *)
(*---------------------------------------------*)
STATION^.FEEDER_POS[STATION^.uiFeederMoveSetupActive].ACT_SETUP := STATION^.FEEDER_POS[STATION^.uiFeederMoveSetupActive].INPUT.Material;
STATION^.ScannerInput.bDoneFeeder := TRUE;
STATION^.FEEDER_POS[STATION^.uiFeederMoveSetupActive].HandShake.bFeederSetupIO := TRUE;
STATION^.FEEDER_POS[STATION^.uiFeederMoveSetupActive].HandShake.bFeederSetupNIO := FALSE;
STATION^.FEEDER_POS[STATION^.uiFeederMoveSetupActive].HandShake.bFeederPreSetup := FALSE;
STATION^.bMoveSetupActive := FALSE;
STATION^.uiFeederMoveSetupActive := 0;
iStep := 208 ;
RETURN;
(*
IF STATION^.sOrder = '' THEN
iStep := 0; (* done and out *)
ELSE (* simulate order scan *)
STATION^.ScannerInput.szBarcodeOrder := STATION^.sOrder;
iStep := 5; (* check order again *)
END_IF;*)
(*---------------------------------------------*)
(* SUB Error STEP = Delay for Display *)
(*---------------------------------------------*)
cErrStep: (* 499 *)
STATION^.ScannerInput.bError := TRUE;
LogMessage01 (title := 'Error', text := STATION^.ScannerInput.sErrText);
iStep := iStep +1;
500:
IF tTimeInTheStep > cTimeoutError THEN
iStep := 0 ;
END_IF;
(*---------------------------------------------*)
(* totally wrong *)
(*---------------------------------------------*)
ELSE
STATION^.ScannerInput.sErrText := 'PROGRAM ERROR: undefined iSTEP no!!!!!!';
iStep := cErrStep;
END_CASE;
3、Station_INPUT 代码分析
3.1、系统初始化与状态检查
actTimingSystem(); // 时间系统管理(计时、超时检测)
actBarcodeSwitch(); // 条形码扫描设备切换控制
actCheckSetupComplete(); // 检查生产线设置是否完成
IF NOT STATION^.bMoveSetupActive THEN
actCheckMoveSetupActive(); // 激活移动设置状态检查
END_IF
FOR i := 1 TO cMaxFeederStation DO arFeederBomIdx[i] := 0; END_FOR; // 初始化供料器BOM索引
- 功能:
- 启动时间管理系统,为后续超时检测提供基准。
- 检测扫描设备状态,确保条形码输入有效。
- 初始化供料器相关索引数组,为物料分配做准备。
3.2、状态机核心逻辑(CASE 结构)
1. 初始化状态(iStep=0)
0: (* INIT *)
STATION^.ScannerInput.uiCodeSelect := 0; // 重置扫描类型选择
STATION^.ScannerInput.bError := FALSE; // 清除错误标志
STATION^.ScannerInput.sErrText := ''; // 清空错误信息
STATION^.ScannerInput.sBarcodeRead := ''; // 清空扫描缓存
iStep := iStep+1; // 切换到下一个状态
- 功能:系统启动时的初始化,重置扫描模块状态。
2. 主等待状态(iStep=1)
1: (* wait for something *)
actCheckSetupComplete(); // 检查设置完成状态
IF NOT STATION^.bMoveSetupActive THEN
actCheckMoveSetupActive(); // 激活移动设置检查
END_IF
CASE STATION^.ScannerInput.uiCodeSelect OF
0: (* 等待扫描输入,超时则重置预设置 *)
1: (* 扫描供料器条码:错误,需先扫描物料 *)
2: (* 扫描订单条码:进入订单处理流程 *)
3: (* 扫描物料条码:进入物料处理流程 *)
4: (* 扫描预设置条码:激活预设置模式 *)
ELSE: (* 未知扫描类型:错误处理 *)
END_CASE;
- 功能:
根据扫描输入的类型(订单、物料、供料器)切换不同处理流程,确保扫描顺序正确(如必须先扫物料再扫供料器)。
3.3、订单扫描处理流程(iStep=5~12)
1. 订单扫描初始化(iStep=5)
5:
STATION^.ScannerInput.bDoneOrder := FALSE; // 重置订单完成标志
actPrepareOrder(); // 准备订单数据
6: (* 等待MMC系统响应订单数据 *)
IF 收到ACK:验证订单条码一致性
ELSIF 收到错误:记录错误信息
ELSIF 超时:触发超时错误
- 功能:
扫描订单条码后,向 MMC 系统发送订单请求,验证返回的条码与扫描值是否一致,确保订单信息正确。
2. 物料清单(BOM)解析(iStep=7~8)
7: actPrepareGetWBM(); // 准备获取物料清单
8: (* 等待MMC返回BOM数据 *)
IF 成功获取BOM:
// 验证BOM中的产能编号与设备一致
FOR k := 1 TO cMAxMMC_BOM DO
// 按供料器位置存储物料信息到FEEDER_POS数组
END_FOR;
STATION^.ScannerInput.bDoneOrder := TRUE; // 标记订单处理完成
END_IF;
- 功能:
从 MMC 系统获取订单对应的物料清单(BOM),验证产能信息后,将物料分配到对应的供料器位置。
3.4、物料扫描处理流程(iStep=100~102)
100: (* 扫描物料条码 *)
STATION^.ScannerInput.bDoneMaterial := FALSE; // 重置物料完成标志
actPrepareMaterial(); // 准备物料数据
101: (* 等待MMC响应物料信息 *)
102:
STATION^.ScannerInput.bDoneMaterial := TRUE; // 标记物料处理完成
- 功能:扫描物料条码后,与 MMC 系统交互验证物料信息,确保物料与订单匹配。
3.5、供料器扫描处理流程(iStep=200~210)
1. 供料器扫描与分配(iStep=200~207)
200: (* 解析供料器条码,获取供料器编号 *)
201: actCheckMaterial(); // 检查物料与供料器匹配性
202: actFeederAssignment(); // 分配供料器位置
203: actCheckFamilyAndVendor(); // 验证物料族与供应商信息
204: actPrepareFeeder(); // 准备供料器数据
205: (* 等待MMC确认供料器设置 *)
206: actCheckFeeder(); // 检查供料器状态
207:
// 保存供料器设置,标记供料器处理完成
STATION^.FEEDER_POS[...].ACT_SETUP := 物料信息;
STATION^.ScannerInput.bDoneFeeder := TRUE;
- 功能:
扫描供料器条码后,验证物料与供料器的匹配性,将物料信息绑定到具体供料器,并同步到 MMC 系统。
3.6、预设置与移动设置流程(iStep=300~405)
1. 预设置模式(iStep=300~303)
300: (* 预设置入口 *)
301: actVerifyPreSetupAktiv(); // 验证预设置激活状态
302: actPreSetupAssignmentMaterial(); // 分配预设置物料
303: STATION^.ScannerInput.bDoneFeeder := TRUE; // 标记预设置完成
- 功能:用于提前配置供料器物料,支持快速切换生产任务。
2. 移动预设置到实际设置(iStep=400~405)
400: (* 移动预设置入口 *)
401: actCheckFamilyAndVendorPRE(); // 验证预设置物料信息
402: actPrepareFeederPreSetup(); // 准备预设置供料器数据
405:
// 将预设置物料应用到实际供料器
STATION^.FEEDER_POS[...].ACT_SETUP := 预设置物料;
STATION^.bMoveSetupActive := FALSE; // 完成移动设置
- 功能:将预配置的物料信息快速应用到生产线,减少换产时间。
3.7、错误处理流程(iStep=cErrStep~500)
cErrStep: (* 错误状态 *)
STATION^.ScannerInput.bError := TRUE;
LogMessage01('Error', STATION^.ScannerInput.sErrText); // 记录错误日志
500:
IF 超时时间到达 THEN
iStep := 0; // 错误清除后返回初始化状态
END_IF;
- 功能:处理各类异常(如数据不匹配、超时、未知状态),记录错误信息并等待用户确认后重置系统。
3.8、核心交互与数据同步
MMC_COM(...); // 与制造执行系统通信,获取订单和物料数据
FormatString(...); // 格式化错误信息,便于HMI显示
actTimingSystem(); // 管理超时逻辑,确保流程时效性
- 功能:
通过 MMC_COM 功能块与上位机系统交互,同步生产数据;使用 FormatString 生成标准化错误信息,通过 HMI 反馈给操作员。
3.9、整体流程总结
- 扫描优先级控制:必须按 “订单→物料→供料器” 的顺序扫描,确保数据一致性。
- 数据验证机制:通过与 MMC 系统交互,验证订单条码、物料清单、供料器分配的合法性。
- 预设置优化:支持预配置物料,通过 “预设置→实际应用” 流程快速切换生产任务。
- 异常处理:全流程超时检测和错误日志记录,确保系统故障可追溯。
四、MMC_COM 通讯实例
1、MMC_COM变量声明
VAR_INPUT
ptIN_STATION_ITAC :POINTER TO ST_ITAC_V2_0;
END_VAR
VAR
FbTCP_CLIENT :TCP_CLIENT;
RECEIVE_MMC :FB_RECEIVE_MMC_V2_5_0;
SEND_MMC :FB_SEND_MMC_V2_5_0;
// SPLIT_BomString :FB_SPLIT_BomString_V1_0;
fConnectionEstablished :R_TRIG;
fConnectionLost :R_TRIG;
END_VAR
2、MMC_COM代码实例
(* Interface *)
(*---------------------------------------------*)
FbTCP_CLIENT ( bEnable := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bEnable,
Reset := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bReset,
nPartnerPort := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.uiPort,
sPartnerHost := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.sAddress,
tFireDelay := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.tFireDelay,
bConnected => ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected);
fConnectionEstablished (CLK:= ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected);
fConnectionLost (CLK:= NOT ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected);
IF fConnectionEstablished.Q THEN
ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.dtConnected := GetDateTimStamp_AS_STRING();
END_IF;
IF fConnectionLost.Q THEN
ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.dtdisConnected:= GetDateTimStamp_AS_STRING();
END_IF;
(*---------------------------------------------*)
(* OFFLINE !!?? *)
(*---------------------------------------------*)
IF NOT ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected THEN
ptIN_STATION_ITAC^.MMC_Comm.SET_OBC.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_OBC.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_WBM.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_MB.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_MB.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_ACT.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_MD.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_SNC.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_OAT.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_SNB.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_AFO.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.GET_SCM.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_ASN.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_EXS.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_SNR.bSendRequest := FALSE;
ptIN_STATION_ITAC^.MMC_Comm.SET_STS.bSendRequest := FALSE;
RETURN;
END_IF;
(*---------------------------------------------*)
(* Receive Routines *)
(*---------------------------------------------*)
RECEIVE_MMC( ptIN_STATION_ITAC := ptIN_STATION_ITAC, (* !!! POINTER !!! *)
rxBuffer := FbTCP_CLIENT.strReceiveBuffer);
(*---------------------------------------------*)
(* Send Routines *)
(*---------------------------------------------*)
SEND_MMC( ptIN_STATION_ITAC := ptIN_STATION_ITAC, (* !!! POINTER !!! *)
SEND_QUEUE := ADR(FbTCP_CLIENT.strSendQueue)); (* Pointer required *)
3、MMC_COM代码解读
3.1、TCP 客户端连接管理
FbTCP_CLIENT (
bEnable := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bEnable,
Reset := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bReset,
nPartnerPort := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.uiPort,
sPartnerHost := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.sAddress,
tFireDelay := ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.tFireDelay,
bConnected => ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected
);
功能:
实例化 TCP 客户端功能块,配置与 MMC 系统通信的参数(IP 地址、端口号),并通过bConnected
输出连接状态。参数说明:
bEnable
:启用 TCP 连接(由系统控制)。Reset
:重置连接。nPartnerPort
/sPartnerHost
:目标服务器的端口和 IP 地址。tFireDelay
:发送数据的延迟时间。bConnected
:连接状态反馈(TRUE 表示已连接)。
3.2、连接状态监控
fConnectionEstablished (CLK:= ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected);
fConnectionLost (CLK:= NOT ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected);
IF fConnectionEstablished.Q THEN
ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.dtConnected := GetDateTimStamp_AS_STRING();
END_IF;
IF fConnectionLost.Q THEN
ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.dtdisConnected := GetDateTimStamp_AS_STRING();
END_IF;
- 功能:
- 使用上升沿触发 (
fConnectionEstablished
) 和下降沿触发 (fConnectionLost
) 检测连接状态变化。 - 记录连接建立和断开的时间戳,用于日志追踪。
- 使用上升沿触发 (
3.3、离线处理机制
IF NOT ptIN_STATION_ITAC^.MMC_Comm.CONVERSION_INTERFACE.bConnected THEN
ptIN_STATION_ITAC^.MMC_Comm.SET_OBC.bSendRequest := FALSE;
// 禁用所有MMC通信请求...
RETURN;
END_IF;
- 功能:
当 TCP 连接断开时,立即禁用所有 MMC 通信请求(如订单设置、物料查询等),防止数据丢失或通信异常,确保系统安全。
3.4、数据接收处理
RECEIVE_MMC (
ptIN_STATION_ITAC := ptIN_STATION_ITAC,
rxBuffer := FbTCP_CLIENT.strReceiveBuffer
);
- 功能:
调用RECEIVE_MMC
功能块,从 TCP 接收缓冲区 (strReceiveBuffer
) 读取 MMC 系统发送的数据,并解析为系统可识别的格式(如订单信息、物料清单)。
3.5、数据发送处理
SEND_MMC (
ptIN_STATION_ITAC := ptIN_STATION_ITAC,
SEND_QUEUE := ADR(FbTCP_CLIENT.strSendQueue)
);
- 功能:
调用SEND_MMC
功能块,将系统需要发送的数据(如物料请求、设备状态)封装到 TCP 发送队列 (strSendQueue
),由 TCP 客户端发送给 MMC 系统。
五、ACTFEEDER 程序代码
1、ActFeeder 变量声明
VAR CONSTANT
cUnblockTime :TIME := t#5s;
cFeederEmptyTime :TIME := t#1s;
cStepTime :TIME := t#60m;
END_VAR
VAR_INPUT
STATION :POINTER TO ST_SetupControl_ITAC_V2_0;
uiFEEDER :UINT;
bACK_Operator :BOOL;
bNACK_Operator :BOOL;
bFeederFull :BOOL;
bFeederON :BOOL;
bMoveSetupFromPreToAct :BOOL;
bShelfSystem :BOOL;
END_VAR
VAR_OUTPUT
bRequest_HMI :BOOL;
bUnblockFeeder :BOOL;
bDischargeMaterial :BOOL;
bFeederSetupIO :BOOL;
bPreSetupActive :BOOL;
END_VAR
VAR
RemoveBin :FB_RemoveBIN_V1_0;
iStep,iOldStep :INT;
TimerLockFeeder :TON;
TimerFeederEmpty :TON;
FB_TON_StepTime :TON;
tTimeInTheStep :TIME;
END_VAR
2、ActFeeder 程序代码
actTimingSystem();
bFeederSetupIO := STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupIO;
bPreSetupActive := STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederPreSetup;
STATION^.FEEDER_POS[uiFEEDER].HandShake.bMoveSetupFromPreToAct := bMoveSetupFromPreToAct;
(*---------------------------------------------*)
(* Feeder OFF/ON *)
(*---------------------------------------------*)
IF bFeederON THEN
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederON := TRUE;
END_IF;
IF NOT bFeederON THEN
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederON := FALSE;
IF NOT bPreSetupActive THEN
RETURN;
END_IF
END_IF;
(*---------------------------------------------*)
(* Check Fedder SetupNIO *)
(*---------------------------------------------*)
CASE iStep OF
0: (* init *)
(*IF bShelfSystem THEN
bRequest_HMI := FALSE;
bDischargeMaterial := FALSE;
END_IF*)
iStep := iStep + 1;
1:
IF STATION^.FEEDER_POS[uiFEEDER].Handshake.bFeederSetupNIO AND bFeederFull AND NOT bDischargeMaterial AND NOT bPreSetupActive THEN
iStep := iStep + 1;
END_IF;
2: (* send Request to HMI *)
bRequest_HMI := TRUE;
iStep := iStep + 1;
3: (*Wait for Answer Operator*)
IF bACK_Operator THEN
bRequest_HMI := FALSE;
bDischargeMaterial := TRUE;
iStep := 0; (* ReLoop *)
END_IF
IF bNACK_Operator THEN
bRequest_HMI := FALSE;
bDischargeMaterial := FALSE;
iStep := 0; (* ReLoop *)
END_IF
IF tTimeInTheStep > T#30S THEN
bRequest_HMI := FALSE;
iStep := 0; (* ReLoop *)
END_IF
END_CASE;
(*---------------------------------------------*)
(* Feeder Empty *)
(*---------------------------------------------*)
TimerFeederEmpty(IN:= NOT bFeederFull ,PT:=cFeederEmptyTime);
IF TimerFeederEmpty.Q THEN
bDischargeMaterial := FALSE;
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupNIO := TRUE;
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupIO := FALSE;
STATION^.bSetupComplete := FALSE;
END_IF;
IF bShelfSystem AND TimerFeederEmpty.Q AND STATION^.FEEDER_POS[uiFEEDER].ACT_SETUP.sMatNo <> '' THEN
STATION^.FEEDER_POS[uiFEEDER].Handshake.bRemoveBin := TRUE;
END_IF;
(*---------------------------------------------*)
(* Unblock Feeder*)
(*---------------------------------------------*)
IF STATION^.ScannerInput.bDoneFeeder AND STATION^.ScannerInput.uiMaterialFeeder=uiFEEDER THEN
bUnblockFeeder :=TRUE;
END_IF
TimerLockFeeder(IN:=bUnblockFeeder,PT:=cUnblockTime);
IF TimerLockFeeder.Q THEN
bUnblockFeeder :=FALSE;
END_IF
RemoveBin(uiFEEDER := uiFEEDER,
Station := STATION,
bRemove:=STATION^.FEEDER_POS[uiFEEDER].Handshake.bRemoveBin);
3、ActFeeder 代码解释
3.1、基础状态初始化
actTimingSystem(); // 时间系统管理(计时、超时检测)
bFeederSetupIO := STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupIO; // 获取供料器IO设置状态
bPreSetupActive := STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederPreSetup; // 获取预设置状态
STATION^.FEEDER_POS[uiFEEDER].HandShake.bMoveSetupFromPreToAct := bMoveSetupFromPreToAct; // 设置预设置转实际设置标志
- 功能:
初始化供料器状态变量,为后续逻辑判断提供基础数据。
3.2、供料器开关控制
iecst
IF bFeederON THEN
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederON := TRUE; // 开启供料器
END_IF;
IF NOT bFeederON THEN
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederON := FALSE; // 关闭供料器
IF NOT bPreSetupActive THEN
RETURN; // 非预设置模式下直接退出
END_IF
END_IF;
- 功能:
通过bFeederON
信号控制供料器的开启 / 关闭。若关闭且非预设置模式,直接退出当前逻辑。
3.3、物料卸载请求处理(状态机)
iecst
CASE iStep OF
0: iStep := iStep + 1; // 初始化
1: // 检测是否需要卸载物料
IF 供料器已设置且满料且未请求卸载且非预设置模式 THEN
iStep := iStep + 1;
END_IF;
2: // 向HMI发送卸载请求
bRequest_HMI := TRUE;
iStep := iStep + 1;
3: // 等待操作员响应
IF 操作员确认 THEN
bDischargeMaterial := TRUE; // 执行卸载
iStep := 0; // 重置状态机
END_IF;
IF 操作员取消 OR 超时(30秒) THEN
取消请求;
iStep := 0;
END_IF;
END_CASE;
- 功能:
当供料器满料且需要卸载时,通过 HMI 向操作员发送请求,并根据响应执行卸载或取消操作。设置超时机制防止长时间等待。
3.4、空料检测与处理
TimerFeederEmpty(IN:= NOT bFeederFull ,PT:=cFeederEmptyTime); // 空料计时器(非满料时开始计时)
IF TimerFeederEmpty.Q THEN // 空料超时
bDischargeMaterial := FALSE; // 停止卸载
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupNIO := TRUE; // 设置供料器为未就绪状态
STATION^.FEEDER_POS[uiFEEDER].HandShake.bFeederSetupIO := FALSE; // 清除供料器就绪标志
STATION^.bSetupComplete := FALSE; // 标记系统设置未完成
END_IF;
IF bShelfSystem AND TimerFeederEmpty.Q AND 供料器有物料 THEN
STATION^.FEEDER_POS[uiFEEDER].Handshake.bRemoveBin := TRUE; // 触发货架系统移除料箱
END_IF;
- 功能:
- 通过计时器检测供料器空料状态,超时后重置供料器设置。
- 在货架系统中,自动触发料箱移除操作。
3.5、供料器锁定与解锁
IF STATION^.ScannerInput.bDoneFeeder AND STATION^.ScannerInput.uiMaterialFeeder=uiFEEDER THEN
bUnblockFeeder := TRUE; // 供料器扫描完成后解锁
END_IF
TimerLockFeeder(IN:=bUnblockFeeder,PT:=cUnblockTime); // 解锁计时器
IF TimerLockFeeder.Q THEN
bUnblockFeeder := FALSE; // 超时后重新锁定
END_IF
RemoveBin(uiFEEDER := uiFEEDER, // 调用移除料箱功能块
Station := STATION,
bRemove := STATION^.FEEDER_POS[uiFEEDER].Handshake.bRemoveBin);
- 功能:
- 当供料器扫描完成后,短暂解锁供料器(防止误操作)。
- 通过
RemoveBin
功能块执行料箱移除操作,实现自动化物料管理。
3.6 整体流程总结
供料器控制:
- 支持远程开启 / 关闭供料器,非预设置模式下关闭后直接退出。
物料卸载机制:
- 自动检测需要卸载的场景,通过 HMI 与操作员交互,确保操作安全。
- 设置超时保护,避免长时间等待导致流程停滞。
空料处理:
- 通过计时器检测空料状态,自动重置供料器设置。
- 与货架系统集成,实现料箱自动移除。
安全锁定:
- 扫描完成后短暂解锁供料器,防止误操作,提高系统安全性。