********************** Структура ST-программы ********************** Этот раздел описывает базовую структуру программы на языке Structured Text (ST) и принципы модульности. Модульность в ST ================ В языке ST программа строится из программных модулей (POU - Program Organization Unit). Каждый модуль представляет собой отдельный программный блок, который может использоваться как самостоятельный элемент или вызываться из других модулей. Типы программных модулей ------------------------ В ST существует три типа программных модулей: **PROGRAM** — программный модуль, который используется исключительно как функциональный блок в FBD-программах. Он не может быть вызван из ST-кода. Сохраняет состояние между вызовами. **FUNCTION_BLOCK** — функциональный блок, используемый только внутри ST-модулей. Сохраняет состояние между вызовами. Требует создания экземпляра. **FUNCTION** — функция, используемая только внутри ST-модулей. Не сохраняет состояние. Может возвращать одно значение (через имя функции) или несколько значений (через VAR_OUTPUT). .. _program-module: PROGRAM — Программный модуль ============================ Модуль ``PROGRAM`` предназначен для использования в качестве функционального блока в FBD-программах. Он не может быть вызван из ST-кода. **Особенности:** - Используется только как функциональный блок в FBD-программах - Сохраняет состояние между вызовами - Переменные ``VAR`` сохраняют свои значения - Может содержать ``VAR_INPUT``, ``VAR_OUTPUT``, ``VAR_IN_OUT``, ``VAR``, ``VAR_TEMP`` - Не требует создания экземпляра - Не может быть вызван из ST-кода **Пример PROGRAM для использования в FBD:** .. code-table:: PROGRAM MotorControl VAR_INPUT enable : BOOL; // Входной пин в FBD speed_setpoint : INT; // Входной пин в FBD END_VAR VAR_OUTPUT motor_running : BOOL; // Выходной пин в FBD current_speed : INT; // Выходной пин в FBD END_VAR VAR_IN_OUT error_counter : INT; // Параметр по ссылке END_VAR VAR internal_counter : INT := 0; // Внутренняя переменная (не видна в FBD) END_VAR VAR_TEMP temp_value : INT; // Временная переменная END_VAR // Логика управления temp_value := speed_setpoint * 2; IF enable THEN motor_running := TRUE; current_speed := temp_value; internal_counter := internal_counter + 1; ELSE motor_running := FALSE; current_speed := 0; END_IF; END_PROGRAM .. _function-block-module: FUNCTION_BLOCK — Функциональный блок ==================================== Модуль ``FUNCTION_BLOCK`` предназначен для создания переиспользуемых программных компонентов. Он используется только внутри ST-модулей и не отображается в FBD-редакторе. **Особенности:** - Используется только внутри ST-модулей - Сохраняет состояние между вызовами - Переменные ``VAR`` сохраняют свои значения - Требует создания экземпляра перед использованием - Может содержать ``VAR_INPUT``, ``VAR_OUTPUT``, ``VAR_IN_OUT``, ``VAR``, ``VAR_TEMP`` - Не может быть использован в FBD **Пример FUNCTION_BLOCK:** .. code-table:: FUNCTION_BLOCK PIDController VAR_INPUT setpoint : REAL; // Уставка process_value : REAL; // Текущее значение kp : REAL := 1.0; // Коэффициент P ki : REAL := 0.1; // Коэффициент I kd : REAL := 0.05; // Коэффициент D END_VAR VAR_OUTPUT output : REAL; // Выходное значение integral_part : REAL; // Интегральная составляющая END_VAR VAR previous_error : REAL := 0.0; // Предыдущая ошибка (сохраняется) integral : REAL := 0.0; // Интеграл (сохраняется) END_VAR VAR_TEMP temp_error : REAL; // Временная переменная END_VAR // PID-алгоритм temp_error := setpoint - process_value; // ... END_FUNCTION_BLOCK **Использование FUNCTION_BLOCK:** Для использования FUNCTION_BLOCK необходимо создать его экземпляр в разделе переменных: .. code-table:: PROGRAM MainProgram VAR pid1 : PIDController; // Создание экземпляра output_value : REAL; END_VAR // Вызов функционального блока pid1(setpoint := 100.0, process_value := 95.0); output_value := pid1.output; END_PROGRAM .. _function-module: FUNCTION — Функция ================== Модуль ``FUNCTION`` предназначен для выполнения вычислений. В отличие от PROGRAM и FUNCTION_BLOCK, функция не сохраняет состояние между вызовами. **Особенности:** - Используется только внутри ST-модулей - Не сохраняет состояние между вызовами - Все переменные являются временными - Может возвращать значение через имя функции - Может возвращать несколько значений через VAR_OUTPUT - Может содержать ``VAR_INPUT``, ``VAR_OUTPUT``, ``VAR_IN_OUT``, ``VAR``, ``VAR_TEMP`` - Переменные в группе ``VAR`` не сохраняют состояние (аналогичны ``VAR_TEMP``) **Пример FUNCTION с возвратом через имя функции:** .. code-table:: FUNCTION CalculateAverage : REAL VAR_INPUT value1 : REAL; value2 : REAL; value3 : REAL; END_VAR VAR_TEMP sum : REAL; END_VAR sum := value1 + value2 + value3; CalculateAverage := sum / 3.0; END_FUNCTION **Пример FUNCTION с VAR_OUTPUT:** .. code-table:: FUNCTION ProcessData : BOOL VAR_INPUT input_value : INT; multiplier : INT; END_VAR VAR_OUTPUT result : INT; // Дополнительный выходной параметр error_code : INT; // Дополнительный выходной параметр END_VAR VAR_TEMP temp_value : INT; END_VAR temp_value := input_value * multiplier; IF temp_value > 1000 THEN result := 0; error_code := 1; ProcessData := FALSE; // Возврат через имя функции ELSE result := temp_value; error_code := 0; ProcessData := TRUE; // Возврат через имя функции END_IF; END_FUNCTION **Использование FUNCTION с VAR_OUTPUT:** .. code-table:: PROGRAM MainProgram VAR success : BOOL; result_value : INT; error_code : INT; END_VAR // Вызов функции с VAR_OUTPUT success := ProcessData(input_value := 50, multiplier := 10, result := result_value, error_code := error_code); END_PROGRAM Группы переменных ================= В языке ST переменные объединяются в группы в зависимости от их назначения и области видимости. .. _var-internal-variables: VAR — Внутренние переменные --------------------------- Переменные, объявленные в блоке ``VAR``, являются локальными для данного модуля. - В PROGRAM и FUNCTION_BLOCK сохраняют значение между вызовами - В FUNCTION не сохраняют значение (аналогичны VAR_TEMP) - Могут быть инициализированы при объявлении - Могут иметь прямой доступ к аппаратным портам (с использованием ``AT``), за исключением универсальных входов/выходов **Пример:** .. code-table:: VAR counter : INT := 0; // Инициализированная переменная temp_value : REAL; // Неинициализированная переменная port_input AT %DIN1 : BOOL; // Прямой доступ к порту ввода port_output AT %DOUT1 : BOOL; // Прямой доступ к порту вывода array_data : ARRAY[0..9] OF INT; // Массив END_VAR .. _var-temp-variables: VAR_TEMP — Временные переменные ------------------------------- Переменные, объявленные в блоке ``VAR_TEMP``, являются временными и могут использоваться в любых типах модулей. - Создаются при каждом вызове - Не сохраняют значение между вызовами - Не могут быть инициализированы **Пример:** .. code-table:: PROGRAM ExampleProgram VAR_TEMP temp_counter : INT; // Временная переменная temp_index : INT; // Временная переменная для цикла END_VAR FOR temp_index := 1 TO 10 DO temp_counter := temp_counter + temp_index; END_FOR; END_PROGRAM .. _var-input-parameters: VAR_INPUT — Входные параметры ----------------------------- Переменные, объявленные в блоке ``VAR_INPUT``, используются для передачи данных в модуль извне. - Доступны только для чтения (нельзя изменять внутри модуля) - Могут иметь значения по умолчанию - Для PROGRAM — отображаются как входы в FBD - Для FUNCTION_BLOCK и FUNCTION — входные параметры при вызове - **Могут принимать константы, выражения и переменные** **Пример:** .. code-table:: VAR_INPUT enable : BOOL := TRUE; // Вход с значением по умолчанию setpoint : INT; // Вход без значения по умолчанию reset : BOOL; // Сигнал сброса END_VAR **Передача значений в VAR_INPUT:** .. code-table:: PROGRAM Example VAR pid : PIDController; speed : INT := 100; END_VAR // Передача константы pid(setpoint := 50.0); // Передача выражения pid(setpoint := speed * 2 + 10); // Передача переменной pid(setpoint := speed); END_PROGRAM .. _var-output-parameters: VAR_OUTPUT — Выходные параметры ------------------------------- Переменные, объявленные в блоке ``VAR_OUTPUT``, используются для возврата данных из модуля. - Доступны только для записи (нельзя читать до присваивания) - Сохраняют значение между вызовами (для PROGRAM и FUNCTION_BLOCK) - Для PROGRAM — отображаются как выходы в FBD - Для FUNCTION_BLOCK и FUNCTION — выходные параметры - **Могут принимать только переменные с совпадающим типом данных** **Пример:** .. code-table:: VAR_OUTPUT result : INT; // Выходной результат is_ready : BOOL; // Флаг готовности error_code : DINT; // Код ошибки END_VAR **Правильная передача в VAR_OUTPUT:** .. code-table:: PROGRAM Example VAR pid : PIDController; output_value : REAL; // Переменная для подключения к выходу END_VAR // Правильно: передача переменной pid(setpoint := 100.0, process_value := 95.0); output_value := pid.output; // Чтение из VAR_OUTPUT // Ошибка: нельзя передать константу в VAR_OUTPUT // pid(output := 50.0); // НЕПРАВИЛЬНО! END_PROGRAM .. _var-in-out-parameters: VAR_IN_OUT — Параметры по ссылке -------------------------------- Переменные, объявленные в блоке ``VAR_IN_OUT``, передаются по ссылке. Это позволяет изменять исходные переменные, переданные в модуль. - Изменения внутри модуля влияют на исходную переменную - Не могут иметь значения по умолчанию - Используются для больших структур данных (массивы, строки) - Для PROGRAM — отображаются как входы/выходы в FBD - Для FUNCTION_BLOCK и FUNCTION — параметры по ссылке - **Могут принимать только переменные с совпадающим типом данных** **Пример:** .. code-table:: VAR_IN_OUT inout_data : ARRAY[0..99] OF INT; // Массив по ссылке inout_string : STRING; // Строка по ссылке inout_value : INT; // Целочисленное значение по ссылке END_VAR **Правильная передача в VAR_IN_OUT:** .. code-table:: PROGRAM Example VAR my_data : ARRAY[0..9] OF INT; my_value : INT := 10; END_VAR // Правильно: передача переменной ProcessData(inout_data := my_data, inout_value := my_value); // Ошибка: нельзя передать константу в VAR_IN_OUT // ProcessData(inout_value := 5); // НЕПРАВИЛЬНО! END_PROGRAM Сравнение групп переменных ========================== .. list-table:: :header-rows: 1 :widths: 15, 15, 20, 20, 30 * - Группа - Где используется - Сохраняет значение - Направление - Принимает * - ``VAR`` - PROGRAM, FB, FUNC - Да (кроме FUNC) - Внутренняя - — * - ``VAR_TEMP`` - PROGRAM, FB, FUNC - Нет - Внутренняя - — * - ``VAR_INPUT`` - PROGRAM, FB, FUNC - Зависит от типа - Вход - Константы, выражения, переменные * - ``VAR_OUTPUT`` - PROGRAM, FB, FUNC - Да (для PROGRAM и FB) - Выход - Только переменные * - ``VAR_IN_OUT`` - PROGRAM, FB, FUNC - Нет (ссылка) - Вход/Выход - Только переменные Примеры использования ===================== **Пример PROGRAM с использованием FUNCTION_BLOCK:** .. code-table:: PROGRAM MainProgram VAR pid1 : PIDController; // Экземпляр FUNCTION_BLOCK setpoint : REAL := 100.0; actual : REAL := 95.0; control_output : REAL; error_count : INT := 0; END_VAR VAR_IN_OUT error_counter : INT; // Параметр по ссылке END_VAR VAR_TEMP temp_value : REAL; // Временная переменная END_VAR // Вызов FUNCTION_BLOCK pid1(setpoint := setpoint, process_value := actual, kp := 1.5, // Константа в VAR_INPUT ki := actual * 0.01); // Выражение в VAR_INPUT // Чтение VAR_OUTPUT control_output := pid1.output; // Передача в VAR_IN_OUT error_counter := error_count; END_PROGRAM **Пример FUNCTION с VAR_OUTPUT:** .. code-table:: FUNCTION CalculateStatistics : BOOL VAR_INPUT value1 : REAL; value2 : REAL; value3 : REAL; END_VAR VAR_OUTPUT average : REAL; // Выходной параметр max_value : REAL; // Выходной параметр min_value : REAL; // Выходной параметр END_VAR VAR_TEMP sum : REAL; END_VAR sum := value1 + value2 + value3; average := sum / 3.0; max_value := value1; IF value2 > max_value THEN max_value := value2; END_IF; IF value3 > max_value THEN max_value := value3; END_IF; min_value := value1; IF value2 < min_value THEN min_value := value2; END_IF; IF value3 < min_value THEN min_value := value3; END_IF; CalculateStatistics := TRUE; END_FUNCTION **Использование FUNCTION с VAR_OUTPUT:** .. code-table:: PROGRAM MainProgram VAR success : BOOL; avg : REAL; max : REAL; min : REAL; END_VAR success := CalculateStatistics(value1 := 10.0, value2 := 20.0, value3 := 15.0, average := avg, max_value := max, min_value := min); END_PROGRAM .. note:: - Точность именования переменных и соблюдение синтаксиса имеют важное значение. - Объявление переменных обязательно должно происходить перед их использованием в теле программы. - PROGRAM используется только как функциональный блок в FBD и не может быть вызван из ST-кода. - FUNCTION_BLOCK требует создания экземпляра перед использованием. - VAR_TEMP могут использоваться в любых типах модулей. - При передаче в VAR_INPUT тип данных приводится к типу VAR_INPUT. - VAR_OUTPUT и VAR_IN_OUT требуют передачи переменных с совпадающим типом данных. .. seealso:: * :doc:`data_types` - для информации о типах данных. * :doc:`operators` - для изучения операторов. * :doc:`getting_started` - для информации о создании ST-модуля и его использовании в FBD.