Почитал серию "Монограф" от Leon78 и Михайло! :) . Очень интересно! Есть над чем подумать...
Сам пользуюсь модифицированным методом, базирующийся на Switch, и практического применения его на S7-200/300 Вавиловым Константином Валерьевичем. Со статьями Вавилова можно ознакомиться на сайте Шалыто А.А. -
http://is.ifmo.ru/progeny/
Правда, некоторые приемы, изложенные у К.В. Вавилова, меня не очень устраивали. К примеру: вынос таймеров за тело функции, использование двух логических переменных там, где должна быть одна выходная... К середине 2004 года получилось составить шаблон для STL (Step7), огромную помощь оказала инструкция распределенного перехода "
JL". Чем и пользуюсь постоянно. Есть пока и минусы, бифуркацию не рассматривал (не было необходимости).
Пример:
Технологический алгоритм управления жаротрубным котлом с вспомогательным оборудованием (насосная группа и трехходовой клапан рециркуляции, базовые алгоритмы этих устройств остались "за кадром")
Структура программы:
Порядок разработки алгоритма управления котлом:
На первом этапе определяю необходимые входные и выходные данные...
Данные, необходимые для работы функционального блока, поступают от автоматики безопасности котла,и функциональных блоков управления вспомогательным оборудованием, т.е. с соответствующих алгоритмов.
Далее разработка алгоритма:
Код в STL данного алгоритма:
Код: Выделить всё
FUNCTION_BLOCK "AUTOMAT_BOIL"
TITLE =
AUTHOR : CHANt
FAMILY : IES
NAME : AU_BOIL
VERSION : 0.1
VAR_INPUT
A_RUN_BOIL : BOOL ; //Включить котел
COOL_RESET : BOOL ; //Сбросить режим расхолаживания котла
ALARM_SHARED : BOOL ; //Общий аварийный сигнал выключения котельной
ALARM_BOIL : BOOL ; //Общий аварийный сигнал по котлу
ALARM_BURNER : BOOL ; //Авария горелки
ALARM_C_BOILS : BOOL ; //Общий аварийный сигнал по котловому контуру
NOT_RUN_NK : BOOL ; //Группа насосов рециркуляции неисправна
NORMA_BURNER : BOOL ; //Горелка в работе
POWER : BOOL ; //Есть электропитание котла
TIM_NUM_BOIL : TIMER ; //Номер таймера задержки выключения котла
TIM_BASE_BOIL : S5TIME ; //База времени для таймера
END_VAR
VAR_OUTPUT
A_RUN_NK : BOOL ; //Запустить группу рецирку
RUN_PID : BOOL ; //Включить регулятор рециркуляции
OPEN_PID : BOOL ; //Открыть регулятор при остывании котла
CLOSE_PID : BOOL ; //Закрыть регулятор при полной остановке котла (по умолчанию закрыт)
RUN_BURNER : BOOL ; //Включить горелку
WORK_BOIL : BOOL ; //Котел в работе
COOL_BOIL : BOOL ; //Расхолаживание котла
ALARM_BOIL_1 : BOOL ; //Авария котла
END_VAR
VAR_IN_OUT
STATE_WORD : INT ; //Слово с текущим номером состояния алгоритма
END_VAR
VAR
TIM_BOIL : BOOL ; //Истек таймер задержки выключения котла
END_VAR
VAR_TEMP
A_RUN_NK_S : BOOL ; //Признак запуска котловых насосов
A_RUN_NK_R : BOOL ; //Сбросить признак запуска котловых насосов
RUN_PID_S : BOOL ; //Признак запуска регулятора рециркуляции
RUN_PID_R : BOOL ; //Сбросить признак запуска регулятора рециркуляции
OPEN_PID_S : BOOL ; //Установить признак открыть регулятор
OPEN_PID_R : BOOL ; //Сбросить признак открыть регулятор
CLOSE_PID_S : BOOL ; //Признак запуска закрыть регулятор
CLOSE_PID_R : BOOL ; //Сбросить признак закрыть регулятор
RUN_BURNER_S : BOOL ; //Признак запуска горелки
RUN_BURNER_R : BOOL ; //Сбросить признак запуска горелки
WORK_BOIL_S : BOOL ; //Признак котел в работе
WORK_BOIL_R : BOOL ; //Сбросить признак котел в работе
COOL_BOIL_S : BOOL ; //Признак запуска котел расхолаживается
COOL_BOIL_R : BOOL ; //Сбросить признак запуска котел расхолаживается
ALARM_BOIL_S : BOOL ; //Признак аварии котла
ALARM_BOIL_R : BOOL ; //Сбросить признак аварии котла
TIM_BOIL_S : BOOL ; //Включить таймер задержки выключения котла
TIM_BOIL_R : BOOL ; //Выключить таймер задержки выключения котла
END_VAR
BEGIN
NETWORK
TITLE =Сброс промежуточных переменных и обработка слова состояния
CLR ;
= #A_RUN_NK_S;
= #A_RUN_NK_R;
= #RUN_PID_S;
= #RUN_PID_R;
= #OPEN_PID_S;
= #OPEN_PID_R;
= #CLOSE_PID_S;
= #CLOSE_PID_R;
= #RUN_BURNER_S;
= #RUN_BURNER_R;
= #WORK_BOIL_S;
= #WORK_BOIL_R;
= #COOL_BOIL_S;
= #COOL_BOIL_R;
= #ALARM_BOIL_S;
= #ALARM_BOIL_R;
= #TIM_BOIL_S;
= #TIM_BOIL_R;
L #STATE_WORD;
JL GT10;
JU ST_0;
JU ST_1;
JU ST_2;
JU ST_3;
JU ST_4;
JU ST_5;
JU ST_6;
JU ST_7;
JU ST_8;
JU ST_9;
GT10: JU Err;
NETWORK
TITLE =Обработка начального состояния
//1.A_RUN_BOIL&!ALARM_SHARED&!ALARM_BOIL&!ALARM_BURNER&!ALARM_C_BOILS&!NOT_RUN_NK&
//POWER\z:OPEN_PID_S;CLOSE_PID_R
//2.!CLOSE_PID\z:CLOSE_PID_S
//3.ALARM_BURNER||NOT_RUN_NK\z:ALARM_BOIL_S
ST_0: A #A_RUN_BOIL;
AN #ALARM_SHARED;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #ALARM_C_BOILS;
AN #NOT_RUN_NK;
A #POWER;
JCN Tr01;
= #OPEN_PID_S;
= #CLOSE_PID_R;
L 1;
T #STATE_WORD;
JU End;
Tr01: AN #CLOSE_PID;
JCN Tr02;
= #CLOSE_PID_S;
L 7;
T #STATE_WORD;
JU End;
Tr02: O #ALARM_BURNER;
O #NOT_RUN_NK;
JCN End;
= #ALARM_BOIL_S;
L 9;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 1
//1.ALARM_BOIL||!POWER||NOT_RUN_NK\z:ALARM_BOIL_S
//2.!A_RUN_BOIL||ALARM_SHARED||ALARM_C_BOILS\z:OPEN_PID_R;CLOSE_PID_S;
//3.A_RUN_BOIL&!ALARM_SHARED&!ALARM_BOIL&!ALARM_BURNER&!ALARM_C_BOILS&!NOT_RUN_NK&
//POWER\z:A_RUN_NK_S
ST_1: O #ALARM_BOIL;
ON #POWER;
O #NOT_RUN_NK;
JCN Tr11;
= #ALARM_BOIL_S;
L 8;
T #STATE_WORD;
JU End;
Tr11: ON #A_RUN_BOIL;
O #ALARM_SHARED;
O #ALARM_C_BOILS;
JCN Tr12;
= #OPEN_PID_R;
= #CLOSE_PID_S;
L 0;
T #STATE_WORD;
JU End;
Tr12: A #A_RUN_BOIL;
AN #ALARM_SHARED;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #ALARM_C_BOILS;
AN #NOT_RUN_NK;
A #POWER;
JCN End;
= #A_RUN_NK_S;
L 2;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 2
//1.NOT_RUN_NK||ALARM_BOIL||!POWER\z:A_RUN_NK_R;ALARM_BOIL_S
//2.!A_RUN_BOIL||ALARM_SHARED||ALARM_C_BOILS\z:OPEN_PID_R;CLOSE_PID_S;
//A_RUN_NK_R
//3.A_RUN_BOIL&!ALARM_SHARED&!ALARM_BOIL&!ALARM_BURNER&!ALARM_C_BOILS&!NOT_RUN_NK&
//POWER\z:RUN_BURNER_S
ST_2: O #NOT_RUN_NK;
O #ALARM_BOIL;
ON #POWER;
JCN Tr21;
= #ALARM_BOIL_S;
= #A_RUN_NK_R;
L 8;
T #STATE_WORD;
JU End;
Tr21: ON #A_RUN_BOIL;
O #ALARM_SHARED;
O #ALARM_C_BOILS;
JCN Tr22;
= #OPEN_PID_R;
= #CLOSE_PID_S;
= #A_RUN_NK_R;
L 0;
T #STATE_WORD;
JU End;
Tr22: A #A_RUN_BOIL;
AN #ALARM_SHARED;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #ALARM_C_BOILS;
AN #NOT_RUN_NK;
A #POWER;
JCN End;
= #RUN_BURNER_S;
L 3;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 3
//1.ALARM_BURNER||NOT_RUN_NK||ALARM_BOIL||!POWER\z:A_RUN_NK_R;RUN_BURNER_R;
//ALARM_BOIL_S
//2.!A_RUN_BOIL||ALARM_SHARED||ALARM_C_BOILS\z:OPEN_PID_R;CLOSE_PID_S;
//A_RUN_NK_R;RUN_BURNER_R
//3.NORMA_BURNER&A_RUN_BOIL&!ALARM_SHARED&!ALARM_BOIL&!ALARM_BURNER&!ALARM_C_BOILS
//&!NOT_RUN_NK&POWER\z:OPEN_PID_R;WORK_BOIL_S;RUN_PID_S
ST_3: O #ALARM_BURNER;
O #NOT_RUN_NK;
O #ALARM_BOIL;
ON #POWER;
JCN Tr31;
= #A_RUN_NK_R;
= #RUN_BURNER_R;
= #ALARM_BOIL_S;
L 8;
T #STATE_WORD;
JU End;
Tr31: ON #A_RUN_BOIL;
O #ALARM_SHARED;
O #ALARM_C_BOILS;
JCN Tr32;
= #OPEN_PID_R;
= #CLOSE_PID_S;
= #A_RUN_NK_R;
= #RUN_BURNER_R;
L 0;
T #STATE_WORD;
JU End;
Tr32: A #NORMA_BURNER;
A #A_RUN_BOIL;
AN #ALARM_SHARED;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #ALARM_C_BOILS;
AN #NOT_RUN_NK;
A #POWER;
JCN End;
= #OPEN_PID_R;
= #WORK_BOIL_S;
= #RUN_PID_S;
L 4;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 4
//1.ALARM_BOIL||ALARM_BURNER||NOT_RUN_NK||!POWER\z:RUN_BURNER_R;
//WORK_BOIL_R;RUN_PID_R;ALARM_BOIL_S
//2.ALARM_SHARED||ALARM_C_BOILS\z:CLOSE_PID_S;A_RUN_NK_R;RUN_BURNER_R;WORK_BOIL_R;
//RUN_PID_R
//3.!NORMA_BURNER&A_RUN_BOIL&!ALARM_BURNER\z:RUN_PID_R;OPEN_PID_S;WORK_BOIL_R;
//RUN_BURNER_R;COOL_BOIL_S;TIM_BOIL_S
//4.!A_RUN_BOIL&!ALARM_BURNER\z:RUN_PID_R;OPEN_PID_S;WORK_BOIL_R;
//RUN_BURNER_R;COOL_BOIL_S;TIM_BOIL_S
ST_4: O #ALARM_BOIL;
O #ALARM_BURNER;
O #NOT_RUN_NK;
ON #POWER;
JCN Tr41;
= #RUN_BURNER_R;
= #WORK_BOIL_R;
= #RUN_PID_R;
= #ALARM_BOIL_S;
L 8;
T #STATE_WORD;
JU End;
Tr41: O #ALARM_SHARED;
O #ALARM_C_BOILS;
JCN Tr42;
= #CLOSE_PID_S;
= #A_RUN_NK_R;
= #RUN_BURNER_R;
= #WORK_BOIL_R;
= #RUN_PID_R;
L 0;
T #STATE_WORD;
JU End;
Tr42: AN #NORMA_BURNER;
A #A_RUN_BOIL;
AN #ALARM_BURNER;
JCN Tr43;
= #RUN_PID_R;
= #OPEN_PID_S;
= #WORK_BOIL_R;
= #RUN_BURNER_R;
= #COOL_BOIL_S;
= #TIM_BOIL_S;
L 5;
T #STATE_WORD;
JU End;
Tr43: AN #A_RUN_BOIL;
AN #ALARM_BURNER;
JCN End;
= #RUN_PID_R;
= #OPEN_PID_S;
= #WORK_BOIL_R;
= #RUN_BURNER_R;
= #COOL_BOIL_S;
= #TIM_BOIL_S;
L 5;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 5
//1.!TIM_BOIL&!POWER\z:A_RUN_NK_R;COOL_BOIL_R;TIM_BOIL_R;ALARM_BOIL_S
//2.TIM_BOIL\z:A_RUN_NK_R;COOL_BOIL_R
//3.COOL_RESET&!ALARM_BOIL&!ALARM_BURNER&!NOT_RUN_NK&POWER\z:OPEN_PID_R;CLOSE_PID_
//S;TIM_BOIL_R;A_RUN_NK_R;COOL_BOIL_R
ST_5: AN #TIM_BOIL;
AN #POWER;
JCN Tr51;
= #A_RUN_NK_R;
= #COOL_BOIL_R;
= #TIM_BOIL_R;
= #ALARM_BOIL_S;
L 8;
T #STATE_WORD;
JU End;
Tr51: A #TIM_BOIL;
JCN Tr52;
= #A_RUN_NK_R;
= #COOL_BOIL_R;
L 6;
T #STATE_WORD;
JU End;
Tr52: A #COOL_RESET;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #NOT_RUN_NK;
A #POWER;
JCN End;
= #OPEN_PID_R;
= #CLOSE_PID_S;
= #TIM_BOIL_R;
= #A_RUN_NK_R;
= #COOL_BOIL_R;
= #ALARM_BOIL_R;
L 0;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 6
//TIM_BOIL\z:OPEN_PID_R;CLOSE_PID_S;TIM_BOIL_R
ST_6: A #TIM_BOIL;
JCN End;
= #OPEN_PID_R;
= #CLOSE_PID_S;
= #TIM_BOIL_R;
= #ALARM_BOIL_R;
L 0;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 7
//CLOSE_PID
ST_7: A #CLOSE_PID;
JCN End;
L 0;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 8
//1.!POWER\z:ALARM_BOIL_R;OPEN_PID_R
//2.(ALARM_BOIL||ALARM_BURNER||NOT_RUN_NK)||(!ALARM_BOIL&!ALARM_BURNER&
//!NOT_RUN_NK)&POWER\z:OPEN_PID_S;COOL_BOIL_S;
//TIM_BOIL_S
ST_8: AN #POWER;
JCN Tr81;
= #ALARM_BOIL_R;
= #OPEN_PID_R;
= #A_RUN_NK_R;
L 0;
T #STATE_WORD;
JU End;
Tr81: A( ;
O #ALARM_BOIL;
O #ALARM_BURNER;
O #NOT_RUN_NK;
) ;
O( ;
AN #ALARM_BOIL;
AN #ALARM_BURNER;
AN #NOT_RUN_NK;
) ;
A #POWER;
JCN End;
= #OPEN_PID_S;
= #COOL_BOIL_S;
= #TIM_BOIL_S;
L 5;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка состояния 9
//1.!ALARM_BURNER&!NOT_RUN_NK&POWER\z:ALARM_BOIL_R
ST_9: AN #ALARM_BURNER;
AN #NOT_RUN_NK;
A #POWER;
JCN End;
= #ALARM_BOIL_R;
L 0;
T #STATE_WORD;
JU End;
NETWORK
TITLE =Обработка ошибки распределенного перехода
Err: CLR ;
= #A_RUN_NK;
= #RUN_PID;
= #OPEN_PID;
= #CLOSE_PID;
= #RUN_BURNER;
= #WORK_BOIL;
= #COOL_BOIL;
= #ALARM_BOIL_1;
L 0; //и загрузить число 0
T #STATE_WORD; //в слово состояния
JU End; //выйти на конец блока
End: NOP 0; // конец блока
NETWORK
TITLE =Обработка выходных сигналов
A #A_RUN_NK_S;
S #A_RUN_NK;
A #A_RUN_NK_R;
R #A_RUN_NK;
NOP 0;
A #RUN_PID_S;
S #RUN_PID;
A #RUN_PID_R;
R #RUN_PID;
NOP 0;
A #OPEN_PID_S;
S #OPEN_PID;
A #OPEN_PID_R;
R #OPEN_PID;
NOP 0;
A #CLOSE_PID_S;
S #CLOSE_PID;
A #CLOSE_PID_R;
R #CLOSE_PID;
NOP 0;
A #RUN_BURNER_S;
S #RUN_BURNER;
A #RUN_BURNER_R;
R #RUN_BURNER;
NOP 0;
A #WORK_BOIL_S;
S #WORK_BOIL;
A #WORK_BOIL_R;
R #WORK_BOIL;
NOP 0;
A #COOL_BOIL_S;
S #COOL_BOIL;
A #COOL_BOIL_R;
R #COOL_BOIL;
NOP 0;
A #ALARM_BOIL_S;
S #ALARM_BOIL_1;
A #ALARM_BOIL_R;
R #ALARM_BOIL_1;
NOP 0;
NETWORK
TITLE =Обработка таймера
A #TIM_BOIL_S;
L #TIM_BASE_BOIL;
SS #TIM_NUM_BOIL;
A #TIM_BOIL_R;
R #TIM_NUM_BOIL;
A #TIM_NUM_BOIL;
= #TIM_BOIL;
END_FUNCTION_BLOCK
В общем виде, тело программы состоит из:
1) обнуление (сброс) команд, признаков и т.п., используемых в автомате, но не имеющих обнуления по условию;
2) определение текущего состояния;
3) проверка условий и действий в состоянии 0;
4) проверка условий и действий в состоянии N;
5) обработка ошибки распределенного перехода;
6) установка/сброс выходных переменных;
7) обработка вложенных таймеров.
Шаблон STL общего вида:
Код: Выделить всё
NETWORK
TITLE =Сброс промежуточных переменных и анализ слова состояния
CLR ; //сбросить в 0
= # Временная переменная 1;
= # Временная переменная i;
L #STATE_WORD; //загрузка слова состояния для перехода
JL GT_3; // метка перехода, которая указывает на конец списка
JU ST_0; //переход на начального состояния графа переходов
JU ST_1; // переход на 1 состояние графа перехода
JU ST_2; // переход на i состояние графа перехода
GT_3: JU Err; // переход на метку обработок ошибок инструкции JL
NETWORK
TITLE =Обработка начального состояния
ST_0: A #Входной параметр 1; // номер состояния автомата и условие 1
A #Входной параметр 2; //условие 2
JCN End; //если условие не выполнено уход на метку
= #Временная переменная 1; //Действие 1
= # Временная переменная 2; //Действие 2
= # Временная переменная i; //Действие i
L 1; //переход по дуге графа в требуемое состояние
T #STATE_WORD; //загрузка номера следующего состояния
JU End; //Безусловный переход на конец блока
NETWORK
TITLE =Обработка состояния 1
ST_1: A # Входной параметр 1; // номер состояния автомата и условие 1
AN # Входной параметр 1; //условие 2
JCN Tr01; //если условие не выполнено уход на метку
= #Временная переменная 1; //Действие 1
= # Временная переменная 2; //Действие 2
= # Временная переменная i; //Действие i
L 3; //переход по дуге графа в требуемое состояние
T #STATE_WORD; //загрузка номера следующего состояния
JU End; //Безусловный переход на конец блока
Tr01: A # Входной параметр 1; // номер перехода (дуги) автомата и условие 1
AN # Входной параметр 1; //условие 2
JCN End; //если условие не выполнено уход на метку
L 0; //переход по дуге графа в начальное состояние
T #STATE_WORD; //загрузка номера следующего состояния
JU End; //Безусловный переход на конец блока
И т.д.
NETWORK
TITLE =Обработка ошибки распределенного перехода
Err: CLR
= Выходной параметр 1;
= Выходной параметр 2;
= Выходной параметр i;
L 0; //и загрузить число 0 начальное состояние
T #STATE_WORD; //в слово состояния
JU End; //выйти на конец блока
End: NOP 0; // конец блока
NETWORK
TITLE =Обработка выходных сигналов
A # Временная переменная 1;
S # Выходной параметр 1;
A # сброс Временная переменная 1;
R # Выходной параметр 1;
NOP 0;
NETWORK
TITLE =Обработка таймера
A #если есть команда на включение таймера, загрузить:;
L #временную базу;
SS #номер таймера;
A #если есть команда на сброс таймера;
R #сбросить таймер;
A #если таймер отработал;
= #установить внутреннюю перменную;
И для устранения "зависаний" выходных переменных, при некорректном выключении контроллера (бывает и такое), в ОВ100 (однократно, при запуске контроллера). в слово состояния загружаю большое число, больше чем кол-во состояний. При этом, после анализа слова управления, осуществляется переход на обработку ошибок распределенного перехода (JL) со сбросом выходных переменных и приведение алгоритма к начальному состоянию.
P.S. На STL размер кода значительно меньше чем в Graph.
--------------------------------------------------------------------------------------------