Hallo.
Habe nun schon mehrere Monate an meiner Rollladensteuerung gespielt und programmiert.
Anbei mein FB als Info …
in dieser Struktur speichere ich für jeden Rollladen die letzten Bewegungen mit Position und Zeit, je Wochentag + Betriebsstunden
TYPE tRolloConf:
STRUCT
iDemandTime:ARRAY[1..MAXROLLSP,1..MAX_DAY] OF TOD;
iDemandPos:ARRAY[1..MAXROLLSP,1..MAX_DAY] OF INT;
iDemandIndex:INT:=1;
iBetrStunden:TIME;
END_STRUCT
END_TYPE
über diese Struktur erhält man den Namen,Position und kann Automatikbefehle über Sollposition und bChangePosition schicken ..
der if_time Block, dient der Anwesenheitssimulation, die dann die gespeicherten Sollposition aus der oberen Struktur wieder anfährt …
TYPE tRollo:
STRUCT
sName:STRING[20];
iPosition:INT;
PositionTime: TIME:= t#0s;
SollPosition:INT;
bChangePosition:BOOL;
if_Time:ARRAY[1..MAXROLLSP] OF IfTime;
END_STRUCT
END_TYPE
nun der FB …
FUNCTION_BLOCK Rolladensteuerung
VAR_INPUT
Taster_Roll_Hoch:BOOL;
Taster_Roll_Runter:BOOL;
Gruppe_Roll_Hoch:BOOL;
Gruppe_Roll_Runter:BOOL;
Beschattung:BOOL;
Beschattung_Pos:INT;
MaxTime: TIME;
iRoll:INT;
bExtern:BOOL;
END_VAR
VAR_OUTPUT
Ausgang_Roll_Hoch:BOOL;
Ausgang_Roll_Runter:BOOL;
Position: INT:=0;
END_VAR
VAR
Eingang_Roll_Hoch :BOOL;
Eingang_Roll_Runter:BOOL;
edge_hoch : BOOL;
edge_runter : BOOL;
edge_Taster_hoch : BOOL;
edge_Taster_runter : BOOL;
t_neu: TIME;
t_last: TIME;
t_taster_hoch_alt: TIME;
t_taster_runter_alt: TIME;
t_last_time_hoch: TIME;
t_last_time_runter: TIME;
t_alt: TIME;
t_delta: TIME;
postmp: DINT;
up_time:IfTime;
down_time:IfTime;
bSwitchUpTime: BOOL;
bSwitchDownTime: BOOL;
ExternAktiv: BOOL;
stmp: STRING;
Index: INT;
bHandbedienung: BOOL;
day: INT;
bCal: BOOL;
END_VAR
(aktuelle Zeit holen)
t_neu := TIME();
(Löschen der Speicherdaten)
IF ClearRollData=1 THEN
Config.Rollos[iRoll].iBetrStunden:=T#0s;
Config.Rollos[iRoll].iDemandIndex:=1;
FOR day:=1 TO MAX_DAY DO
FOR Index:=1 TO MAXROLLSP DO
Config.Rollos[iRoll].iDemandTime[Index,day]:=TOD#00:00:00;
Config.Rollos[iRoll].iDemandPos[Index,day]:=0;
END_FOR
END_FOR
END_IF
(Verknüpfung des Einzel- u. Gruppeneingangs)
Eingang_Roll_Hoch:=Taster_Roll_Hoch OR Gruppe_Roll_Hoch;
Eingang_Roll_Runter:=Taster_Roll_Runter OR Gruppe_Roll_Runter;
(Eingangsabfrage Hoch)
IF Eingang_Roll_Hoch AND NOT edge_taster_hoch THEN
(wenn gedrückt)
(Automatik abbrechen)
ExternAktiv:=FALSE;
edge_taster_hoch := TRUE;
(Zeit merken)
t_taster_hoch_alt:=t_neu;
ELSIF NOT Eingang_Roll_Hoch AND edge_taster_hoch THEN
(wenn losgelassen)
edge_taster_hoch := FALSE;
END_IF
(Eingang Hoch wurde betätigt)
IF edge_taster_hoch THEN
(Abfrage der Tastzeit)
IF t_neu-t_taster_hoch_alt>Config.Rollos_TastZeitKurz THEN
(Lange Tastzeit → Automatik / Zeit merken)
(Handbedienungsflag setzen → keine Fenstertürkontaktprüfung)
bHandbedienung:=TRUE;
Rollos[iRoll].bChangePosition:=TRUE;
Rollos[iRoll].SollPosition:=0;
END_IF
END_IF
(Eingangsabfrage Runter)
IF Eingang_Roll_Runter AND NOT edge_taster_runter THEN
(wenn gedrückt)
(Automatik abbrechen)
ExternAktiv:=FALSE;
edge_taster_runter := TRUE;
t_taster_runter_alt:=t_neu;
ELSIF NOT Eingang_Roll_Runter AND edge_taster_runter THEN
(wenn losgelassen)
edge_taster_runter := FALSE;
END_IF
(Eingang Runter wurde betätigt)
IF edge_taster_runter THEN
IF t_neu-t_taster_runter_alt>Config.Rollos_TastZeitKurz THEN
(Lange Tastzeit → Automatik / Zeit merken)
bHandbedienung:=TRUE;
Rollos[iRoll].bChangePosition:=TRUE;
Rollos[iRoll].SollPosition:=100;
END_IF
END_IF
(Simulation)
IF bSimulation=1 THEN
FOR Index:=1 TO MAXROLLSP DO
Rollos[iRoll].if_Time[Index](ActTime:=Times.dActualTime_TOD, SwitchTime:=Config.Rollos[iRoll].iDemandTime[Index,Times.weekday], bSwitchTime=>bSwitchUpTime);
IF bSwitchUpTime=1 AND bSimulation THEN
Rollos[iRoll].bChangePosition:=TRUE;
Rollos[iRoll].SollPosition:=Config.Rollos[iRoll].iDemandPos[Index,Times.weekday];
bHandbedienung:=TRUE;
END_IF
END_FOR
END_IF
(Ausgang Hoch setzen)
IF Eingang_Roll_Hoch=1 THEN
Ausgang_Roll_Hoch:=TRUE;
Ausgang_Roll_Runter:=FALSE;
(Ausgang Runter setzen)
ELSIF Eingang_Roll_Runter=1 THEN
Ausgang_Roll_Hoch:=FALSE;
Ausgang_Roll_Runter:=TRUE;
ELSE
(Ausgänge löschen)
Ausgang_Roll_Hoch:=FALSE;
Ausgang_Roll_Runter:=FALSE;
END_IF
(Beschattungsabfrage)
IF Beschattung THEN
IF ABS(Beschattung_Pos-Position)>1 THEN
Rollos[iRoll].bChangePosition:=TRUE;
Rollos[iRoll].SollPosition:=Beschattung_Pos;
bHandbedienung:=TRUE;
END_IF
END_IF
(Externe Sollwertvorgabe)
IF Rollos[iRoll].bChangePosition THEN
Rollos[iRoll].bChangePosition:=FALSE;
IF ABS(Rollos[iRoll].SollPosition-Position)>1 THEN
(Automatikbetriebsarten löschen)
(Externaktiv Flag setzen)
ExternAktiv:=TRUE;
IF Rollos[iRoll].SollPosition<Rollos[iRoll].iPosition THEN
bHandbedienung:=TRUE;
END_IF
IF Rollos[iRoll].SollPosition=0 THEN
bCal:=1;
ELSE
bCal:=0;
END_IF
END_IF
END_IF
(Abfrage Externaktiv)
IF ExternAktiv THEN
IF bExtern=TRUE OR bHandbedienung=TRUE THEN
(Vergleich Soll-/Ist-Position)
IF ABS(Rollos[iRoll].SollPosition-Position)>=1 OR bCal THEN
IF ABS(Rollos[iRoll].SollPosition-Position)<1 THEN
IF t_neu-t_last>t#5s THEN
bCal:=FALSE;
END_IF
ELSE
t_last:=t_neu;
END_IF
(Ausgang Runter setzen)
IF Rollos[iRoll].SollPosition>Position THEN
Ausgang_Roll_Runter:=TRUE;
Ausgang_Roll_Hoch:=FALSE;
ELSE
(Ausgang Hoch setzen)
Ausgang_Roll_Hoch:=TRUE;
Ausgang_Roll_Runter:=FALSE;
END_IF;
ELSE
stmp:=CONCAT(‘->’,INT_TO_STRING(Rollos[iRoll].SollPosition));
stmp := CONCAT (Rollos[iRoll].sName,stmp);
stmp := CONCAT ('Rolladen ',stmp);
BDEMeldung(MeldungIn:=stmp);
IF bSimulation=0 THEN
Config.Rollos[iRoll].iDemandTime[Config.Rollos[iRoll].iDemandIndex,Times.weekday]:=Times.dActualTime_TOD;
Config.Rollos[iRoll].iDemandPos[Config.Rollos[iRoll].iDemandIndex,Times.weekday]:=Rollos[iRoll].SollPosition;
IF Config.Rollos[iRoll].iDemandIndex<MAXROLLSP THEN
Config.Rollos[iRoll].iDemandIndex:=Config.Rollos[iRoll].iDemandIndex+1;
ELSE
Config.Rollos[iRoll].iDemandIndex:=1;
END_IF
END_IF
(*wenn Position erreicht -> Beschattungaktiv auf 0*)
bHandbedienung:=FALSE;
ExternAktiv:=FALSE;
END_IF
ELSE
ExternAktiv:=FALSE;
END_IF
END_IF
(Abfrage, wann letzter Runter Vorgang)
IF Ausgang_Roll_Hoch THEN
(Ausgang Hoch für Zeit sperren)
IF t_neu-t_last_time_Runter<Config.Rollos_PauseAufAb THEN
Ausgang_Roll_Hoch:=FALSE;
END_IF
t_last_time_Hoch:=t_neu;
END_IF
(Abfrage, wann letzter Hoch Vorgang)
IF Ausgang_Roll_Runter THEN
(Ausgang Runter für Zeit sperren)
IF t_neu-t_last_time_Hoch<Config.Rollos_PauseAufAb THEN
Ausgang_Roll_Runter:=FALSE;
END_IF
t_last_time_Runter:=t_neu;
END_IF
(Sicherheitsabfrage, damit nicht beide Ausgänge geschaltet)
IF Ausgang_Roll_Hoch=1 THEN
IF Ausgang_Roll_Runter=1 THEN
Ausgang_Roll_Hoch:=FALSE;
Ausgang_Roll_Runter:=FALSE;
END_IF;
END_IF;
(Betriebsstunden hochzählen)
IF Ausgang_Roll_Runter OR Ausgang_Roll_Hoch THEN
Config.Rollos[iRoll].iBetrStunden:=Config.Rollos[iRoll].iBetrStunden+t_neu-t_alt;
END_IF
(Abfrage ob Ausgang zugeschaltet)
IF Ausgang_Roll_Hoch AND NOT edge_hoch THEN
edge_hoch := TRUE;
ELSIF NOT Ausgang_Roll_Hoch AND edge_hoch THEN
edge_hoch := FALSE;
END_IF
(Abfrage ob Ausgang zugeschaltet)
IF edge_hoch THEN
t_delta:=t_neu-t_alt;
(Berechnung neuer Bestrommungszeit)
Rollos[iRoll].PositionTime:=Rollos[iRoll].PositionTime-REAL_TO_TIME(TIME_TO_REAL(t_delta)*(1/Config.Rollos_RollUpFaktor));
IF Rollos[iRoll].PositionTime>MaxTime THEN
Rollos[iRoll].PositionTime:=t#0s;
END_IF
END_IF
(Abfrage ob Ausgang zugeschaltet)
IF Ausgang_Roll_Runter AND NOT edge_runter THEN
edge_runter := TRUE;
ELSIF NOT Ausgang_Roll_Runter AND edge_runter THEN
edge_runter := FALSE;
END_IF
(Abfrage ob Ausgang zugeschaltet)
IF edge_runter THEN
t_delta:=t_neu-t_alt;
(Berechnung neuer Bestrommungszeit)
Rollos[iRoll].PositionTime:=Rollos[iRoll].PositionTime+t_delta;
IF Rollos[iRoll].PositionTime>MaxTime THEN
Rollos[iRoll].PositionTime:=MaxTime;
END_IF
END_IF
(Berechnung Position aus Bestromungszeit)
postmp:=TIME_TO_DINT(Rollos[iRoll].PositionTime)*100;
Position:=DINT_TO_INT(postmp/TIME_TO_DINT(MaxTime));
Rollos[iRoll].iPosition:=Position;
t_alt:=t_neu;
was an der ganzen Sache interessant ist,
- er speichert alle Position die angefahren wurden
- wenn das Simulation’s Bit gesetzt ist, fährt er seine Sollwerte aus dem Speicher
- der FB berechnet sich aus der bisherigen Bestromungszeit die aktuelle Position..
- er fährt nur auf die Sollposition geregelt ..
- eingebauter Faktor für Mehrzeit beim Hochfahren …
- Selbstkalibrierung beim Hochfahren auf 0 → längere Bestromung als nötig …