Beckhoff(倍福) -- MES(ITAC) TCP 通讯

发布于:2025-06-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、主程序里对通讯程序的调用

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索引
  • 功能
    1. 启动时间管理系统,为后续超时检测提供基准。
    2. 检测扫描设备状态,确保条形码输入有效。
    3. 初始化供料器相关索引数组,为物料分配做准备。
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、整体流程总结
  1. 扫描优先级控制:必须按 “订单→物料→供料器” 的顺序扫描,确保数据一致性。
  2. 数据验证机制:通过与 MMC 系统交互,验证订单条码、物料清单、供料器分配的合法性。
  3. 预设置优化:支持预配置物料,通过 “预设置→实际应用” 流程快速切换生产任务。
  4. 异常处理:全流程超时检测和错误日志记录,确保系统故障可追溯。

四、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;
  • 功能
    1. 使用上升沿触发 (fConnectionEstablished) 和下降沿触发 (fConnectionLost) 检测连接状态变化。
    2. 记录连接建立和断开的时间戳,用于日志追踪。
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;
  • 功能
    1. 通过计时器检测供料器空料状态,超时后重置供料器设置。
    2. 在货架系统中,自动触发料箱移除操作。
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);
  • 功能
    1. 当供料器扫描完成后,短暂解锁供料器(防止误操作)。
    2. 通过RemoveBin功能块执行料箱移除操作,实现自动化物料管理。
3.6 整体流程总结
  1. 供料器控制

    • 支持远程开启 / 关闭供料器,非预设置模式下关闭后直接退出。
  2. 物料卸载机制

    • 自动检测需要卸载的场景,通过 HMI 与操作员交互,确保操作安全。
    • 设置超时保护,避免长时间等待导致流程停滞。
  3. 空料处理

    • 通过计时器检测空料状态,自动重置供料器设置。
    • 与货架系统集成,实现料箱自动移除。
  4. 安全锁定

    • 扫描完成后短暂解锁供料器,防止误操作,提高系统安全性。