Files
BasicComponents/PLC/POUs/Components/Analog/FB_AnalogOutput.TcPOU
2025-11-13 09:19:39 +01:00

237 lines
6.2 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<POU Name="FB_AnalogOutput" Id="{5ea9527b-d363-4c01-ba95-f8c298545979}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FINAL FB_AnalogOutput
VAR_INPUT
// Setpoint
rSetpoint : REAL;
// config data for analog output scaling
stAnalogIOConfig : ST_ANALOG_IO_CONFIG;
// Global switch to dissable all errors
xReleaseErrors : BOOL := TRUE;
// Input to confirm all errors
xConfirmAlarms : BOOL;
// Input to tell the fb thats ist used inside a unit test
// Fb will not throw error messages
{attribute 'hide'}
xInUnitTestMode : BOOL := FALSE;
END_VAR
VAR_OUTPUT
iAnalogValue AT %Q* : INT;
// Error in function block
xError : BOOL;
END_VAR
VAR_IN_OUT
// HMI Interface
stHMIInterface : ST_HMI_ANALOG_VALUE;
END_VAR
VAR
// Setpoint
_rSetpointInternal : REAL;
// Name of the function block
_sName : STRING;
// Scaling factor for conversion
_rConversionFactor : REAL;
// Base offset for scaling factor
_rBaseOffset : REAL;
// Temporary calculated analog value
_rTempAnalogValue : REAL;
// Config error
_xConfigError : BOOL;
// Max process value
_rPVMax : REAL;
// Min process value
_rPVMin : REAL;
// Config error alarm
_fbAlarmConfigError : FB_AlarmMessage(stEventEntry := TC_EVENTS.AnalogOutput.ConfigError, xWithConfirmation := FALSE);
// Internal error flag
_xError : BOOL;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// ===============
// Handle not used
// ===============
IF (NOT stAnalogIOConfig.xUsed) THEN
// Clear all pending alarms if there are any
_fbAlarmConfigError(xActive := FALSE, xRelease := FALSE);
IF xError THEN
_xError := FALSE;
xError := FALSE;
END_IF
// Dont execute anything anymore
RETURN;
END_IF
// =========
// Prechecks
// =========
// Calculate scaling factors,
// scaling will be zero in case
// of invalid scaling parameters.
CalcScalingFactors();
// ===========================
// Config error alarm handling
// ===========================
_fbAlarmConfigError(
xActive:= _xConfigError,
xRelease:= xReleaseErrors,
xAcknowledge:= ,
timOnDelay:= ,
timOffDelay:= ,
xInUnitTestMode:= xInUnitTestMode);
IF _fbAlarmConfigError.Triggered THEN
_xError := TRUE;
END_IF
// ========================
// Analog value calculation
// ========================
// Clamp analogue input levels
_rSetpointInternal := MAX(rSetpoint, _rPVMin);
_rSetpointInternal := MIN(_rSetpointInternal, _rPVMax);
// Calc scaled value
_rTempAnalogValue := _rSetpointInternal * _rConversionFactor + _rBaseOffset;
iAnalogValue := REAL_TO_INT(_rTempAnalogValue);
// ====================
// Handle HMI interface
// ====================
stHMIInterface.xUsed := stAnalogIOConfig.xUsed;
stHMIInterface.sUnit := stAnalogIOConfig.sUnit;
stHMIInterface.rMin := stAnalogIOConfig.rPVMin;
stHMIInterface.rMax := stAnalogIOConfig.rPVMax;
IF _xError THEN
stHMIInterface.iStatus := E_HMI_ANALOG_VALUE_STATUS.ERROR;
ELSE
stHMIInterface.iStatus := E_HMI_ANALOG_VALUE_STATUS.OK;
END_IF
stHMIInterface.sName := _sName;
// ================
// Reset error flag
// ================
IF _xError AND xConfirmAlarms AND (NOT _xConfigError) AND (NOT _fbAlarmConfigError.Triggered) THEN
_xError := FALSE;
END_IF
// Copy internal signals to outputs
xError := _xError;]]></ST>
</Implementation>
<Method Name="CalcScalingFactors" Id="{7d8169fd-cf9b-4df6-b6f9-6740616693c1}">
<Declaration><![CDATA[METHOD PRIVATE CalcScalingFactors : BOOL
VAR
_rNum : REAL;
_rDenom : REAL;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// _lrConversionFactor := (udiAIMax - udiAIMin)/(rPVMax - rPVMin) + udiAIMin
// Splitted in two calculations to catch division by zero
_rNum := INT_TO_REAL(stAnalogIOConfig.iAIMax - stAnalogIOConfig.iAIMin);
_rDenom := (stAnalogIOConfig.rPVMax - stAnalogIOConfig.rPVMin);
// Do not divide by 0 or a negative number
IF _rDenom > 0.0 THEN
_rConversionFactor := _rNum/_rDenom;
_rBaseOffset := INT_TO_REAL(stAnalogIOConfig.iAIMin) - (_rConversionFactor * stAnalogIOConfig.rPVMin);
_rPVMax := stAnalogIOConfig.rPVMax;
_rPVMin := stAnalogIOConfig.rPVMin;
_xConfigError := FALSE;
ELSE
// Division by zero happened
// Or denom was negative
// Set scaling to zero
_rConversionFactor := 0.0;
_rBaseOffset := 0.0;
_rPVMax := 0.0;
_rPVMin := 0.0;
_xConfigError := TRUE;
END_IF]]></ST>
</Implementation>
</Method>
<Method Name="CreateAlarmMSG" Id="{874f5254-0ec6-4c5e-a9a6-0292ac71a964}">
<Declaration><![CDATA[METHOD PRIVATE CreateAlarmMSG
VAR_INPUT
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[{analysis -46}
_fbAlarmConfigError.Arguments.Clear().AddString(_sName);
{analysis +46}]]></ST>
</Implementation>
</Method>
<Method Name="FB_init" Id="{0b8b8fc1-2085-4a85-a9d5-deae06fafe01}">
<Declaration><![CDATA[//FB_Init ist immer implizit verfügbar und wird primär für die Initialisierung verwendet.
//Der Rückgabewert wird nicht ausgewertet. Für gezielte Einflussnahme können Sie
//die Methoden explizit deklarieren und darin mit dem Standard-Initialisierungscode
//zusätzlichen Code bereitstellen. Sie können den Rückgabewert auswerten.
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL; // TRUE: Die Retain-Variablen werden initialisiert (Reset warm / Reset kalt)
bInCopyCode: BOOL; // TRUE: Die Instanz wird danach in den Kopiercode kopiert (Online-Change)
sName : STRING;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[_sName := sName;
CreateAlarmMSG();]]></ST>
</Implementation>
</Method>
<Property Name="Name" Id="{33bc699d-7760-4934-8e7d-cd24d62ae4d2}">
<Declaration><![CDATA[PROPERTY Name : STRING(80)]]></Declaration>
<Get Name="Get" Id="{21d4b695-16bc-443c-9b7e-27e6c5e1de73}">
<Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[Name := _sName;]]></ST>
</Implementation>
</Get>
<Set Name="Set" Id="{c423a761-157c-4651-9a9a-3e5b0e891e86}">
<Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[_sName := Name;
// After a name change, all error messages have to be changed
CreateAlarmMSG();]]></ST>
</Implementation>
</Set>
</Property>
</POU>
</TcPlcObject>