Added JobScheduler and recipe data for stations

This commit is contained in:
2026-02-24 18:28:00 +01:00
parent c4044be7bd
commit 46e294d991
33 changed files with 1454 additions and 2837 deletions

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<DUT Name="ST_HMI_Hotplate" Id="{ab37d0f5-58b8-40e5-b7d2-1ab669f4a063}">
<Declaration><![CDATA[TYPE ST_HMI_Hotplate :
STRUCT
stStationCmds : ST_HMI_PackML;
// Setpoint
stSetpoint : ST_HMI_ANALOG_VALUE;
// Process value
stPV : ST_HMI_ANALOG_VALUE;
// Enable button
stEnableBtn : ST_HMI_CONTROL_BUTTON;
// Disable button
stDisableBtn : ST_HMI_CONTROL_BUTTON;
// Status of slots (true = product in in this slot)
axSlotStatus : ARRAY[0..8] OF BOOL;
END_STRUCT
END_TYPE
]]></Declaration>
</DUT>
</TcPlcObject>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<DUT Name="ST_Recipe_Hotplate" Id="{c622bf0d-8040-4151-b720-bcd2c14eb3b4}">
<Declaration><![CDATA[TYPE ST_Recipe_Hotplate :
STRUCT
// Resting time in seconds
rRestingTime : REAL;
// Temperature in °C
rTemp : REAL;
END_STRUCT
END_TYPE
]]></Declaration>
</DUT>
</TcPlcObject>

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<POU Name="FB_Hotplate" Id="{317a2373-f886-4e32-b683-81b726d00aac}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_Hotplate EXTENDS FB_PackMLGeneric
VAR_INPUT
xEnable : BOOL;
rTargetTemp : REAL;
xReleaseAlarms : BOOL;
xConfirmAlarms : BOOL;
END_VAR
VAR_OUTPUT
uiNextFreeSlot : UINT;
uiNextReadySlot : UINT;
END_VAR
VAR_IN_OUT
stHMIInterface : ST_HMI_Hotplate;
END_VAR
VAR
xEnableHotplate AT %Q* : BOOL;
// _axSlotFree : ARRAY [0..(GVL_HeatCoolConfig.HEAT_COOL_PLATES_NUM_SLOTS - 1)] OF BOOL;
// _atonSlotTimer : ARRAY[0..(GVL_HeatCoolConfig.HEAT_COOL_PLATES_NUM_SLOTS - 1)] OF TON;
// Temp sensor
_fbTempSensor : FB_AnalogInput('Temp sensor');
_stTempSensorConfig : ST_ANALOG_IO_CONFIG := (sUnit := '°C', rPVMin := -200, rPVMax := 850, iAIMin := -2000, iAIMax := 8500);
_stTempSEnsorEWConfig : ST_ANALOG_EW_CONFIG := (
stLevels := (
rErrorMin := -2000,
rErrorMax := 8500,
rWarningMin := -1000,
rWarningMax := 7500),
stDelays := (
timErrorHighOn := T#1S,
timErrorLowOn := T#1S,
timWarningHighOn := T#1S,
timWarningLowOn := T#1S,
timHardwareSignalLevelOff := T#1S));
_fbPITempControl : FB_PI;
_fbLimit : FB_Limit;
_fbPWMOut : FB_PWM;
_xEnable : BOOL;
_xFirstCycle : BOOL := TRUE;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[IF _xFirstCycle THEN
_xFirstCycle := FALSE;
stHMIInterface.stSetpoint.rMin := 0;
stHMIInterface.stSetpoint.rMax := 140.0;
stHMIInterface.stSetpoint.sUnit := '°C';
stHMIInterface.stSetpoint.sName := 'Temp. Hotplate';
END_IF
A_HandleHMIInput();
// Call sensor fbs
_fbTempSensor(
stAnalogIOConfig:= _stTempSensorConfig,
stAnalogEWConfig:= _stTempSEnsorEWConfig,
xReleaseErrors:= xReleaseAlarms,
xReleaseLimitErrors:= FALSE,
xReleaseHardwareErrors:= TRUE,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stPV);
// For now get setpoint from HMI interface
_fbPITempControl(
rSP:= stHMIInterface.stSetpoint.rValue,
rPV:= _fbTempSensor.rScaledValue,
rKp:= 6,
rTn:= 0,
xEnable:= _xEnable,
rMV=> _fbLimit.rIn);
_fbLimit(
rMin:= 0,
rMax:= 100.0,
rOut=> _fbPWMOut.rPWM,
xClampedUpper=> _fbPITempControl.xSaturatedUpper,
xClampedLower=> _fbPITempControl.xSaturatedLower);
_fbPWMOut(
timPeriod:= T#100MS,
xOutput=> xEnableHotplate);
SUPER^(stPackMLHMIInterface := stHMIInterface.stStationCmds);
]]></ST>
</Implementation>
<Action Name="A_HandleHMIInput" Id="{d22cec08-4a88-4001-b04b-e7a9775ff9a8}">
<Implementation>
<ST><![CDATA[// Clamp HMI Setpoint
IF stHMIInterface.stSetpoint.rValue > 140.0 THEN
stHMIInterface.stSetpoint.rValue := 140;
END_IF
IF stHMIInterface.stSetpoint.rValue < 0.0 THEN
stHMIInterface.stSetpoint.rValue := 0.0;
END_IF]]></ST>
</Implementation>
</Action>
<Method Name="FB_Init" Id="{b45cedd9-9c6c-4658-b56c-da5577886b8f}">
<Declaration><![CDATA[//FB_Init is always available implicitly and it is used primarily for initialization.
//The return value is not evaluated. For a specific influence, you can also declare the
//methods explicitly and provide additional code there with the standard initialization
//code. You can evaluate the return value.
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
bInCopyCode: BOOL; // TRUE: the instance will be copied to the copy code afterward (online change)
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[]]></ST>
</Implementation>
</Method>
<Method Name="M_AddItem" Id="{9707459a-6558-487c-b730-c9dc92d598ed}">
<Declaration><![CDATA[METHOD M_AddItem
VAR_INPUT
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[]]></ST>
</Implementation>
</Method>
</POU>
</TcPlcObject>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<POU Name="FB_PWM" Id="{39ea0d97-8eb7-44fa-b55f-8461b6c6c8ae}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_PWM
VAR_INPUT
rPWM : REAL;
timPeriod : TIME;
END_VAR
VAR_OUTPUT
xOutput : BOOL;
END_VAR
VAR
_tonTimer : TON;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// Check for possible division by zero
IF TIME_TO_REAL(timPeriod) = 0 THEN
xOutput := FALSE;
RETURN;
END_IF
_tonTimer(IN := TRUE, PT := timPeriod);
IF _tonTimer.Q THEN
_tonTimer(IN := FALSE);
END_IF
IF rPWM = 0.0 THEN
xOutput := FALSE;
ELSIF rPWM >= 100.0 THEN
xOutput := TRUE;
ELSE
IF (1.0 - (TIME_TO_REAL(_tonTimer.ET) / TIME_TO_REAL(timPeriod))) <= (rPWM * 0.01) THEN
xOutput := TRUE;
ELSE
xOutput := FALSE;
END_IF
END_IF]]></ST>
</Implementation>
</POU>
</TcPlcObject>