PDA

Просмотр полной версии : код смены участков программы



werg
26.06.2018, 18:09
Добрый день!
Подскажите, пожалуйста, как реализовать код на ST правильно (что бы не плодить лишние строки и уменьшить используемые ресурсы ПЛК)
Задача такая :
Реализовать переключение участков программы.

В частности интересует следующее:
Есть входные переменные
-Start (Bool)
-от VAL_1 до VAL_n (Real) - задание величины уставки для каждого участка
-от Тime_1 до Time_n (INT) - время выхода на уставку, сиречь время участка от 1 до n
Выходные переменные
- Nr_uch (int) номер участка
-Тime_uch(int) время участка
- И другие не относящиеся к теме вопроса
1) По фронту Start и ненулевому значению входной переменной Time_ начинается участок 1,
выполняются инструкции
2) По внутренней команде(определяется отдельной функцией, не входящей в суть вопроса) происходит переключение на участок 2
выполняются инструкции
.......
.......
n) По внутренней команде(определяется отдельной функцией, не входящей в суть вопроса) происходит переключение на участок n

После окончания участка n цикл завершается.

приборист
26.06.2018, 19:53
Case для такого и придуман

Владимир Ситников
27.06.2018, 08:48
И массивы.

Осинский Алексей
27.06.2018, 09:44
И массивы.

Я бы делал так:

Предположим, у Вас есть глобальная константа, содержащая количество участков в системе


VAR_GLOBAL CONSTANT
g_c_usiMaxSectorsCount : USINT := 10; (* Максимальное количество участков *)
END_VAR


Объявите структуру, которая описывает все данные, которые необходимы для управления участком


(* Данные, относящиеся к одному участку *)
TYPE Sector :
STRUCT
rSetpoint : REAL; (* Уставка *)
timMinExecution : TIME; (* Время выполнения "работы" на участке *)
END_STRUCT
END_TYPE


ФБ, управляющий системой при этом может выглядеть вот так:
Интерфейс:



FUNCTION_BLOCK SystemControl
VAR_INPUT
xStart : BOOL;
astSystemSectors : ARRAY [1..g_c_usiMaxSectorsCount] OF Sector;
END_VAR
VAR_OUTPUT
xBusy : BOOL;
xDone : BOOL;
END_VAR
VAR
m_fb_StartCommand : R_TRIG;
m_usiCurrentSectorId : USINT;
m_stCurrentSector : Sector;
m_fb_SectorExectutionFinish : TON; (* Таймер времени выполнения сектора *)
END_VAR

Реализация:



m_fb_StartCommand.CLK := xStart;
m_fb_StartCommand();

(* Если получена команда на старт и ФБ еще не в работе *)
IF (m_fb_StartCommand.Q) AND (NOT xBusy) THEN
(* Начнем с первого сектора *)
m_usiCurrentSectorId := 1;
(* Сбросим время наработки сектора *)
m_fb_SectorExectutionFinish.IN := FALSE;
m_fb_SectorExectutionFinish();
xDone := FALSE;
xBusy := TRUE;
END_IF

IF xBusy THEN
m_stCurrentSector := astSystemSectors[m_usiCurrentSectorId];
m_fb_SectorExectutionFinish.IN := TRUE;
m_fb_SectorExectutionFinish.PT := m_stCurrentSector.timMinExecution;
m_fb_SectorExectutionFinish();
(* Регулирование где-то здесь *)

(* Если закончилось время выполнения перейти к следующему участку.
Возможно Вам нужно будет доработать это условие в соответствии с Вашими требованиями *)
IF m_fb_SectorExectutionFinish.Q THEN
m_usiCurrentSectorId := m_usiCurrentSectorId + 1;
m_fb_SectorExectutionFinish.IN := FALSE;
m_fb_SectorExectutionFinish();
END_IF

(* Если закончились все сектора *)
IF m_usiCurrentSectorId > g_c_usiMaxSectorsCount THEN
(* Работа завершена *)
xDone := TRUE;
xBusy := FALSE;
END_IF
END_IF


То же самое, но в виде проекта: