PDA

Просмотр полной версии : Не явное обращение к переменным



Igor_Efremenko
27.02.2018, 11:29
Доброго времени суток!
Помогите, пожалуйста разобраться с такой ситуацией:

Предположим:
1) есть несколько переменных А1,А2,А3, содержащие некоторые значения;
2) Есть переменная того же типа, которой необходимо присвоить значение одной из этих переменных;
3) Есть строковая переменная В, которая содержит название переменной, от которой необходимо получить значение

Пробую делать так:

PROGRAM TestVar
VAR
A:WORD;
A1:WORD;
A2:WORD;
A3:WORD;
B:STRING(20);
pw:POINTER TO WORD;
END_VAR


---------- Сама программа ---------------

A:=0;

A1:=111;
A2:=222;
A3:=333;

B:='A1';

pw:=ADR( ПреобразоватьСодержимое(В) ); (* ТУТ ЯВНО ОШИБКА, но как написать правильно ??? *)

A:=pw^;

Как правильно реализовать?

capzap
27.02.2018, 11:35
IF B='A1' THEN
pw:=ADR(A1);
ELSIF B='A2' THEN
pw:=ADR(A2);
ELSIF B='A3' THEN
pw:=ADR(A3);
END_IF;
так попробуйте

Igor_Efremenko
27.02.2018, 11:47
IF B='A1' THEN
pw:=ADR(A1);
ELSIF B='A2' THEN
pw:=ADR(A2);
ELSIF B='A3' THEN
pw:=ADR(A3);
END_IF;
так попробуйте

Проблема в том, что я не могу знать чему именно будет равно, а переменных типа А1,А2..... - предположительно будет порядка 30000

PS Программа будет получать данные о том, из какой именно надо будет прочитать значение переменной

Dimensy
27.02.2018, 11:47
IF B='A1' THEN
pw:=ADR(A1);
ELSIF B='A2' THEN
pw:=ADR(A2);
ELSIF B='A3' THEN
pw:=ADR(A3);
END_IF;
так попробуйте
а зачем тогда указатель использовать?

Igor_Efremenko
27.02.2018, 11:51
...а какие варианты, если не использовать перечисление полного списка?

Dimensy
27.02.2018, 11:56
Проблема в том, что я не могу знать чему именно будет равно, а переменных типа А1,А2..... - предположительно будет порядка 30000

PS Программа будет получать данные о том, из какой именно надо будет прочитать значение переменной
А что Вы вообще хотите реализовать? Если, типа работа с рецептами, то где-то здесь была темка по этому поводу

Igor_Efremenko
27.02.2018, 12:17
Суть следующая:
Имеется огромное количество запорной арматуры(кранов) и пользователь динамически может формировать некоторую последовательность из этих кранов
... может быть порядка 2-50 кранов из общего числа (30000)
Задача: проанализировать состояние этих кранов (т.е. имеется 30000 УникПеременных.state; оператор указывает какие именно УникПеременных нужно анализировать сегодня)
В итоге наполняется вот такая структура:
35845

Вопрос: Как теперь зная имя переменной обратиться к её значению STATE (например ZDV0116.STATE, которая описана отдельно) ?

PS Можно просто завести переменную ZDV0116:WORD; (не принципиально).... как к ней обратиться, зная её имя?

Igor_Efremenko
27.02.2018, 12:22
Можно-ли получить указатель например таким образом:
pw:=ADR('A1');
....указатель на ячейку памяти, где хранится значение переменной А1 ?

capzap
27.02.2018, 12:26
нет в языках МЭК такого понятия как eval
Указатель возвращает адрес области памяти, где храниться значение объекта, ни о каких именах переменных он не знает. С указателем можно только узнать адрес начального объекта и смещать на размер байт, согласно типа данных этого/их объекта/ов

Igor_Efremenko
27.02.2018, 12:28
Может как-то можно эту проблему решить другим способом, без указателей?

Igor_Efremenko
27.02.2018, 12:30
PS Используется программный PLC

melky
27.02.2018, 16:30
формированием маски массива, то, что "1" принимаем в работу, что "0" не принимаем.
Не знаю, как это на ST описать, на C# примерно такое делал, там где проставлял true, уходило в работу, остальное отбрасывалось.

У меня было два массива в результате. в Первом "источник" (например кран 1, кран 10, кран 23 и т.д.) во втором их данные.

Осинский Алексей
28.02.2018, 12:22
Предположим у Вас есть ФБ ValveController, который осуществляет управление задвижкой.

ФБ выглядит примерно так:


FUNCTION_BLOCK ValveController
VAR_INPUT
sNameToSet : STRING;
END_VAR
VAR_OUTPUT
sName : STRING;
END_VAR
VAR
END_VAR

// Тело ФБ:
IF (sName = '') AND (sNameToSet <> '') THEN
sName := sNameToSet;
END_IF


Там, где Вам необходимо объявите массив ФБ (для примера объявлю в глобальных переменных):


VAR_GLOBAL CONSTANT
g_c_uiValvesCount : UINT := 30;
END_VAR
VAR_GLOBAL
g_astValvesList : ARRAY [1..g_c_uiValvesCount] OF ValveController;
i : UINT;
END_VAR


и проинициализируйте его например так:


IF NOT m_xIsValvesInitialized THEN
FOR i := 1 TO g_c_uiValvesCount DO
g_astValvesList[i].sNameToSet := UINT_TO_STRING (i);
g_astValvesList[i]();
END_FOR
m_xIsValvesInitialized := TRUE;
END_IF



Когда станет известно к какой задвижке обратиться Вам нужно будет всего лишь найти индекс задвижки в массиве зная ее имя.
Например так:



(*
Функция возвращает индекс задвижки в массиве по ее имени.
Если задвижка с указанным именем не найдена - вернет 0
*)
FUNCTION FindValveIndexByName : UINT
VAR_INPUT
sValveToFindName : STRING;
END_VAR
VAR
i : UINT;
END_VAR

// Тело функции
FindValveIndexByName := 0;
i := 1;
WHILE (FindValveIndexByName = 0) AND (i <= g_c_uiValvesCount) DO
IF g_astValvesList[i].sName = sValveToFindName THEN
FindValveIndexByName := i;
END_IF
i := i + 1;
END_WHILE


Когда нужно будет обратиться к задвижке выполните код


uiCurrentValveIndex := FindValveIndexByName ('5');
IF uiCurrentValveIndex > 0 THEN
(* Тут выполняете необходимые манипуляции с задвижкой примерно так g_astValvesList[uiCurrentValveIndex].state *)
END_IF


Единственное что нужно помнить - перебор 30000 значений приведет к увеличению времени цикла.
Поэтому выполняйте поиск по имени только тогда, когда это действительно важно.

В приложении файл, содержащий код из этого сообщения.

Осинский Алексей
28.02.2018, 12:40
Если же Вы хотите сохранить возможность работы с задвижкой по имени переменной в программе подойдет второй способ:

Допустим ФБ Вашей задвижки выглядит так:


FUNCTION_BLOCK ValveController
VAR_INPUT
END_VAR
VAR_OUTPUT
dwState : DWORD;
END_VAR
VAR
END_VAR


Объявите структуру


TYPE NAMED_VALVE :
STRUCT
sName : STRING;
pfbValve : POINTER TO ValveController;
END_STRUCT
END_TYPE


Объявите массив структур (для примера в глобальных переменных)


VAR_GLOBAL CONSTANT
g_c_uiValvesCount : UINT := 30;
END_VAR
VAR_GLOBAL
g_astValvesList : ARRAY [1..g_c_uiValvesCount] OF NAMED_VALVE;
END_VAR


Инициализируйте массив например так:


IF NOT m_xIsValvesInitialized THEN
FOR i := 1 TO g_c_uiValvesCount DO
g_astValvesList[i].sName := UINT_TO_STRING (i);
g_astValvesList[i].pfbValve := 0; (* Вместо 0 ADR (экземпляр ФБ задвижки) *)
END_FOR
m_xIsValvesInitialized := TRUE;
END_IF


Когда станет известно к какой задвижке обратиться Вам нужно будет всего лишь найти индекс задвижки в массиве зная ее имя.
Например так:


(*
Функция возвращает индекс задвижки в массиве по ее имени.
Если задвижка с указанным именем не найдена - вернет 0
*)
FUNCTION FindValveIndexByName : UINT
VAR_INPUT
sValveToFindName : STRING;
END_VAR
VAR
i : UINT;
END_VAR

// Тело функции
FindValveIndexByName := 0;
i := 1;
WHILE (FindValveIndexByName = 0) AND (i <= g_c_uiValvesCount) DO
IF g_astValvesList[i].sName = sValveToFindName THEN
FindValveIndexByName := i;
END_IF
i := i + 1;
END_WHILE


Чтобы обратиться к задвижке выполните код


uiCurrentValveIndex := FindValveIndexByName ('5');
IF uiCurrentValveIndex > 0 THEN
IF g_astValvesList[i].pfbValve <> 0 THEN
;(* Тут выполняете необходимые манипуляции с задвижкой примерно так g_astValvesList[i].pfbValve^.dwState*)
END_IF
END_IF

Dimensy
28.02.2018, 14:09
Э-э, я дико извеняюсь, но объясните, пожалуйста, в чем смысл такой конструкции


Код:

FUNCTION_BLOCK ValveController
VAR_INPUT
sNameToSet : STRING;
END_VAR
VAR_OUTPUT
sName : STRING;
END_VAR
VAR
END_VAR

// Тело ФБ:
IF (sName = '') AND (sNameToSet <> '') THEN
sName := sNameToSet;
END_IF

Там, где Вам необходимо объявите массив ФБ (для примера объявлю в глобальных переменных):
Код:

VAR_GLOBAL CONSTANT
g_c_uiValvesCount : UINT := 30;
END_VAR
VAR_GLOBAL
g_astValvesList : ARRAY [1..g_c_uiValvesCount] OF ValveController;
i : UINT;
END_VAR


Не проще ли тупо написать g_astValvesList : ARRAY [1..g_c_uiValvesCount] OF STRING

Осинский Алексей
28.02.2018, 16:06
Э-э, я дико извеняюсь, но объясните, пожалуйста, в чем смысл такой конструкции

Не проще ли тупо написать g_astValvesList : ARRAY [1..g_c_uiValvesCount] OF STRING

Написать-то можно. А как потом понять что за задвижка под этим именем понимается?
Варианта 2:
1) Задвижка сама знает своем имя и входит в общий список задвижек (решение, приведенное в посте 13 (http://www.owen.ru/forum/showthread.php?t=28309&p=271524&viewfull=1#post271524));
2) Задвижки не знают своих имен, но где-то в системе есть список всех задвижек с именами и указателями на них (решение, приведенное в посте 14 (http://www.owen.ru/forum/showthread.php?t=28309&p=271530&viewfull=1#post271530)).

Igor_Efremenko
02.03.2018, 12:53
Написать-то можно. А как потом понять что за задвижка под этим именем понимается?
Варианта 2:
1) Задвижка сама знает своем имя и входит в общий список задвижек (решение, приведенное в посте 13 (http://www.owen.ru/forum/showthread.php?t=28309&p=271524&viewfull=1#post271524));
2) Задвижки не знают своих имен, но где-то в системе есть список всех задвижек с именами и указателями на них (решение, приведенное в посте 14 (http://www.owen.ru/forum/showthread.php?t=28309&p=271530&viewfull=1#post271530)).

Большое спасибо, Осинский Алексей!