PDA

Просмотр полной версии : "Хороший тон" (ST) или как правильно структурировать проект



Smith2007
05.03.2015, 19:45
В 13 году начал изучение Codesys (по видеолекциям Кирила). Спустя пару недель написал первую программу, которая уже управляла реальным объектом (меняла режимы работы котлов).
С той поры проект обрастал новыми POU, функциями, переменными, модулями ввода-вывода и т.д.
Глядя сейчас на свое творение, меня начинают терзать мысли "а не переписать ли все с нуля, используя накопленный опыт?"

Хотел спросить у уважаемых форумчан, как правильно структурировать проект? Что будет считаться "хорошим тоном" и какие модули выводить в отдельные программы.

Yegor
05.03.2015, 21:27
Вопрос сильно выходит за рамки конкретной среды разработки и конкретного языка.

На скриншоте вижу кучу программ. Такой подход мне кажется проблемным — слишком много отправных точек для отслеживания логики (даже если все они вызываются из PLC_PRG, например). Однозначно плохо, если эти программы увязаны между собой через собственные или глобальные переменные. Progressive disclosure на нуле.

В проектах покрупнее поведение узлов я стараюсь инкапсулировать в блоках, чтобы не загромождать автоматный код вторичной для него фигнёй вроде специфики ввода-вывода. Функциональным блокам у меня практически запрещено обращаться ко внешним для них переменным. И ввод-вывод делаю минимальным числом отдельных кусков, чтобы не держать в памяти различия между нормально закрытым и нормально открытым, например. Инглиш везде: понимаю, что это может оказаться злой шуткой в моё отсутствие, но не могу заставить себя писать код транслитом.

Самостоятельные ФБ, чистые автоматы, инкапсуляция состояний/поведений и сосредоточенный ввод-вывод — ключи к победе, как по мне, кароч.

В совсем мелких установках (или в средних со множеством однотипных узлов) — тупо максимум логических выражений и минимум ветвлений. От структуризации кода и абстрагирования всего и вся в таких проектах толку мало, зато монтажники рады, когда косяк железной или программной коммутации быстро обнаруживается.

Валенок
05.03.2015, 22:56
как правильно структурировать проект?
Вопрос из серии - как правильно готовить еду.

amn
06.03.2015, 02:17
Вопрос из серии - как правильно готовить еду.
Точно подметили :) Хорошая тема. Рецепты от профессионалов: кто как готовит проекты. Такой информации мало, не то что про еду.

По поводу программ хотел бы уточнить. Мне кажется если программа в цикле вызывается один раз, например из PLC_PRG и далее остальные блоки используют значения с ее выходов, то это удобно, доступ из любого места.

Функциональным блокам у меня практически запрещено обращаться ко внешним для них переменным
Егор, а как Вы организуете ввод/вывод, отдельный блок делаете и уже с него на входы функциональным блокам или как-то иначе?

Smith2007
06.03.2015, 05:11
Все pou явызываю по таймеру. Начал беспокоить pou отвечающий за работу с модемом. Иной раз я вижу что мне на тел от пм01 приходит искаженные слова. Может один, а может и три символа искажены.
Кроме того есть сетевые переменные в слейвах, которые в том числе используются как глобальные.
В одном из присланных мне проектов я видел отдельный pou обеспечивающий считывание данных со входов и отдельных для записи выходов.

Для некоторых покажется странной данная тема, но мне не приходилось раньше создавать программы и уж тем более для ПЛК.

Yegor
06.03.2015, 08:59
Егор, а как Вы организуете ввод/вывод, отдельный блок делаете и уже с него на входы функциональным блокам или как-то иначе?В зависимости от всякой промежуточной фигни (вроде LIN_TRAFO, необходимого для вывода на аналоговые выходы того же ПЛК160) либо в действие основной программы, либо в отдельную программу (приходится).

Smith2007
06.03.2015, 10:13
Если есть несколько программ, которые вызываются по таймеру, какое количество будет предельным?

Yegor
06.03.2015, 11:25
Такое, при котором время срабатывания таймера начнёт коррелировать с количеством вызываемых им программ.

amn
06.03.2015, 16:46
Спасибо, Егор, еще насчет аварий хотел поинтересоваться, как Вы их обрабатываете? Я разбиваю проект на несколько самостоятельных ФБ и аварии у меня разбросаны по всему проекту. То есть в каждом ФБ приходится учитывать все аварийные ситуации. Как-то думал сделать аварии отдельно, но проще мне это не показалось.

Smith2007
06.03.2015, 18:43
Спасибо, Егор, еще насчет аварий хотел поинтересоваться, как Вы их обрабатываете? Я разбиваю проект на несколько самостоятельных ФБ и аварии у меня разбросаны по всему проекту. То есть в каждом ФБ приходится учитывать все аварийные ситуации. Как-то думал сделать аварии отдельно, но проще мне это не показалось.

Такой же вопрос был :)
С авариями я поступил следующим образом:
Создал глобальный массив из структур. Каждая запись описывает одно событие. В структуре имеются:
флаг состояния, текстовое описание, уровень критичности, период повторения формирования сообщения о событии (ФБ TON), и еще несколько служебных полей.

Каждая программа при обнаружении выхода параметра за пределы нормы - выставляет флаг соответствующего события.
Отдельная программа (запускается так же по таймеру) при каждом входе проверяет одну строку глобального массива событий. Если флаг взведен - генерирует различные сигналы (в том числе устанавливает требование отправки СМС)


TYPE Alarm :
STRUCT
Alert: BOOL;
Level: BYTE;
mode: INT;

t_idle: TIME;
Msg: STRING[255] :='';
Count: INT;
fTON: TON;
END_STRUCT
END_TYPE




VAR_GLOBAL
Control : ARRAY[1..11] OF Alarm := (Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#24h, Count :=0 ), (* 01 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 02 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 03 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 04 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#20m, Count :=0 ), (* 05 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#10m, Count :=0 ), (* 06 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 07 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#10m, Count :=0 ), (* 08 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#30m, Count :=0 ), (* 09 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#30m, Count :=0 ), (* 10 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#3m, Count :=0 ); (* 11 *)




__________________________________________________ _________________________________

Не так давно, на одном из форумов меня натолкнули на мысль, что набор "уставок" (заданных параметров) можно хранить в отдельном массиве. Например: Ночной режим, Дневной режим, Режим ограниченной охраны, Режим полной охраны и пр. И по команде грузить тот или иной набор уставок. При этом еще можно сделать возможность сохранять произвольное количество наборов по запросу пользователя.
В системах "Умный дом" это называется "снимок".

energvk
07.03.2015, 00:00
Такой же вопрос был :)
С авариями я поступил следующим образом:
Создал глобальный массив из структур. Каждая запись описывает одно событие. В структуре имеются:
флаг состояния, текстовое описание, уровень критичности, период повторения формирования сообщения о событии (ФБ TON), и еще несколько служебных полей.

Каждая программа при обнаружении выхода параметра за пределы нормы - выставляет флаг соответствующего события.
Отдельная программа (запускается так же по таймеру) при каждом входе проверяет одну строку глобального массива событий. Если флаг взведен - генерирует различные сигналы (в том числе устанавливает требование отправки СМС)


TYPE Alarm :
STRUCT
Alert: BOOL;
Level: BYTE;
mode: INT;

t_idle: TIME;
Msg: STRING[255] :='';
Count: INT;
fTON: TON;
END_STRUCT
END_TYPE




VAR_GLOBAL
Control : ARRAY[1..11] OF Alarm := (Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#24h, Count :=0 ), (* 01 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 02 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 03 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 04 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#20m, Count :=0 ), (* 05 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#10m, Count :=0 ), (* 06 *)
(Alert := FALSE, Level := 16#00, mode :=0, t_idle := T#10m, Count :=0 ), (* 07 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#10m, Count :=0 ), (* 08 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#30m, Count :=0 ), (* 09 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#30m, Count :=0 ), (* 10 *)
(Alert := FALSE, Level := 16#01, mode :=0, t_idle := T#3m, Count :=0 ); (* 11 *)



Вот это интересное решение. А не расскажите поподробнее,как вы это реализовали?

Smith2007
07.03.2015, 10:00
Вот это интересное решение. А не расскажите поподробнее,как вы это реализовали?
Массив инициализируется при старте ПЛК. Дальше соответствующий POU устанавливает флаг Alrt = True. Отдельный POU запускается по таймеру с периодом 300 мс и за один вызов обрабатывает одну строку.

amn
07.03.2015, 10:58
Какие преимущества дает вызов POU по таймеру? Не проще ли вызывать в каждом цикле?

Sergey666
07.03.2015, 11:48
Какие преимущества дает вызов POU по таймеру? Не проще ли вызывать в каждом цикле?

А есть необходимость?
Напр. пресловутый блок получения-изменения системного времени ПЛК , какой смысл запускать его чаще чем 1раз в 500...1000мс ?
И дофига таких , напр. аналог.вх ну не могут поменять значение чаще чем за 500мс , какой смысл к ним тыркаться в каждом цикле ?

Smith2007
07.03.2015, 12:26
Какие преимущества дает вызов POU по таймеру? Не проще ли вызывать в каждом цикле?
Как раз в этом суть создания самой темы. Возможно я не правильно организую управление.
17017

amn
07.03.2015, 12:39
Спасибо, значит в больших проектах смысл заключается в уменьшении времени цикла программы. Я обычно внутри блока ставлю таймер в случае необходимости.

lara197a
07.03.2015, 13:55
нет все поу должны крутиться в цикле.
Вся безопасность в больших проектах выносится на реле безопасности.
Все скоростные задачи, с критичным временем выполнения, обрабатываются в отдельных устройствах.
А так в общем время цикла к примеру в S400 15-17мс и всем хватает.
Если этого мало, то в августе вышла модель s1500 c временем выполнения операции 1нс.
На нем гарантированно можно получить время цикла 200-250мкс.

Smith2007
07.03.2015, 16:12
нет все поу должны крутиться в цикле.


Это понятно. Правилен ли в принципе такой подход?
Есть несколько задач:
1. Управление режимами работы котлов и циркуляционными насосами в зависимости от нескольких параметров.
2. Мониторинг параметров водоснабжения (в том числе датчики протечки, расхода и пр)
3. Мониторинг параметров водоотведения
4. Мониторинг и управление автоматическими воротами
5. Охрана периметра
6 Мониторинг (и частичное управление) энергоснабжением
На сколько верно, что я сделал из них отдельные программы (POU) и запускаю их по таймеру. Период как правило от 500 до 2000 мс, кроме POU управления модемом. Там 10 мс.