sakanchik
10.03.2026, 18:26
Всем добрый день.
Я только начинаю изучать язык Structured Text и программирование ПЛК в целом. Работаю с Owen Logic и контроллером ПР200. До этого в основном использовал FBD, но сейчас пытаюсь освоить ST, потому что для более сложной логики он кажется удобнее.В качестве практики пытаюсь написать программу управления коптильной камерой. Логика примерно такая:есть рецепты,в каждом рецепте есть несколько шагов,каждый шаг соответствует определённому процессу (нагрев, розжиг, копчение, проветривание и т.д.),оператор может редактировать рецепт, выбирая процесс для каждого шага,затем программа выполняет шаги по порядку.
Пока я сделал простую архитектуру:
Рецепты хранятся в массиве RecipeSteps,каждый элемент массива хранит номер процесса,по номеру процесса через CASE включаются нужные выходы.
Это мой первый более-менее большой кусок ST, поэтому понимаю, что в нём могут быть ошибки и не самые правильные решения.
Буду очень благодарен, если подскажете.Правильно ли я вообще выбрал архитектуру,есть ли более правильный способ хранить рецепты,как лучше организовать редактирование шагов,нет ли типичных ошибок начинающих, которые я уже допустилю
Код прикладываю ниже:
FUNCTION_BLOCK koptilna
VAR_INPUT
ProgramRun : BOOL; //программа в работе
BtnStart : BOOL; //запуск программы
BtnStop : BOOL; //стоп рограммы
SelectRecipe : UDINT; // выбранный рецепт
EditStep : UDINT; // редактирование шага
SelectProcess : UDINT; // выбранный процесс
END_VAR
VAR_OUTPUT
HeatCamera : BOOL; //нагрев камеры
HeatGen : BOOL; //розжиг дымогенератора
Speed1 : BOOL; //двигатели скорость 1
Speed2 : BOOL; //двигатели скорость 2
Valve1 : BOOL; //выброс 1/3
Valve2 : BOOL; //выброс 2/3
Boost : BOOL; //наддув
Blowdown : BOOL; //поддув
Firefighting : BOOL; //пожаротушение
Stirrer : BOOL; //ворошитель
Sink : BOOL; //мойка
Hydration : BOOL; //увлажнение
CurenStep : UDINT; //позицая шага
END_VAR
VAR
RecipeSteps : ARRAY [0..200] OF UDINT;
RecipeIndex : UDINT; // индекс рецепта
EditIndex : UDINT; // индекс редактирования
SelectProcessOld : UDINT; //старое значение выбраного процесса
StepNomber : UDINT; //номер шага
END_VAR
//Значение по умолчанию для выходов
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
//Запуск программы
IF BtnStart THEN
ProgramRun := TRUE;
CurenStep := 1;
END_IF;
//Остановка программы
IF BtnStop THEN
ProgramRun := FALSE;
CurenStep := 1;
END_IF
//Автоматическое сохранние при редактировании рецепта
IF SelectProcess <> SelectProcessOld THEN
IF (SelectProcess >= 0) AND (SelectProcessOld <=10) THEN
IF (EditStep >= 0) AND (EditStep <=20) THEN
EditIndex := (SelectRecipe - 1) * 20 + EditStep;
RecipeSteps [EditIndex] := SelectProcess;
END_IF
END_IF
END_IF
StepNomber := RecipeSteps [RecipeIndex];
//Режимы работы
CASE StepNomber OF
0://Завершение процессов
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
1://Нагрев
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := TRUE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
2://Розжиг
HeatCamera := TRUE;
HeatGen := TRUE;
Speed1 := TRUE;
Speed2 := FALSE;
Valve1 := TRUE;
Valve2 := TRUE;
Boost := TRUE;
Blowdown := TRUE;
Firefighting := FALSE;
Stirrer := TRUE;
Sink := FALSE;
Hydration := TRUE;
3://Копчения
HeatCamera := TRUE;
HeatGen := TRUE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := FALSE;
Valve2 := TRUE;
Boost := TRUE;
Blowdown := TRUE;
Firefighting := FALSE;
Stirrer := TRUE;
Sink := FALSE;
Hydration := TRUE;
4://Проветривание
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := TRUE;
Valve2 := TRUE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
5://Мойка
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := TRUE;
Hydration := FALSE;
6://Сушка
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
END_CASE;
END_FUNCTION_BLOCK
Заранее спасибо всем, кто подскажет, куда лучше двигаться дальше.
Любая критика и советы приветствуются.
Я только начинаю изучать язык Structured Text и программирование ПЛК в целом. Работаю с Owen Logic и контроллером ПР200. До этого в основном использовал FBD, но сейчас пытаюсь освоить ST, потому что для более сложной логики он кажется удобнее.В качестве практики пытаюсь написать программу управления коптильной камерой. Логика примерно такая:есть рецепты,в каждом рецепте есть несколько шагов,каждый шаг соответствует определённому процессу (нагрев, розжиг, копчение, проветривание и т.д.),оператор может редактировать рецепт, выбирая процесс для каждого шага,затем программа выполняет шаги по порядку.
Пока я сделал простую архитектуру:
Рецепты хранятся в массиве RecipeSteps,каждый элемент массива хранит номер процесса,по номеру процесса через CASE включаются нужные выходы.
Это мой первый более-менее большой кусок ST, поэтому понимаю, что в нём могут быть ошибки и не самые правильные решения.
Буду очень благодарен, если подскажете.Правильно ли я вообще выбрал архитектуру,есть ли более правильный способ хранить рецепты,как лучше организовать редактирование шагов,нет ли типичных ошибок начинающих, которые я уже допустилю
Код прикладываю ниже:
FUNCTION_BLOCK koptilna
VAR_INPUT
ProgramRun : BOOL; //программа в работе
BtnStart : BOOL; //запуск программы
BtnStop : BOOL; //стоп рограммы
SelectRecipe : UDINT; // выбранный рецепт
EditStep : UDINT; // редактирование шага
SelectProcess : UDINT; // выбранный процесс
END_VAR
VAR_OUTPUT
HeatCamera : BOOL; //нагрев камеры
HeatGen : BOOL; //розжиг дымогенератора
Speed1 : BOOL; //двигатели скорость 1
Speed2 : BOOL; //двигатели скорость 2
Valve1 : BOOL; //выброс 1/3
Valve2 : BOOL; //выброс 2/3
Boost : BOOL; //наддув
Blowdown : BOOL; //поддув
Firefighting : BOOL; //пожаротушение
Stirrer : BOOL; //ворошитель
Sink : BOOL; //мойка
Hydration : BOOL; //увлажнение
CurenStep : UDINT; //позицая шага
END_VAR
VAR
RecipeSteps : ARRAY [0..200] OF UDINT;
RecipeIndex : UDINT; // индекс рецепта
EditIndex : UDINT; // индекс редактирования
SelectProcessOld : UDINT; //старое значение выбраного процесса
StepNomber : UDINT; //номер шага
END_VAR
//Значение по умолчанию для выходов
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
//Запуск программы
IF BtnStart THEN
ProgramRun := TRUE;
CurenStep := 1;
END_IF;
//Остановка программы
IF BtnStop THEN
ProgramRun := FALSE;
CurenStep := 1;
END_IF
//Автоматическое сохранние при редактировании рецепта
IF SelectProcess <> SelectProcessOld THEN
IF (SelectProcess >= 0) AND (SelectProcessOld <=10) THEN
IF (EditStep >= 0) AND (EditStep <=20) THEN
EditIndex := (SelectRecipe - 1) * 20 + EditStep;
RecipeSteps [EditIndex] := SelectProcess;
END_IF
END_IF
END_IF
StepNomber := RecipeSteps [RecipeIndex];
//Режимы работы
CASE StepNomber OF
0://Завершение процессов
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
1://Нагрев
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := TRUE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
2://Розжиг
HeatCamera := TRUE;
HeatGen := TRUE;
Speed1 := TRUE;
Speed2 := FALSE;
Valve1 := TRUE;
Valve2 := TRUE;
Boost := TRUE;
Blowdown := TRUE;
Firefighting := FALSE;
Stirrer := TRUE;
Sink := FALSE;
Hydration := TRUE;
3://Копчения
HeatCamera := TRUE;
HeatGen := TRUE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := FALSE;
Valve2 := TRUE;
Boost := TRUE;
Blowdown := TRUE;
Firefighting := FALSE;
Stirrer := TRUE;
Sink := FALSE;
Hydration := TRUE;
4://Проветривание
HeatCamera := FALSE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := TRUE;
Valve2 := TRUE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
5://Мойка
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := FALSE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := TRUE;
Hydration := FALSE;
6://Сушка
HeatCamera := TRUE;
HeatGen := FALSE;
Speed1 := FALSE;
Speed2 := TRUE;
Valve1 := FALSE;
Valve2 := FALSE;
Boost := FALSE;
Blowdown := FALSE;
Firefighting := FALSE;
Stirrer := FALSE;
Sink := FALSE;
Hydration := FALSE;
END_CASE;
END_FUNCTION_BLOCK
Заранее спасибо всем, кто подскажет, куда лучше двигаться дальше.
Любая критика и советы приветствуются.