Есть ПИД-регулятор. Есть клапан, который управляется дискретными выходами Открыть, Закрыть, с него приходят дискретные Открыто/Закрыто.
Время полного хода клапана - 100 секунд.
Написал впервые что-то на ST, оцените, может кто-то что-то дополнит. Может кому-то понадобится.
Коротко: запоминается предыдущее воздействие, рассчитывается новое как разница предыдущее-новое.
В другой части программы обрабатываю условия, если ПИД выдал 0% или 100%, то выдаю на соответствующие выходы время равное 1,2 полного хода, чтоб клапан точно дошёл.
Как запихнуть подобное условие в этот блок - я не смог разобраться.
А может уже есть готовые кейсы подобного управления и я просто изобрёл велосипед.

Скрытый текст:
PHP код:
FUNCTION_BLOCK ValveControl

VAR_INPUT
    PIDOutput
REAL;    // 0-100% от PID-регулятора
    
FullTimeREAL;    // Время полного хода клапана в секундах
    
OpenStateBOOL;    // Состояние клапана "Открыт"
    
CloseStateBOOL;    // Состояние клапана "Закрыт"
    
UnixTimeUDINT;     // Текущее время в Unix формате (секунды)
END_VAR

VAR_OUTPUT
    OpenOutput
BOOL;    // Выход "Открыть"
    
CloseOutputBOOL;    // Выход "Закрыть"
    
OpenTimeREAL;    // Рассчитанное время открытия (секунды)
    
CloseTimeREAL;   // Рассчитанное время закрытия (секунды)
END_VAR

VAR
    
PreviousOutputREAL;    // Предыдущее значение сигнала PID
    
OpenTimeCounterREAL;         // Счетчик времени открытия
    
CloseTimeCounterREAL;       // Счетчик времени закрытия
    
OpenTimerStartedBOOL;     // Флаг запуска таймера открытия
    
CloseTimerStartedBOOL;    // Флаг запуска таймера закрытия
    
InitializedBOOL;     // Флаг инициализации 
    
LastOpenTimeUDINT// Время начала таймера открытия
    
LastCloseTimeUDINT// Время начала таймера закрытия
END_VAR

// Инициализация переменных при первом вызове функции
IF NOT Initialized THEN
    PreviousOutput 
:= 0;
    
OpenTimeCounter := 0;
    
CloseTimeCounter := 0;
    
OpenTimerStarted := FALSE;
    
CloseTimerStarted := FALSE;
    
Initialized := TRUE;
END_IF

// Проверка состояния клапана
IF OpenState THEN
    OpenTimeCounter 
:= 0// Сбрасываем счетчик времени открытия
    
OpenTimerStarted := FALSE;
    
OpenOutput := FALSE// Сбрасываем выход "Открыть"
ELSIF CloseState THEN
    CloseTimeCounter 
:= 0// Сбрасываем счетчик времени закрытия
    
CloseTimerStarted := FALSE;
    
CloseOutput := FALSE// Сбрасываем выход "Закрыть"
END_IF

// Вычисление времени удержания выхода
IF PIDOutput PreviousOutput THEN
    OpenTimeCounter 
:= OpenTimeCounter + (PIDOutput PreviousOutput) / 100 FullTime;
ELSIF PIDOutput PreviousOutput THEN
    CloseTimeCounter 
:= CloseTimeCounter + (PreviousOutput PIDOutput) / 100 FullTime;
END_IF

// Установка выхода "Открыть"
IF OpenTimeCounter AND NOT OpenTimerStarted THEN
    OpenTimerStarted 
:= TRUE;
    
LastOpenTime := UnixTime// Запоминаем начальное время
    
OpenOutput := TRUE;
END_IF

// Проверка таймера открытия
IF OpenTimerStarted THEN
    
// Сбрасываем выход "Открыть" только если таймер сработал
    
IF UnixTime LastOpenTime >= REAL_TO_UDINT(OpenTimeCounterTHEN 
        OpenOutput 
:= FALSE;
        
OpenTimerStarted := FALSE;
        
OpenTimeCounter := 0;
    
END_IF

    
// Сбрасываем выход "Открыть" если клапан уже открыт
    
IF OpenState THEN
        OpenOutput 
:= FALSE;
        
OpenTimerStarted := FALSE;
        
OpenTimeCounter := 0;
    
END_IF
END_IF

// Установка выхода "Закрыть"
IF CloseTimeCounter AND NOT CloseTimerStarted THEN
    CloseTimerStarted 
:= TRUE;
    
LastCloseTime := UnixTime// Запоминаем начальное время
    
CloseOutput := TRUE;
END_IF

// Проверка таймера закрытия
IF CloseTimerStarted THEN
    
// Сбрасываем выход "Закрыть" только если таймер сработал
    
IF UnixTime LastCloseTime >= REAL_TO_UDINT(CloseTimeCounterTHEN
        CloseOutput 
:= FALSE;
        
CloseTimerStarted := FALSE;
        
CloseTimeCounter := 0;
    
END_IF

    
// Сбрасываем выход "Закрыть" если клапан уже закрыт
    
IF CloseState THEN
        CloseOutput 
:= FALSE;
        
CloseTimerStarted := FALSE;
        
CloseTimeCounter := 0;
    
END_IF
END_IF

// Сохранение текущего значения сигнала PID
PreviousOutput := PIDOutput;

// Установка выходных значений OpenTime и CloseTime
OpenTime := OpenTimeCounter
CloseTime := CloseTimeCounter

END_FUNCTION_BLOCK