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 ...