ST 전체 코드 펼치기
(* PLC LAB - 5-floor educational virtual elevator
IEC 61131-3 Structured Text example. Invoke every 50 ms.
Pos and Door are a SOFTWARE PLANT, not physical drive control.
Generic syntax: adapt declarations/conversions for the chosen PLC.
Call[1..5], OpenPB, ClosePB, ResetPB are one-scan input pulses.
Estop is TRUE when emergency stop is requested.
States: 0 idle, 10 moving, 20 opening, 30 open, 40 closing, 90 fault.
Simulation I/O map:
I0.0 DoorClosed, I0.1 DoorOpened, I0.2 Obstacle,
I0.3 Overload, I0.4 Estop; I1.0..I1.4 floor sensors.
Q0.0 Up, Q0.1 Down, Q0.2 OpenMotor, Q0.3 CloseMotor.
This is not certified or suitable for a real elevator.
Fire extension: I0.5 FireAlarm, I0.6 MainSmoke, M0.0 FireActive.
FireResetPB is an administrator pulse, allowed after recall completion.
Fire states: 50 prepare, 51 close, 52 decelerate, 53 travel,
54 open, 55 hold, 56 stationary direction-change delay.
RecallFloor: 1 primary; 2 preselected alternate (demo assumption only).
Fire input NEVER sets Estop. Existing protections remain effective.
Sensor exception rules of commercial fire service are NOT replicated.
The brake curve and 0.4 s delay are illustrative, not drive parameters.
*)
FUNCTION_BLOCK FB_Elevator5F
VAR_INPUT
Call : ARRAY[1..5] OF BOOL;
Estop, Overload, Obstacle : BOOL;
OpenPB, ClosePB, ResetPB : BOOL;
FireAlarm, MainSmoke, FireResetPB : BOOL;
END_VAR
VAR_OUTPUT
Up, Down, OpenMotor, CloseMotor : BOOL;
DoorClosed, DoorOpened, Zone, Fault : BOOL;
FloorSensor : ARRAY[1..5] OF BOOL;
Request : ARRAY[1..5] OF BOOL;
Pos : REAL := 1.0;
Door : REAL := 0.0;
Floor : INT := 1;
State : INT := 0;
Direction : INT := 0;
FireActive : BOOL := FALSE;
RecallFloor : INT := 1;
END_VAR
VAR
n, Here, Nearest : INT;
Above, Below, Reached : BOOL;
HoldTime : REAL := 0.0;
Distance, Best : REAL;
Step : REAL := 0.025; (* 0.05 s / 2.0 s per floor *)
WasMoving, Replan : BOOL;
BrakeStart, BrakeEnd, BrakeDuration, PhaseTime, Ratio, Delta, OldPos : REAL;
END_VAR
(* Read virtual sensor image; latch momentary calls. *)
Here := REAL_TO_INT(Pos);
Zone := ABS(Pos - INT_TO_REAL(Here)) < 0.001;
DoorClosed := Door <= 0.0;
DoorOpened := Door >= 1.0;
FOR n := 1 TO 5 DO
FloorSensor[n] := Zone AND (Here = n);
IF Call[n] AND NOT (FireActive OR FireAlarm OR MainSmoke) THEN
IF Zone AND (Here = n) AND ((State = 20) OR (State = 30) OR (State = 40)) THEN
HoldTime := 0.0;
IF State = 40 THEN State := 20; END_IF;
ELSE Request[n] := TRUE;
END_IF;
END_IF;
END_FOR;
(* Outputs default OFF every scan. Fault stays latched after release. *)
Up := FALSE; Down := FALSE; OpenMotor := FALSE; CloseMotor := FALSE;
WasMoving := (State = 10) OR (State = 52) OR (State = 53);
IF Estop OR (WasMoving AND (Overload OR NOT DoorClosed)) THEN
Fault := TRUE; State := 90;
END_IF;
IF ResetPB AND NOT Estop AND NOT Overload AND Fault THEN
Fault := FALSE;
IF FireActive THEN State := 50;
ELSIF Door > 0.0 THEN State := 20; ELSE State := 0; END_IF;
END_IF;
(* Recall latches independently from emergency stop. *)
Replan := FALSE;
IF (FireAlarm OR MainSmoke) AND NOT FireActive THEN
FireActive := TRUE; RecallFloor := 1;
IF MainSmoke THEN RecallFloor := 2; END_IF;
FOR n := 1 TO 5 DO Request[n] := FALSE; END_FOR;
Replan := TRUE;
END_IF;
IF FireActive AND MainSmoke AND (RecallFloor <> 2) THEN
RecallFloor := 2; Replan := TRUE;
END_IF;
IF FireResetPB AND FireActive AND NOT FireAlarm AND NOT MainSmoke
AND NOT Fault AND (State = 55) THEN
FireActive := FALSE; RecallFloor := 1; Direction := 0;
State := 30; HoldTime := 0.0;
END_IF;
IF Replan AND NOT Fault THEN
Delta := INT_TO_REAL(RecallFloor) - Pos;
IF WasMoving AND (Direction <> 0) AND (INT_TO_REAL(Direction) * Delta <= 0.0) THEN
BrakeStart := Pos;
IF Zone THEN BrakeEnd := INT_TO_REAL(Here);
ELSIF Direction > 0 THEN
FOR n := 5 TO 1 BY -1 DO
IF INT_TO_REAL(n) > Pos THEN BrakeEnd := INT_TO_REAL(n); END_IF;
END_FOR;
ELSE
FOR n := 1 TO 5 DO
IF INT_TO_REAL(n) < Pos THEN BrakeEnd := INT_TO_REAL(n); END_IF;
END_FOR;
END_IF;
BrakeDuration := MAX(0.4, ABS(BrakeEnd - BrakeStart) * 4.0);
PhaseTime := 0.0; State := 52;
ELSIF WasMoving AND DoorClosed AND (ABS(Delta) > 0.001) THEN
IF Delta > 0.0 THEN Direction := 1; ELSE Direction := -1; END_IF;
State := 53;
ELSE State := 50;
END_IF;
END_IF;
IF NOT Fault THEN
IF FireActive THEN
CASE State OF
50:
IF ABS(Pos - INT_TO_REAL(RecallFloor)) < 0.001 THEN
Floor := RecallFloor; State := 54;
ELSIF Door > 0.0 THEN State := 51;
ELSIF NOT Overload THEN
IF INT_TO_REAL(RecallFloor) > Pos THEN Direction := 1; ELSE Direction := -1; END_IF;
State := 53;
END_IF;
51:
IF Obstacle OR Overload THEN
OpenMotor := Door < 1.0; Door := MIN(1.0, Door + 0.05);
ELSE
CloseMotor := TRUE; Door := MAX(0.0, Door - 0.05);
IF Door <= 0.0 THEN CloseMotor := FALSE; State := 50; END_IF;
END_IF;
52:
PhaseTime := PhaseTime + 0.05;
Ratio := MIN(1.0, PhaseTime / BrakeDuration);
Pos := BrakeStart + (BrakeEnd - BrakeStart) * (2.0 * Ratio - Ratio * Ratio);
Up := (Ratio < 1.0) AND (BrakeEnd > BrakeStart);
Down := (Ratio < 1.0) AND (BrakeEnd < BrakeStart);
IF Ratio >= 1.0 THEN
Pos := BrakeEnd; Floor := REAL_TO_INT(BrakeEnd);
PhaseTime := 0.0; State := 56;
END_IF;
56:
PhaseTime := PhaseTime + 0.05;
IF PhaseTime >= 0.4 THEN State := 50; END_IF;
53:
Delta := INT_TO_REAL(RecallFloor) - Pos; OldPos := Pos;
IF Delta > 0.0 THEN Direction := 1; ELSE Direction := -1; END_IF;
Pos := Pos + INT_TO_REAL(Direction) * MIN(ABS(Delta), Step);
Up := Direction = 1; Down := Direction = -1;
FOR n := 1 TO 5 DO
IF ((Direction = 1) AND (INT_TO_REAL(n) > OldPos) AND (INT_TO_REAL(n) <= Pos + 0.000001))
OR ((Direction = -1) AND (INT_TO_REAL(n) < OldPos) AND (INT_TO_REAL(n) >= Pos - 0.000001))
THEN Floor := n; END_IF;
END_FOR;
IF ABS(Pos - INT_TO_REAL(RecallFloor)) < 0.000001 THEN
Pos := INT_TO_REAL(RecallFloor); Floor := RecallFloor;
Up := FALSE; Down := FALSE; State := 54;
END_IF;
54:
OpenMotor := TRUE; Door := MIN(1.0, Door + 0.05);
IF Door >= 1.0 THEN OpenMotor := FALSE; State := 55; END_IF;
55: (* Hold doors open, refuse ordinary calls, await administrator reset. *)
Up := FALSE; Down := FALSE;
ELSE State := 50;
END_CASE;
ELSE
IF OpenPB AND Zone AND ((State = 0) OR (State = 30) OR (State = 40)) THEN
State := 20; HoldTime := 0.0;
END_IF;
IF ClosePB AND (State = 30) AND NOT Obstacle AND NOT Overload THEN
State := 40;
END_IF;
CASE State OF
0: (* Same-floor service, otherwise retain direction while work remains. *)
IF Zone AND Request[Here] THEN
Request[Here] := FALSE; State := 20;
ELSIF NOT Overload AND DoorClosed THEN
Above := FALSE; Below := FALSE; Best := 99.0; Nearest := 0;
FOR n := 1 TO 5 DO
IF Request[n] THEN
Above := Above OR (INT_TO_REAL(n) > Pos + 0.001);
Below := Below OR (INT_TO_REAL(n) < Pos - 0.001);
Distance := ABS(INT_TO_REAL(n) - Pos);
IF Distance < Best THEN Best := Distance; Nearest := n; END_IF;
END_IF;
END_FOR;
IF ((Direction = 1) AND Above) OR ((Direction = -1) AND Below) THEN
State := 10;
ELSIF Nearest <> 0 THEN
IF INT_TO_REAL(Nearest) > Pos THEN Direction := 1; ELSE Direction := -1; END_IF;
State := 10;
ELSE Direction := 0;
END_IF;
END_IF;
10: (* Virtual movement and floor crossing. *)
Up := Direction = 1; Down := Direction = -1;
FOR n := 1 TO 5 DO
Reached := ((Direction = 1) AND (INT_TO_REAL(n) > Pos + 0.001)
AND (INT_TO_REAL(n) <= Pos + Step + 0.001))
OR ((Direction = -1) AND (INT_TO_REAL(n) < Pos - 0.001)
AND (INT_TO_REAL(n) >= Pos - Step - 0.001));
IF Reached THEN
Floor := n;
IF Request[n] OR (n = 1) OR (n = 5) THEN
Pos := INT_TO_REAL(n); Request[n] := FALSE; State := 20;
Up := FALSE; Down := FALSE;
EXIT;
END_IF;
END_IF;
END_FOR;
IF State = 10 THEN Pos := LIMIT(1.0, Pos + INT_TO_REAL(Direction) * Step, 5.0); END_IF;
20:
OpenMotor := TRUE; Door := MIN(1.0, Door + 0.05);
IF Door >= 1.0 THEN State := 30; HoldTime := 0.0; OpenMotor := FALSE; END_IF;
30:
IF Obstacle OR Overload THEN HoldTime := 0.0;
ELSE HoldTime := HoldTime + 0.05;
END_IF;
IF HoldTime >= 2.5 THEN State := 40; END_IF;
40:
IF Obstacle OR Overload THEN State := 20;
ELSE
CloseMotor := TRUE; Door := MAX(0.0, Door - 0.05);
IF Door <= 0.0 THEN State := 0; CloseMotor := FALSE; END_IF;
END_IF;
END_CASE;
END_IF;
END_IF;
END_FUNCTION_BLOCK
브라우저 실행 기준은 controller.js입니다. ST는 같은 제어 흐름을 표현한 교육용 예제이며 스캔 내 실행 순서까지 동일한 코드 변환은 아닙니다. 제조사별 선언·입출력 매핑·안전 설계가 필요합니다.