PDA

Просмотр полной версии : Как правильно объявить структуру?



Вова
28.03.2011, 09:47
Здравствуйте!
Я новичок, только изучаю CoDeSys. Пробую в разделе глобальных переменных создать структуру по примеру из руководства:

VAR_GLOBAL
TYPE STRUCT1
STRUCT
p1:INT;
p2:INT;
p3:DWORD;
END_STRUCT
END_VAR
Ругается (скрин ошибок ниже). Скажите пожалуйста, что не так делаю? Прилагаю проект.

Александр Приходько
28.03.2011, 10:21
VAR_GLOBAL уберите.

Вова
28.03.2011, 10:35
Убрал. Но и сам пробовал уже. Ругается

Ошибка 4024: Global_Variables (1): Должно быть VAR_GLOBAL перед 'TYPE'

Александр Приходько
28.03.2011, 11:18
Все верно. Потому что структуры нужно объявлять в особом месте, читаем справку Codesys :


Структуры
Структуры создаются на вкладке Типы данных Организатора Объектов. Объявление должно начинаться с ключевых слов TYPE и STRUCT и заканчиваться строками END_STRUCT и END_TYPE.

Синтаксис:

TYPE <Имя _структуры>:

STRUCT

<Объявление переменной 1>

.

.

<Объявление переменной n>

END_STRUCT

END_TYPE

<Имя _структуры> образует новый тип данных, который может быть использован в любой части проекта наряду с базовыми типами.

Вложенные структуры допускаются. Единственное ограничение заключается в запрете размещения элементов структуры по прямым адресам (AT объявления недопустимы!).

Пример объявления структуры по имени Polygonline:

TYPE Polygonline:

STRUCT

Start:ARRAY [1..2] OF INT;

Point1:ARRAY [1..2] OF INT;

Point2:ARRAY [1..2] OF INT;

Point3:ARRAY [1..2] OF INT;

Point4:ARRAY [1..2] OF INT;

End:ARRAY [1..2] OF INT;

END_STRUCT

END_TYPE



Пример инициализации структуры:

Poly_1:polygonline := ( Start:=3,3, Point1 =5,2, Point2:=7,3, Point3:=8,5, Point4:=5,7, End := 3,5);

Для доступа к элементам структуры используется следующий синтаксис:

<Имя_структуры>.<Имя_компонента>

Например, структура "Week" содержит компонент "Monday", обращение к которому будет выглядеть так:

Week.Monday

Вова
28.03.2011, 11:33
Спасибо большое!
Сам виноват, две страницы вниз не пролистал..
Тему можно закрывать.

Thorn
27.07.2011, 19:30
ограничение заключается в запрете размещения элементов структуры по прямым адресамВот эта штука сильно осложняет жизнь :( Нет ли какого либо обходного пути? Проблема такая - в var_global пара сотен переменных на которые забиндены адреса в modbus slave. Тяжело работать с таким количеством имён, вот если бы их как-то разделять на секции по устройствам (часто одинаковым) или по назначению, структуры бы подошли идеально, но...

Thorn
28.07.2011, 21:00
А зачем увлекаться прямым заданием глобальных переменных, неужели нельзя проще в самом слейв-устройстве присвоить имя каждому каналу, вот и будет Вам группировка по секциям и точно так же в процессе работы они станут глобальными переменнымиЭто плохая идея. Слейв там один, через него идёт обмен с сенсорной панелью и скадой. А теперь представьте что вы поменяли тип CPU, у вас ес-но слетел PLC Configuration и вам надо заново при помощи мыши заполнить всю эту богодельню (повторяю, около 200 переменных только обмен с сенс. панелью). Переменные однозначно надо описывать в VAR_GLOBAL, много проще переправить адреса в текстовом файле если что.

Как образец реальный кусок обмена с паналью на конкурирующей системе (не CoDeSys, физ. адреса не нужны):
=========================

TYPE
PI : STRUCT
PB : REAL := 0.0;
TI : REAL := 0.0;
DBand : REAL := 0.0;
FMT : REAL := 0.0;(*Full movement time - s*)
MinBreakTime : REAL := 0.0; (*ms*)
MinPulseTime : REAL := 0.0; (*ms*)
END_STRUCT;
END_TYPE

netPID : PI; // PI regulator of the network circuit
b1PID : PI; // PI regulator of burner 1
b2PID : PI; // PI regulator of burner 2

=========================
CoDeSys:

iHWSPump1manSt AT %QX6.4.0.0: BOOL;(*B24*)
iHWSPump2manSt AT %QX6.4.0.1: BOOL;(*B25*)
alarmFlowIHWS AT %QX6.4.0.2: BOOL;(*B26*)
alarmMot1IHWS AT %QX6.4.0.3: BOOL;(*B27*)
alarmMot2IHWS AT %QX6.4.0.4: BOOL;(*B28*)

_здесь выкинут кусок переменных других устройств_

iHWSHiLimit AT %QW6.45.0: WORD;(*W38*)
iHWSLoLimit AT %QW6.46.0: WORD;(*W39*)
IHWSdelay AT %QW6.47.0: WORD;(*W40*)

_здесь выкинут ещё кусок ещё других устройств_
_и снова булевские_

IHWSMan3WayLess AT %QX6.140.0.2: BOOL;(*B2111*)
IHWSMan3WayMore AT %QX6.140.0.3: BOOL;(*B2111*)
_и т.д.

Как бы это примерно могло выглядеть в CoDeSys:

iHWS : STRUCT (*Насос ГВС*)
pump1manSt AT %QX6.4.0.0: BOOL;(*B24*)
pump2manSt AT %QX6.4.0.1: BOOL;(*B25*)
alarmFlow AT %QX6.4.0.2: BOOL;(*B26*)
alarmMot1 AT %QX6.4.0.3: BOOL;(*B27*)
alarmMot2 AT %QX6.4.0.4: BOOL;(*B28*)
man3WayLess AT %QX6.140.0.2: BOOL;(*B2111*)
man3WayMore AT %QX6.140.0.3: BOOL;(*B2111*)
hiLimit AT %QW6.45.0: WORD;(*W38*)
loLimit AT %QW6.46.0: WORD;(*W39*)
delay AT %QW6.47.0: WORD;(*W40*)
END_STRUCT;

iNet : STRUCT (*Насос сети*)
pump1manSt AT %QX6.3.0.1: BOOL;(*B17*)
pump2manSt AT %QX6.3.0.2: BOOL;(*B18*)
_И Так Далее._

END_STRUCT;


Нет, жить можно, но когда за месяц проходят через руки несколько проектов на одну тему но с разными вводными - рехтование каждый раз общей свалки малость удручает. И просто думаешь - а вдруг я пропустил что-то очевидное, что используют другие.

P.S. - Мда, чем больше я на свою-же статью смотрю, тем больше понимаю что основное зло не столько в запрете на структуры, сколько в самих физ адресах... Ладно, не важно.

Thorn
31.07.2011, 20:42
В развитие ответа capzap — указатель на структуру.
Способ очень интересный, спасибо. Единственно сразу нашлась ложка дёгтя - биты напрямую упаковывать не удастся, поскольку CoDeSys под булевую переменную отводит 1 байт, после маппинга на абс. адрес в "PLC Config" получается что 1 это 1, 2 это 256, 4 это 65536 и т.д., т.е. в двойном слове без дополнительных извратов можно передать не более 4 булевых переменных, да ещё при этом на стороне скады/панели эту ситуёвину разруливать. Ну или и там структуру нарисовать ;) если пакет программирования позволит.

Thorn
01.08.2011, 16:36
Угу, хорошо. Попробуем нарисовать тест:


(**********Структура************)
TYPE singlePump : (*Насос с одним двигателем*)
STRUCT
(* pumpEn :bool; (*Пуск разрешён*)
pumpManSt :bool; (*Ручной пуск*)
*)
bools :WORD;(*Булевые переменные (см.выше)*)
img :WORD; (*маска состояния - 2#1-руч;2#10авар.;2#100раб.;*)
flowDelay :WORD; (*начальная задержка по протоку - сек.*)
maxGapTime :WORD; (*максимальный провал на установленном потоке - сек.*)
END_STRUCT
END_TYPE

(**********Константы битов************)
VAR_GLOBAL CONSTANT
pumpEn:INT := 0; (*Пуск разрешён*)
pumpManSt:INT := 1; (*Ручной пуск*)
END_VAR

(**********Экземпляры структур************)
VAR_GLOBAL
pump1,pump2,pump3:POINTER TO singlePump;
END_VAR

(**********PLC_PRG************)
(*Настраиваем начальные адреса структур (надо-бы перевесить на "Event Start")*)
pump1 := ADR(%QW6.1.0);(*начальный адрес слейва панели*)
pump2 := pump1 + SIZEOF(pump1^);
pump3 := pump2 + SIZEOF(pump1^) ;

(*Проверка доступности полей*)
pump2^.pumpManSt := TRUE;
pump1^.flowDelay := 5;
Ну в общем почти... :) Единственно что не нравится это секция "VAR_GLOBAL CONSTANT" - лишняя она, но с другой стороны пользовать "pump1^.bools.1" и каждый раз выяснять в комментах что это такое - тоже не дело.

Thorn
01.08.2011, 22:01
При тестировании выплыл ещё один косячок.

Так размер структуры равен 8 байт:
STRUCT
bools :WORD;
img :INT;
temp :REAL;
END_STRUCT

А вот так 12 байт:
STRUCT
bools :WORD;
temp :REAL;
img :INT;
END_STRUCT

Данные при передаче понятно тоже сдвигаются. Помнится в Сях на этот случай был ключик #pragma pack. Здесь аналога похоже нет, так что надо иметь в виду...

Загнетов
03.09.2012, 12:09
А вот именно в КДС и необязательно с булями возится. Биту дал имя, и обращайся к нему как элементу структуры.
Var
Mask:word;
Const
Who:byte:=3
Mask.Who:=FALSE;

Хочется word'ы раскрыть в онлайне полями как структуру ? bitaccess в помощь.


Ваш способ интересный, но возможны ситуации, когда константа (Who) ошибочно применена ( для индексации положения бита в слове) не к той структуре, для которой она предназначена.
И таких констант в программе при упаковывании битов может быть несколько сотен...

Компилятор такую смысловую ошибку не заметит, ведь синтаксис не нарушен, а константу можно использовать для любых целей :eek:

const
who:byte:=3; (*адрес бита в structrure_1 *)
regime:byte:=5; (*адрес бита в structrure_2 *)

strusture_1.who:= FALSE;

structure_2.who:= FALSE;
structure_2.regime:= FALSE; (* ошибка *)

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

в итоге - за такое удобство придется заплатить тем, от чего пытались уйти.

gtfox
17.04.2014, 19:06
При тестировании выплыл ещё один косячок.

Так размер структуры равен 8 байт:
STRUCT
bools :WORD;
img :INT;
temp :REAL;
END_STRUCT

А вот так 12 байт:
STRUCT
bools :WORD;
temp :REAL;
img :INT;
END_STRUCT

Данные при передаче понятно тоже сдвигаются. Помнится в Сях на этот случай был ключик #pragma pack. Здесь аналога похоже нет, так что надо иметь в виду...

struct ровняется под кварту в отличие от ФБ. И sizeof офлайн/онлайн - из-за этого могут отличаться. Но лично я тоже предпочитаю явное указание пустышек.
мда... и об этом можно узнать только с форума, а не из документации

gtfox
17.04.2014, 20:07
я выкладывал на просторах форума пример, где в конфигураторе объявлял только одну переменную, по ней находил адрес канала, остальные каналы брались по смещению. Мне кажется такой подход к программе Вашего случая будет портироваться на любой ПЛК ("тип CPU")

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

ps
благо Ctrl+V работает в конфигурации плк без лишних вопросов

gtfox
18.04.2014, 08:54
А по подробнее, что там с панелью, у меня такой подход применяется на производстве,где панель слейв и всё работает

ага, ясно. У меня панель мастер. А если контроллер мастер то работает.
видимо слейв овена так написан, что он обрабатывает запросы только к переменным, натыканным в конфигурации плк.

gtfox
18.04.2014, 18:41
А к каким переменным еще нужно обрабатывать ?
точно не помню, стандарт это или ограничения модикона... от 400001 до 465536

Ryzhij
19.04.2014, 12:47
точно не помню, стандарт это или ограничения модикона... от 400001 до 465536
Объявите, и хоть об-обрабатывайтесь ;)
А пока Вы их в структуру не внесёте - их для системы просто не существует, ни самих переменных, ни, как следствие, их свойств.
Что и как тут обрабатывать?
"Нам бы схемку, аль чертёж - мы б затеяли вертёж. Ну, а так, как ни старайся..."

gtfox
21.04.2014, 09:15
А их нету. Как обрабатывать-то ?

Что и как тут обрабатывать?

Благодарю, все понял.

PS
Ну я вообще вот из-за этого вопроса (http://www.owen.ru/forum/showthread.php?t=17119) начал копаться в этих делах. у ваги не надо было ничего натыкивать.

PPS
Если надо обязательно объявлять в конфигурации все что будет использоваться то как вот это работает (я не проверял)

я выкладывал на просторах форума пример, где в конфигураторе объявлял только одну переменную, по ней находил адрес канала, остальные каналы брались по смещению. Мне кажется такой подход к программе Вашего случая будет портироваться на любой ПЛК ("тип CPU")

amn
21.04.2014, 17:37
Добавляете в конфигурации столько регистров, чтобы их общий размер был такой же, как у структуры. Размер структуры должен быть кратным 4 байтам для выравнивания. Имя даете только первому регистру. Далее в начале программы структуре через указатель присваиваете значения из конфигурации

Ptr_slave:=ADR(first_config); (*адрес первого элемента конфигурации*)
slv:=Ptr_slave^; (*переменная типа "структура" получает все значения из конфигурации*)

... (*далее в программе используем структуру вместо конфигурации*)

в конце программы

Ptr_slave^:=slv; (*копируем значения из структуры в конфигурацию*)

P.S. прежде чем воспользоваться примером почитайте эту ссылку http://www.owen.ru/forum/showthread.php?t=12362&p=153876&viewfull=1#post153876