PDA

Просмотр полной версии : Как передать массив в функциональный блок если зарание не известно сколько элемнтов



Serhioromano
26.03.2017, 16:50
Предположим есть массивы


myArray1 := ARRAY[0..2] OF STRING;
myArray2 := ARRAY[0..10] OF STRING;
myArray3 := ARRAY[0..4] OF STRING;

Конечно же все сложней. Это не строки а структура с многотиповым хранением данных.

Есть так же универсальный функциональный блок который может их обработать. Он просто в цикле походит по каждому элементу и делает свое дело.

Когда я поределяю входную переменную мне надо написать


In := ARRAY[0..2] OF STRING;

И вот тут проблема. я ведь могу туда опустить любой массив а у меня разное количество элементов.

Как мне сделать так что бы можно было передать массив с любым колличеством элементов?

capzap
26.03.2017, 21:52
добавляйте а свою структуру некий id, в фб передайте указатель, если у очередного элемента индекс равен нулю, значит массив закончился

Serhioromano
27.03.2017, 07:54
Нет это понятно. Я могу пройти в цикле неопределенное количество элементов. Это не проблема. Как этот массив передать в FB? Ведь мне нужно декларировать переменную входную или локальную и там указвать зарание количество элементов в массиве, так что как я не передавай, входная переменная должна иметь тоже колличество.

capzap
27.03.2017, 08:26
массив, это уложенные последовательно в памяти однородные данные, ни какой массив передавать в ФБ я не предлагаю, а рекомендую передавать указатель на тип данных из которых сформирован массив, начиная с начального элемента массива, а далее как угодно, в цикле определяете когда данные закончились или с этим указателем передавайте количество элементов массива. В оскат библиотеке много таких примеров

slonegd
29.03.2017, 09:48
Когда работал с файлами, там тоже заранее неизвестно сколько и чего записывать надо обычно. Как советует capzap, то просто дать указатель и работать с ним. Также можно передавать и разнородную структуру. Мне было удобно указатель на байт и sizeof структуры, чтобы определить её границы.

Serhioromano
30.03.2017, 03:36
Можно примерчик указателя?

petera
30.03.2017, 07:15
Можно примерчик указателя?

Кусочно-линейная аппроксимация http://www.owen.ru/forum/showthread.php?t=10555&p=220263&viewfull=1#post220263

FUNCTION MyGraf_p : REAL
VAR_INPUT
IN: REAL; (*Входной сигнал*)
pt : POINTER TO ARRAY[0..99] OF Point_GR; (*Массив точек графика, не более 100 пар точек X,Y*)
size : UINT;
END_VAR
VAR
a: INT; (*Начало интервала поиска*)
b: INT; (*Конец интервала поиска*)
N: INT; (*Число точек в графике*)
i: INT;
END_VAR

N:= SHR(size,3)-1; (*Число точек в графике*)
(*Начальные значения интнрвала поиска*)
a:=0;
b:=N-1;

(*Обрезание графика для крайних точек*)
IF IN<=pt^[0].X THEN
MyGraf_p:=pt^[0].Y;
ELSIF IN>=pt^[N-1].X THEN
MyGraf_p:=pt^[N-1].Y;
(*Теперь можно начать поиск*)
ELSE
WHILE (b-a) <> 1 DO (*В конце концов, входной сигнал ТОЧНО попадет между двумя соседними точками X(a) и Х(а+1)*)
i:=(a+b)/2; (*Делим интервал поиска пополам*)
IF IN=pt^[i+1].X THEN (*Может нам повезло, и мы сразу нашли точку? *)
a:=i; b:=i+1; (*Бинго! прекращаем итераций, нечего в пустую молотить :) *)
(*мимо :( ,тогда посмотрим в какую половину интервала попали*)
ELSIF IN>pt^[i].X THEN (*Если входной сигнал больше середины интервала поиска,*)
a:=i; (*то следующий поиск будем делать начиная от середины и до конца массива*)
ELSE (*А если входной сигнал меньше середины интервала поиска,*)
b:=i; (*то следующий поиск будем делать начиная от начала и до середины массива*)
END_IF
(*Таким образом на каждой итерации отбрасываем из поиска заведомо ненужную половину значений
две соседние координаты X(a) и Х(а+1), меду которыми попадает входной сигнал найдем очень быстро
для 8 точек графика нужно не более 3 итераций
при 9..16 точек в графике нужно не более 4 итераций
при 17..32 точек в графике нужно не более 5 итераций
при 33..64 точек в графике нужно не более 6 итераций
при 65..128 точек в графике нужно не более 7 итераций
инфа точная - 100% ;) *)
END_WHILE
(*Теперь самое простое - сделать линейную аппроксимацию по двум точкам ;) *)
MyGraf_p:=pt^[b].Y-(pt^[b].X-IN)*(pt^[b].Y-pt^[a].Y)/(pt^[b].X-pt^[a].X);
END_IF
Сам массив структур передается в функцию через указатель, по этому вызывать ее нужно так
MyGraf_p(IN, ADR(Имя_Массива), SIZEOF(Имя_Массива))

Например

PROGRAM PLC_PRG
VAR
GR: ARRAY [0..49] OF Point_GR:=
(X:=0, Y:=15),(X:=3, Y:=25),(X:=4, Y:=45),(X:=8, Y:=75),(X:=15, Y:=45),
(X:=16, Y:=45),(X:=20, Y:=65),(X:=22, Y:=75),(X:=40, Y:=95),(X:=50, Y:=105),

(X:=110, Y:=15),(X:=120, Y:=25),(X:=130, Y:=45),(X:=140, Y:=75),(X:=150, Y:=45),
(X:=160, Y:=45),(X:=200, Y:=65),(X:=220, Y:=75),(X:=240, Y:=95),(X:=250, Y:=305),

(X:=301, Y:=15),(X:=305, Y:=25),(X:=324, Y:=45),(X:=380, Y:=75),(X:=415, Y:=45),
(X:=416, Y:=45),(X:=420, Y:=65),(X:=422, Y:=75),(X:=440, Y:=495),(X:=450, Y:=505),

(X:=511, Y:=15),(X:=515, Y:=25),(X:=524, Y:=45),(X:=580, Y:=75),(X:=615, Y:=45),
(X:=416, Y:=45),(X:=420, Y:=65),(X:=422, Y:=75),(X:=440, Y:=495),(X:=450, Y:=505),

(X:=621, Y:=15),(X:=625, Y:=25),(X:=634, Y:=45),(X:=680, Y:=75),(X:=695, Y:=45),
(X:=676, Y:=45),(X:=680, Y:=65),(X:=692, Y:=75),(X:=740, Y:=495),(X:=750, Y:=505);

IN: REAL;
OUT: REAL;
END_VAR
(*ВАЖНО!
Таблица должна быть обязательно отсортирована по X в порядке возрастания значений.*)

OUT:=MyGraf_p(IN, ADR(GR), SIZEOF(GR));

capzap
30.03.2017, 07:54
Сам массив структур передается в функцию через указатель, по этому вызывать ее нужно так
это не совсем то про что я говорю,указатель на объект, из чего состоит массив, а не указатель на массив

lazy
30.03.2017, 12:28
как то так:

FUNCTION_BLOCK FB

VAR_INPUT
In : POINTER TO STRING;
Sz: byte;
END_VAR

VAR
str: STRING;
END_VAR

где то в прграмме:
FB( In := adr( myArray1[0] ), Sz := 2 );

А это где то в теле FB:
можно в цикле от нуля до Sz
str := In^ - это myArray1[0];
In := In + sizeof( str ); (* теперь str := In^ - это myArray1[1]; *)

Владимир Ситников
30.03.2017, 12:45
это не совсем то про что я говорю,указатель на объект, из чего состоит массив, а не указатель на массив

Вот интересно. Вроде, должен быть безопасный язык. А чуть что сразу работа с памятью и адресами.
Была бы возможность передавать статические массивы.
Или это в КДС3 уже сделано?

lazy
30.03.2017, 15:39
Была бы возможность передавать статические массивы.

так передавай, хоть по ссылке хоть через указатель. и во втором. в третьем ввобще ссылки есть как сущность )

var_in_out
arr: ARRAY [0..255] OF BYTE; ссылка
end_var

var_in_out
parr: pointer to ARRAY [0..255] OF BYTE; указатель
end_var

кста, не знаю чо будет если в эти переменные скормить массив меньшей длинны. хозяину топика можно былобы проверить )

Евгений Кислов
30.03.2017, 15:46
Была бы возможность передавать статические массивы.[Или это в КДС3 уже сделано?

В КДС3 (начиная с SP8) можно так (естественно, только для VAR_INPUT и VAR_IN_OUT):

30310

Владимир Ситников
30.03.2017, 15:50
так передавай, хоть по ссылке хоть через указатель. и во втором. в третьем ввобще ссылки есть как сущность )
Не понимаю. Разве можно передать массив так, чтобы "на принимающей стороне" компилятор проверял код и сообщал о выходах за границы массива?


кста, не знаю чо будет если в эти переменные скормить массив меньшей длинны. хозяину
Во во. Я и говорю, что в КДС2 нет возможности сделать блок-обработку массива, который мог бы принимать массивы разных размеров и при этом проверялись границы массива на этапе компиляции.

lazy
30.03.2017, 17:14
который мог бы принимать массивы разных размеров и при этом проверялись границы массива на этапе компиляции.

как на этапе компиляции можно знать длину переменного массива? )

а вообще массив с переменной длинной в кодесисе можно самому сделать.

Serhioromano
30.03.2017, 17:33
Короче 3 меня массив это анимация фонтана. Каждый элемент массива это струтура кторая хранит время, начальную точку, конечную точку, тип линейности и время паузы по достижении.

На фонтане 3 контура. Например пока один кнтур за 3 цикла поднимает от 0 до 100, другой контур 3 раза поднимает от 0 до 100 за это время. Значит в массиве первого контура один элемент, а в массиве второго контура 3 элемента.

Блок который это обрабатывает один и тот же. Вот в чем проблема. Если я сделал.

pt : POINTER TO ARRAY[0..99] OF Point_GR;

то и передать мне нужно будет массив с [0..99]. А как? ведь у меня разные длинны массива для каждого контура? Мне чтоделать разные копии блоков для этого? Но ведь я всегда могу добавить новые элементы для дополнительных узоров анимации, и что потом переделывать блоки?

Короче сейчас я делал так. Я передаю в блок просто номер программы. Массивы программы я сделал глобальными, а уже в нутри блока я использую CASE что бы обращаться к нужному массиву.

Пока так. Это вроде работает но мне кажется должен быть более элегантный способ решит эту задачу.

petera
30.03.2017, 21:18
Короче 3 меня массив это анимация фонтана. Каждый элемент массива это струтура кторая хранит время, начальную точку, конечную точку, тип линейности и время паузы по достижении.

На фонтане 3 контура. Например пока один кнтур за 3 цикла поднимает от 0 до 100, другой контур 3 раза поднимает от 0 до 100 за это время. Значит в массиве первого контура один элемент, а в массиве второго контура 3 элемента.

Блок который это обрабатывает один и тот же. Вот в чем проблема. Если я сделал.

pt : POINTER TO ARRAY[0..99] OF Point_GR;

то и передать мне нужно будет массив с [0..99]. А как? ведь у меня разные длинны массива для каждого контура? Мне чтоделать разные копии блоков для этого? Но ведь я всегда могу добавить новые элементы для дополнительных узоров анимации, и что потом переделывать блоки?
Как Вы смотрели пример http://www.owen.ru/forum/showthread.php?t=26394&p=242495&viewfull=1#post242495

Сам массив структур передается в функцию через указатель, по этому вызывать ее нужно так
MyGraf_p(IN, ADR(Имя_Массива), SIZEOF(Имя_Массива))
В функции
pt : POINTER TO ARRAY[0..99] OF Point_GR;
Это максимальное количество! Реальное количество определяется при вызове параметром SIZEOF(Имя_Массива)
в моем примере - это первая строка функции
N:= SHR(size,3)-1; (*Число точек в графике*)

В примере есть вызов функции для графиков с разным количеством точек, например 50 точек
VAR
GR: ARRAY [0..49] OF Point_GR:=
(X:=0, Y:=15),(X:=3, Y:=25),(X:=4, Y:=45),(X:=8, Y:=75),(X:=15, Y:=45),
(X:=16, Y:=45),(X:=20, Y:=65),(X:=22, Y:=75),(X:=40, Y:=95),(X:=50, Y:=105),

(X:=110, Y:=15),(X:=120, Y:=25),(X:=130, Y:=45),(X:=140, Y:=75),(X:=150, Y:=45),
(X:=160, Y:=45),(X:=200, Y:=65),(X:=220, Y:=75),(X:=240, Y:=95),(X:=250, Y:=305),

(X:=301, Y:=15),(X:=305, Y:=25),(X:=324, Y:=45),(X:=380, Y:=75),(X:=415, Y:=45),
(X:=416, Y:=45),(X:=420, Y:=65),(X:=422, Y:=75),(X:=440, Y:=495),(X:=450, Y:=505),

(X:=511, Y:=15),(X:=515, Y:=25),(X:=524, Y:=45),(X:=580, Y:=75),(X:=615, Y:=45),
(X:=416, Y:=45),(X:=420, Y:=65),(X:=422, Y:=75),(X:=440, Y:=495),(X:=450, Y:=505),

(X:=621, Y:=15),(X:=625, Y:=25),(X:=634, Y:=45),(X:=680, Y:=75),(X:=695, Y:=45),
(X:=676, Y:=45),(X:=680, Y:=65),(X:=692, Y:=75),(X:=740, Y:=495),(X:=750, Y:=505);

IN: REAL;
OUT: REAL;
END_VAR

Вызов функции
OUT:=MyGraf_p(IN, ADR(GR), SIZEOF(GR));

Serhioromano
31.03.2017, 19:31
А зачем тут вообще массивы ? Может списки ?
Как образуются данные ?

Можно пример списка? Не пойму о чем речь.

Serhioromano
02.04.2017, 15:33
Понятно. Я вообщем то программист. Хотя и вышел и прикладного программирования. В КДС программирую пару лет. Знаю пяток языков.

Но у меня все еще вопрос что такое списки? На что вы ссылаетесь по этим термином? Думаете я не погуглил по теме списков и КДС? Нет, я погуглил, но ни чего не нашел. Этот термин мне ни о чем не говорит уж извините меня. В КДС есть структуры, есть массивы но списков я не нашел.

Приведите пример хоть как декларировать список в ST? Что за тип данных? Или хотя бы скажите английский термен который используется для этого. По слову list ни чего нет.

Если вы ссылаетесь в общем на концепт программирования или метод структоризации, то покажите как его реализовать в среде ST.

amn
04.04.2017, 00:07
Список - это определяемый пользователем тип данных под названием "перечисление". Посмотрите в документации "Руководство пользователя по программированию ПЛК в CODESYS" (файл CoDeSys_V23_RU.pdf стр. 334) на диске, который идет с ПЛК или на сайте Овена.

Serhioromano
04.04.2017, 15:14
Список - это определяемый пользователем тип данных под названием "перечисление". Посмотрите в документации "Руководство пользователя по программированию ПЛК в CODESYS" (файл CoDeSys_V23_RU.pdf стр. 334) на диске, который идет с ПЛК или на сайте Овена.

Спасибо.


Издеваетесь ?
function_block item //элемент списка
var ...
... //данные
var_output
next : dword; //суть - pointer to item;
end_var
-------------
... //творим


пример прогона списка

var
list, //сам список
p : pointer to item; //времянка
------------
p := list;
while p <> 0 do
p^( ..., next => p);
end_while

Спасибо. Речь идет о перечеслениях. Я понял. Не сразу понял что вы называете списком.

К сожалению я не вижу как я могу заменить свой массив "списком". Вот что у меня. Печатаю без копи\вставить так что могут быть ошибки.



TYPE RepCyc STRUCT
from:INT;
to:int;
ease:STRING;
pause:INT;
cycle:INT;
END_STRUCT


Теперь я объявляю глобальную переменную.



VAR
glbAnimationWave: ARRAY[1..5] OR RepCyc := (from:=20, to:=80, ease:='easeInCubic', pause:=2, cycle:=2).......
END_VAR


И так далее. Где каждый элемент массива это задача как себя поведет фонтан от цикла к циклу.

Перечесления же с другой стороны это


Перечисление - это определяемый пользователем тип данных, задающий несколько строковых псевдонимов для числовых констант.

Хотя я понял о чем идет речь в смысле списков, можете мне посоветовать как мне оптимально их использовать в моей задаче?

Serhioromano
06.04.2017, 10:12
Короче вчера все переписал. Спасибо. Поинтеры работают отлично. А вот как в моем случае использовать перечисления или как Валенок написал списки, я так и не понял.