Блог

Structured Text по IEC 61131-3: Компактный справочник синтаксиса и типовые ошибки компиляцииStructured Text по IEC 61131-3: Компактный справочник синтаксиса и типовые ошибки компиляции

Structured Text (ST) в IEC 61131-3 - это текстовый язык для ПЛК, близкий по духу к Pascal/Ada: строгие типы, блоки объявлений, управляющие конструкции и вызовы FB/FC. На практике половина времени уходит не на «алгоритм», а на сообщения компилятора про несовместимость типов и область видимости.
Ниже - сжатый справочник синтаксиса (без претензии заменить стандарт), плюс мини-таблица: типичная формулировка ошибки - что обычно не так. Конкретные номера и тексты сообщений у Siemens, CODESYS, Rockwell различаются, но смысл у ошибок один.

Короткий ответ

•Объявления живут в секциях VAR / VAR_INPUT / VAR_OUTPUT / VAR_IN_OUT / VAR_TEMP / VAR_GLOBAL (и др. в зависимости от среды).
•Базовые типы: BOOL, целые SINT/INT/DINT/LINT и беззнаковые USINT/UINT/UDINT/ULINT, REAL/LREAL, STRING[(n)], WSTRING, TIME, DATE, TOD, DT.
ENUM и STRUCT задают именованные типы; доступ к полю - точка.
REFERENCE TO (ссылка на переменную типа T) есть в стандарте и ряде сред; «сырые указатели» в стиле C в ПЛК обычно запрещены или вендор-специфичны - не смешивайте с REFERENCE.
•Большинство «непонятных» ошибок компилятора - это типы, направление параметров (IN_OUT), экземпляры FB и синтаксис вызова.
Дальше - по пунктам.

Программа, функция, функциональный блок

Типовые оболочки (ключевые слова стандарта, порядок секций может требоваться строго в вашей IDE):
PROGRAMEND_PROGRAM - организационная единица верхнего уровня (в зависимости от рантайма).
FUNCTION_BLOCKEND_FUNCTION_BLOCK - блок с сохраняемыми внутренними переменными, вызывается через экземпляр.
FUNCTIONEND_FUNCTION - без внутреннего сохраняемого состояния между вызовами (кроме статики, если среда позволяет - осторожно), обычно возвращает значение.
Вызов FB: указывают имя экземпляра, затем параметры в скобках или через присваивание входам - синтаксис зависит от среды. Забытый экземпляр или неверное имя - частая причина «identifier not found».

Объявления переменных

Пример каркаса (иллюстративно по IEC, без привязки к одному редактору):
VAR_INPUT - только читает блок снаружи. VAR_OUTPUT - наружу. VAR_IN_OUT - ссылочная семантика (передаётся «как адрес»), запрет на привязку к выражению вместо переменной - частый источник ошибок.

Элементарные типы и литералы

BOOL: TRUE, FALSE.
•Целые литералы: 10, 16#FF (шестнадцатеричный вид по среде).
REAL/LREAL: 1.0, научная запись в зависимости от среды (1.0E-3).
TIME: T#500ms, TIME#1s_200ms - синтаксис литералов зависит от реализации; при ошибке смотрите справку среды.
STRING: одинарные кавычки в IEC; длина задаётся типом STRING[80].

ENUM

TYPE E_Mode : (Stop, Run, Fault) := Stop; END_TYPE
Использование: сравнения, CASE E_Mode OF .... Ошибки: смешение INT и ENUM без ENUM_TO_* или без явного приведения, разные типы ENUM в одном выражении.

STRUCT и ARRAY

Доступ: p.x, a[i]. Индекс за границей - часто рантайм или проверка диапазона по настройке компилятора, не всегда ошибка на этапе компиляции.

Операторы (кратко)

Присваивание :=, сравнения =, <>, <, >, <=, >=, логика AND/OR/XOR/NOT, битовые AND для целых, скобки для приоритета. Конкатенация строк + или функция в зависимости от среды.

Управляющие конструкции

IF … ELSIF … ELSE … END_IF
CASE выражение OF 1: … 2..5: … ELSE … END_CASE
FOR i := a TO b BY step DO … END_FOR
WHILE условие DO … END_WHILE
REPEAT … UNTIL условие END_REPEAT
EXIT (выход из цикла), RETURN (в FUNCTION/FB - по правилам среды)
Забытый END_IF или ; после присваивания - классика «unexpected token».

REFERENCE TO и «указатели»

В IEC 61131-3 третьего издания есть REFERENCE TO - ссылка на другую переменную совместимого типа, с операциями REF() / разыменование в синтаксисе среды (например ^ в части реализаций).
Это не указатель на произвольную память C. Если ваша среда не поддерживает REFERENCE - компилятор скажет «unknown type» или аналог.

Стиль кода (минимум правил для команды)

•Один стиль имён: CamelCase или snake_case, но не вперемешку.
Не экономить на скобках в сложных булевых выражениях.
Не раздувать один IF на экран - вынести в FB или CASE.
•Критичные участки снабжать коротким комментарием «зачем», не «что делает строка».

Мини-таблица: формулировка ошибки - что обычно не так

Типичная формулировка (или близкий перевод)
Что обычно не так
Unknown identifier / необъявленный идентификатор
Опечатка, другой POU, нет префикса экземпляра FB, нет доступа к полю структуры
Syntax error / unexpected token
Пропущен ;, лишняя запятая, неверная скобка, END_* не тот
Type mismatch / несовместимость типов
INT vs REAL, TIME vs INT, смешение ENUM и числа
Operand types incompatible
Операция не определена для пары типов (например деление STRING)
Invalid assignment / запись невозможна
Запись в VAR_INPUT, в CONST, в выход чужого FB не через допустимый синтаксис
Expression must be a variable
В VAR_IN_OUT передали литерал или выражение вместо переменной
FB instance not found / нет экземпляра
Не объявлен экземпляр FB в VAR или неверная область видимости
Ambiguous name / неоднозначное имя
Два одинаковых имени в разных пространствах имён, конфликт с библиотекой
Call parameter list mismatch
Неверное число/порядок параметров, другая сигнатура перегрузки
Range exceeds / string length
STRING[n] превышена длина литерала, массив за пределами при константном индексе

Где уместен СТАБУР

В проектах на базе СТАБУР имеет смысл единый гайдлайн ST: именование, работа с ENUM/STRUCT, правила VAR_IN_OUT, шаблоны FB и список запрещённых приёмов (магические числа, неявные приведения). Это уменьшает шум в компиляторе и ускоряет ревью.

Заключение

ST по IEC 61131-3 - строгий язык: чем раньше вы привыкаете читать ошибки как «диагностику типов и области видимости», тем меньше времени тратится на отладку «на железе». Держите под рукой карту типов и правила передачи по ссылке - и компилятор станет союзником, а не шумом.

FAQ

Где взять полный синтаксис?

В официальном стандарте IEC 61131-3 и в документации вашей среды - реализации отличаются.

Почему один и тот же код компилируется в одной IDE и нет в другой?

Разные подмножества стандарта, расширения, строгость проверок.

Нужны ли указатели в ST?

В большинстве прикладных задач АСУ ТП - нет; REFERENCE - отдельный инструмент под конкретные паттерны.

Как уменьшить поток ложных «type mismatch»?

Явные приведения и отдельные типы для физических величин (давление, мм) вместо «везде REAL».

ST лучше LD для алгоритмов?

Часто да для ветвлений, циклов, структур данных - см. матрицу языков в отдельной статье.

Внутренняя перелинковка

Обсуждение