Загрузка данных
// ===================== Инициализация и мигание =====================
IF BlinkState_05S THEN
C := NOT(C);
END_IF
// ===================== Аварийный останов =====================
IF Stop OR Flow_alarm OR Pump_fault OR NOT(phase_ok) THEN
PV.On_chiller := FALSE;
END_IF
Alarm_comp := (pressure_real > 32) OR NOT(Pressure_low) OR NOT(Pressure_up);
// ===================== Насос и контроль протока =====================
IF PV.On_chiller THEN
On_sw_chiller := "СТОП";
Pump_on := TRUE;
ELSE
On_sw_chiller := "ПУСК";
Pump_on := FALSE;
END_IF
Time_pump(IN := Pump_on, PT := PV.Pump_time);
IF Time_pump.Q THEN
Flow_alarm := NOT(Flow);
Time_pump(IN := FALSE);
END_IF
IF NOT Pump_on THEN
Flow_alarm := FALSE; // автоматический сброс аварии протока при останове насоса
END_IF
// ===================== ПИД водяного контура (всегда активен) =====================
Water_PID(
ACT := temp_in,
SET := Pv.temp,
SUP := 0.1,
OFS := 0,
M_I := , // или FALSE
MAN := , // или FALSE
RST := NOT(PV.On_chiller),
KP := Water_KP,
TN := Water_KI,
TV := Water_KD,
LL := Water_LL,
LH := Water_LH,
Y => Water_PI_out,
DIFF => ,
LIM => Water_LIM
);
Water_PI_real_out := Water_LH - Water_PI_out;
// Постоянные времени (доступны всегда)
Pump1_time := PV.Comp_on_time;
Pump2_time := PV.Comp_on_time; // при необходимости заменить на отдельную уставку
// ===================== Формирование команд Comp_x_on =====================
IF PV.On_chiller THEN
IF NOT(Alarm_comp) THEN
// Гистерезисное определение требуемого числа компрессоров (req_comp)
CASE req_comp OF
0: // сейчас 0
IF Water_PI_real_out > Hyst_On_1comp THEN
req_comp := 1;
END_IF
1: // сейчас 1
IF Water_PI_real_out < Hyst_Off_1comp THEN
req_comp := 0;
ELSIF Water_PI_real_out > Hyst_On_2comp THEN
req_comp := 2;
END_IF
2: // сейчас 2
IF Water_PI_real_out < Hyst_Off_2comp THEN
req_comp := 1;
END_IF
END_CASE
// Назначение команд Comp_1_on / Comp_2_on с чередованием по наработке
CASE req_comp OF
0: // оба выключены
Comp_1_on := FALSE;
Comp_2_on := FALSE;
2: // оба включены
Comp_1_on := TRUE;
Comp_2_on := TRUE;
1: // работает один
IF Comp_1_RUN AND Comp_2_RUN THEN
// переход 2→1: выключаем более изношенный
IF PV.WorkTime_drill_comp1_MIN > PV.WorkTime_drill_comp2_MIN THEN
Comp_1_on := FALSE; Comp_2_on := TRUE;
ELSE
Comp_1_on := TRUE; Comp_2_on := FALSE;
END_IF
ELSIF Comp_1_RUN AND NOT Comp_2_RUN THEN
// уже работает первый
Comp_1_on := TRUE; Comp_2_on := FALSE;
ELSIF NOT Comp_1_RUN AND Comp_2_RUN THEN
// уже работает второй
Comp_1_on := FALSE; Comp_2_on := TRUE;
ELSE
// оба остановлены: включаем с меньшей наработкой
IF PV.WorkTime_drill_comp1_MIN <= PV.WorkTime_drill_comp2_MIN THEN
Comp_1_on := TRUE; Comp_2_on := FALSE;
ELSE
Comp_1_on := FALSE; Comp_2_on := TRUE;
END_IF
END_IF
END_CASE
ELSE
// Авария по давлению – снимаем команды
Comp_1_on := FALSE;
Comp_2_on := FALSE;
END_IF
// Аварийное отключение: немедленный сброс реле и таймеров
IF Alarm_comp THEN
Comp_1_on := FALSE;
Comp_2_on := FALSE;
Time_comp_1_RUN(IN := FALSE);
Time_comp_1_STOP(IN := FALSE);
Comp_1_RUN := FALSE;
Time_comp_2_RUN(IN := FALSE);
Time_comp_2_STOP(IN := FALSE);
Comp_2_RUN := FALSE;
END_IF
ELSE
// Чиллер выключен – только снимаем команды, таймеры продолжают работу
Comp_1_on := FALSE;
Comp_2_on := FALSE;
END_IF
// ===================== Защитные таймеры (работают всегда) =====================
// Компрессор 1
Time_comp_1_RUN(IN := Comp_1_on, PT := Pump1_time);
IF Time_comp_1_RUN.Q THEN
Time_comp_1_STOP(IN := FALSE);
Comp_1_RUN := TRUE;
END_IF
Time_comp_1_STOP(IN := NOT Comp_1_on, PT := PV.Comp_off_time);
IF Time_comp_1_STOP.Q THEN
Time_comp_1_RUN(IN := FALSE);
Comp_1_RUN := FALSE;
END_IF
// Компрессор 2
Time_comp_2_RUN(IN := Comp_2_on, PT := Pump2_time);
IF Time_comp_2_RUN.Q THEN
Time_comp_2_STOP(IN := FALSE);
Comp_2_RUN := TRUE;
END_IF
Time_comp_2_STOP(IN := NOT Comp_2_on, PT := PV.Comp_off_time);
IF Time_comp_2_STOP.Q THEN
Time_comp_2_RUN(IN := FALSE);
Comp_2_RUN := FALSE;
END_IF
// ===================== Управление клапаном (всегда) =====================
// Автоматический: открывается при запросе любого компрессора
Valve(IN := Comp_1_on OR Comp_2_on, PT := PV.Comp_on_time - PV.Valve_on_time);
// Ручной: по кнопке Valve_RES открыт 3 секунды
Valve_Manual_Timer(IN := Valve_RES, PT := T#3S);
Valve_on := Valve.Q OR Valve_Manual_Timer.Q;
// Автоматическое закрытие при останове обоих компрессоров
Valve_TRIG(CLK := NOT(Comp_1_RUN) AND NOT(Comp_2_RUN));
IF Valve_TRIG.Q THEN
Valve(IN := FALSE);
END_IF
// ===================== Счётчики наработки (всегда) =====================
Time_comp1(IN := Comp_1_RUN, PT := T#1M);
Time_comp1_TRIG(CLK := Time_comp1.Q);
IF Time_comp1_TRIG.Q THEN
PV.WorkTime_drill_comp1_MIN := PV.WorkTime_drill_comp1_MIN + 1;
Time_comp1(IN := FALSE);
END_IF
IF PV.WorkTime_drill_comp1_MIN = 1440 THEN
PV.WorkTime_drill_comp1_D := PV.WorkTime_drill_comp1_D + 1;
PV.WorkTime_drill_comp1_MIN := 0;
END_IF
Time_comp2(IN := Comp_2_RUN, PT := T#1M);
Time_comp2_TRIG(CLK := Time_comp2.Q);
IF Time_comp2_TRIG.Q THEN
PV.WorkTime_drill_comp2_MIN := PV.WorkTime_drill_comp2_MIN + 1;
Time_comp2(IN := FALSE);
END_IF
IF PV.WorkTime_drill_comp2_MIN = 1440 THEN
PV.WorkTime_drill_comp2_D := PV.WorkTime_drill_comp2_D + 1;
PV.WorkTime_drill_comp2_MIN := 0;
END_IF
// ===================== ПИД вентиляторов =====================
Vent_PID(
ACT := pressure_real,
SET := Pv.pressure,
SUP := 0.1,
OFS := 0,
M_I := ,
MAN := ,
RST := NOT(Comp_1_RUN OR Comp_2_RUN),
KP := Vent_KP,
TN := Vent_KI,
TV := Vent_KD,
LL := Vent_LL,
LH := Vent_LH,
Y => Vent_PI_out,
DIFF => ,
LIM => Vent_LIM
);
Vent_PI_real_out := Vent_LH - Vent_PI_out;
Vent_PI_INT_out := TO_UINT(Vent_PI_real_out);
Vent_1_on := Comp_1_RUN OR Comp_2_RUN;
Vent_2_on := Comp_1_RUN OR Comp_2_RUN;компрессора (выше)