Паттерны и шаблоны можно находить в любой системе и на любом языке программирования. У Скотта Витлока (
Scott Whitlock) в блоге про автоматизацию есть любопытная подборка паттернов (или шаблонов)
Patterns of Ladder Logic Programming на языке лестничных диаграмм, релейной логики или просто
LD. Всё как в большом и кровавом энтерпрайзе с рейтингом R.
Обычно в проектах я использую ST и C# за редким исключением, когда возникает необходимость в других языках, поэтому было особенно интересно посмотреть как будет выглядеть один и тот же алгоритм на трех разных языках программирования МЭК. Я взял паттерн "Дребезг контактов" (
Debounce) и переписал его на LD, ST и CFC.
FBD брать не стал, так как есть CFC, а это более продвинутая и современная версия блочных диаграмм. На картинке выше, адаптация паттерна на языке LD под TwinCAT 3. Про объявление переменных чуть позже.
Вообще проблему с дребезгом лучше устранять на уровне железа, но если что, то в модули дискретных входов уже встроены фильтры. Правда они не настраиваются и не отключаются, что заказано, то заказано. Поэтому, чтобы иметь возможность подкрутить время нечувствительности, я воспользуюсь готовым паттерном, и проверю его работу одновременно на трех языках программирования. Сразу и одновременно.
Continuous Flow Chart
Паттерн настолько простой, что перенос не должен вызывать затруднения, разве что расставить последовательность операций, ну и бывает трудно найти панель инструментов с кнопками элементов диаграммы. Она прячется во
View → Toolbox (Ctrl + Alt + X). Она же хранит элементы для LD и прочих конструкторов.
Объявление переменных остается прежним. Забегая вперед, оно будет таким же и для LD.
Structured Text
LD легко транслируется на ST. Интересно, что шапка с объявлением переменных и ФБ остается по прежнему одинаковой для всех трех языков:
FUNCTION_BLOCK DebounceLD // DebounceST // DebounceCFC
VAR_INPUT
IN: BOOL;
Delay: TIME := T#50MS;
END_VAR
VAR_OUTPUT
Q: BOOL;
END_VAR
VAR
DelayOn: TON;
DelayOff: TOF;
END_VAR
Копируем в программу на ST шапку с объявлением переменных, переименовываем название функционального блока в
DebounceST и дописываем тело программы. Текст лаконичнее картинки, редкий случай когда лучше один раз прочитать, чем долго скользить взглядом по картинке. Хотя, на вкус и цвет...
DelayOn(IN := IN, PT := Delay);
DelayOff(IN := IN, PT := Delay);
Q := DelayOn.Q OR (Q AND DelayOff.Q);
Количество строк (равное трем) также совпадает с тремя "ступенями" лестничной диаграммы LD.
Испытания
Подвергнем три функциональных блока различным испытаниям. С помощью визуализации можно на глазок проверить правильно ли они зажигают и гасят лампочки, а с помощью цикла мы внезапно проверим какой же из языков быстрее:
PROGRAM MAIN
VAR
DebLD : DebounceLD;
DebST : DebounceST;
DebCFC: DebounceCFC;
[...]
lastExecTime := _TaskInfo[1].LastExecTime;
Timer(IN := TRUE);
IF Timer.Q THEN
Timer(IN := FALSE);
state := SEL(state >= 3, state + 1, 0);
END_IF
FOR i := 0 TO 10000 DO
CASE state OF
1:
DebLD ( IN := in, Delay := delay, Q => outLD );
2:
DebCFC( IN := in, Delay := delay, Q => outCFC );
3:
DebST ( IN := in, Delay := delay, Q => outST );
END_CASE
END_FOR
На самом деле правильность работы я определял по цифровому осциллографу, там же случайно выяснилось, что один из языков незначительно проигрывает в производительности... Это все очень не точно и не имеет большого значения, но все-равно интересно:
Синяя линия отражает значение переменной
state, нулевое значение которой соответствует пустому циклу (когда внутри цикла практически ничего не происходит). Заметен небольшой всплеск активности в момент работы CFC функционального блока.
Правда все это крутилось внутри ноутбука, а я
сталкивался с ситуацией, когда рантайм настоящего контроллера отличался от рантайма на ноуте. Поэтому я специально перепроверил поведение на 32-х разрядном контроллере CX9020 под WinCE.
Ситуация аналогичная:
Только не воспринимайте эти результаты всерьез: языки все равно равноценны и равнозначны. Пишите на том, который вам нравится или удобен в каждом конкретном случае.