Hallo zusammen,
nachdem ich ziemlich lange mit dem Actuator_3p gekämpft hatte, habe ich ihn kurzerhand gekürzt und ein wenig für meine Belange umgeschrieben.
Ich habe einen 4-Wege-Mischer mit klassicher 3 Punkt-Ansteuerung (L,N,R) mit internen Endschaltern.
Ich habe mir 2 Magnetendschalter (SMC) mit einem Minimagneten im Drehknopf hinzugebaut und kann nun prima die beiden Positionen sauber abfangen.
Im wesentlichen habe ich nur noch eine Kalibrierung drin und nur noch zufahren, wenn nicht gebraucht.
Also sehr speziell für meinen Heizungsmischer.
Da ich viele gute Ideen hier im OSCAT gefunden habe, poste ich einfach mal meinen geänderten Code hier rein...
Vorsicht: Er nennt sich nun ACTUATOR_3PN, N=Neu 
Ggf. findet der eine oder andere Gefallen und / oder Änderungen...
Ich habe versucht weitestgehend englisch zu kommentieren, bitte Nachsicht :)
LG
Shrimps
(* @NESTEDCOMMENTS := 'Yes' *)
(* @PATH := '\/Engineering\/control' *)
(* @OBJECTFLAGS := '0, 8' *)
(* @SYMFILEFLAGS := '2048' *)
FUNCTION_BLOCK ACTUATOR_3PN
VAR_INPUT
	EN			: BOOL;		(* enable actuator *)
	IN 			: BYTE;		(* Signal Byte *)
	END_CLOSE	: BOOL;		(* Terminating Close *)
	END_OPEN 	: BOOL;		(* Terminating Open *)
END_VAR
VAR_OUTPUT
	OPEN 		: BOOL;		(* Signal for open-Valve *)
	CLOSE 		: BOOL;		(* Signal for Closing-Valve *)
	POS 		: BYTE;		(* Virtual Position *)
	STATUS 		: BYTE;		(* STEPS: 100/230 is good *)
END_VAR
VAR
	ramp 		: _RMP_NEXT;	(* lookup for direction *)
	tx 			: TIME;		(* the exakt time() *)
	next_cal 	: TIME;		(* next calibration pending ? *)
	start		: TIME;		(* Every time we need timedeltas *)
	bShutDown	: BOOL;		(* when EN is off we close the Valve, this is our Memory *)
END_VAR
VAR CONSTANT
	T_RUN 		: TIME := t#80s;	(* maximimum runtime of Valve, longer then time for endswitch *)
	T_CAL 		: TIME := t#6h;		(* permanently make Calibration *)
	t_LockOut 	: TIME := t#5s;		(* Lock for changing Direction too fast *)
	T_RELAY		: TIME := t#1500ms;	(* Locktime for smooth change of relay-Direction *)
END_VAR
(* Original:
version 2.0	28. jan 2010
programmer 	hugo
tested by		oscat
actuator_3P is an interface for a 3 point actuator.
a 3P actuator is a motor with 2 directions that drives a valve or flap. 
the position of the valve or flap is controlled by runtime of the motor foreward or backward.
the available inputs are:
IN specifies the position of the actuator, 0 = 0% and 255 = 100%.
30.07.2015 Shrimps:
Special Version for heating-Mixers with 2 external Position-Switches
renew most steps
Implemented security: When disable, run close first !
If no switch, all will be based on Timers like the original code
*)
(* @END_DECLARATION := '0' *)
tx := TIME(); 							(* read system timer *)
(* all steps will be done with these sequence *)
CASE status OF
	0:	(* Init, will start at Runup or called by Calibration *)
		OPEN 	:= FALSE;				(* Power off *)
		CLOSE 	:= FALSE;				(* Power off *)
		ramp.TR := T_RUN;				(* Fill ramp with default time rising *)
		ramp.TF := T_RUN;				(* Fill ramp with default time falling *)
		start 	:= tx;					(* keep Time in mind *)
		status 	:= 5;					(* do next step *)
	5:	(* Wait some time, better for Relay, perhaps comming from other direction *)
		IF tx - start > T_RELAY THEN	(* Wait *)
			start 	:= tx;				(* keep Time in mind *)
			status := 10;				(* do next step *)
		END_IF
	10:	(* Closing the valve until Timeout or Position reached *)
		CLOSE := TRUE;					(* give valve power *)
		IF tx - start > T_RUN OR END_CLOSE THEN	(* Timeout or final Switch reached ? *)
			CLOSE 	:= FALSE;			(* Stop down *)
			start 	:= tx;				(* keep Time in mind *)
			status 	:= 20;				(* do the next step *)
		END_IF
	20:	(* Wait some seconds to avoid damage of Motor or Relays *)
		IF tx - start > T_RELAY THEN	(* Wait for rewind, better for Relay *)
			start 	:= tx;				(* keep Time in mind *)
			status 	:= 30;				(* do the next step *)
		END_IF
	30:	(* opening Valve *)
		OPEN := TRUE;
		IF tx - start > T_RUN OR END_OPEN THEN (* Timeout or Position reached ? *)
			OPEN 	:= FALSE;			(* Off all Power *)
			ramp.TR := tx - start;		(* Uptime *)
			ramp.IN := 255;				(* set ramp pos to max value, we reached Openposition *)
			start 	:= tx;				(* keep Time in mind *)
			STATUS 	:= 40;				(* do the next step *)
		END_IF
	40: (* pause for some s its better for the relays instead to change direction immediately *)
		IF tx - start > T_RELAY THEN	(* Wait for rewind, better for Relay *)
			start 	:= tx;				(* keep Time in mind *)
			status := 50;				(* do the next step *)
		END_IF
	50:	(* now closing the valve *)
		CLOSE 	:= TRUE;				(* Close valve *)
		IF tx - start > T_RUN OR END_CLOSE THEN (* Timeout or Position reached ? *)
			CLOSE 		:= FALSE;		(* Stop power *)
			ramp.TF 	:= tx - start;	(* TF to be filled! *)
			ramp.IN 	:= 0;			(* Ramp position set to zero *)
			start 		:= tx;			(* keep Time in mind *)
			STATUS 		:= 60;			(* do next step *)
		END_IF
	60:	(* pause for some s its better for the relays instead to change direction immediately *)
		IF tx - start > T_RELAY THEN	(* Wait some s for rewind, better for Relay *)
			next_CAL 	:= tx + T_CAL;	(* Update Calibration Time *)
			start 		:= tx;			(* keep Time in mind *)
			STATUS 		:= 100;			(* do next step *)
		END_IF
	100: (* normal operation *)
		IF NOT en THEN					(* case of power off this module *)
			status 	:= 200;				(* close the valve ! *)
		ELSE							(* standard operation: *)
			bShutDown := FALSE;			(* clear the closing-flag *)
		END_IF
		(* check for auto calibration *)
		(* no lookup for then nearest Position, because opening could make damage by heatings *)
		IF tx > next_cal THEN			(* we reached the next calibration-time *)
			status 	:= 0;				(* full restart *)
		END_IF
		(* do the full job now: *)
		(* set ramp generator to IN *)
		ramp.IN := IN;
		(* Postitioning the valve *)
		OPEN 	:= ramp.UP ;
		CLOSE 	:= ramp.DN ;
	200: (* Shutdown until Close-Position *)
		OPEN 	:= FALSE;
		status 	:= 210;					(* do the next step *)
		start	:= tx;					(* keep Time in mind *)
		(* We closed the valve before ? *)
		(* or is it closed ? *)
		IF END_CLOSE OR bShutDown THEN
			status := 230;				(* wait for ENable *)
		END_IF
	210: (* Close valve *)
		CLOSE := TRUE;					(* Power on *)
		IF tx - start > T_RUN OR END_CLOSE THEN (* Timeout or Position reached ? *)
			CLOSE 	:= FALSE;			(* Stop down *)
			start	:= tx;				(* keep Time in mind *)
			status 	:= 220;				(* do the next step *)
		END_IF
	220:	(* Wait for relays *)
			IF tx - start > T_RELAY THEN	(* Wait some s for rewind, better for Relay *)
				bShutDown := TRUE;		(* we closed successfully *)
				STATUS := 230;			(* do next step *)
			END_IF
	230: (* Shutdown finished, waiting for restart *)
		IF en THEN						(* we want to enable this FB ? *)
			status := 100;				(* go to normal operating mode *)
		END_IF
END_CASE;
(* internal flap simulation and output activation *)
ramp(OUT := POS, TL := t_LockOut);
(* adjust position if end switch is active *)
IF END_OPEN THEN
	pos 	:= 255;
	ramp.IN := 255;
END_IF
IF END_CLOSE THEN
	pos 	:= 0;
	ramp.IN := 0;
END_IF
END_FUNCTION_BLOCK