June 17, 2015

Машина состояний EtherCAT

Машина состояний EhterCAT (EtherCAT State machine (ESM) -- каждое устройство EtherCAT может и обязано находиться в одном из предопределенных состояний. В каждом из состояний мастером шины производятся определенные действия. Даже в случае ошибки или аварии устройство переходит в заранее предусмотренное состояние и выставляет флаг ошибки. Если устройство не поддерживает аппаратный μС-контроллер, то оно должно эмулировать машину состояний EtherCAT.

  • Init (I) - нет синхронного обмена PDO; мастер может писать в информационные регистры подчиненных.
  • Pre-Operational (Pre-Op, PREOP, P) -- нет синхронного обмена PDO; мастер конфигурирует подчиненных; обмен данными через асинхронные почтовые слоты.
  • Safe Operational (Safe-Op, SAFEOP, S) - обмен данными через асинхронные почтовые слоты; синхронный обмен PDO -- только входа; выхода в безопасном состоянии ("Safe State").
  • Operational (OP, O) -- полностью рабочий режим; синхронный обмен данными через PDO: как входа, так и выхода.
  • Bootstrap (B) -- опциональный режим для "заливки" новых прошивок.

Часто используются сокращения или если хотят показать направление переключения:
  • IP: Init → Pre-Op
  • PI: Pre-Op → Init
  • OI: Op → Init
  • SO: SAFEOP → OP

Для инициализации подчиненного устройства, достаточно выполнить проход по состояниям: Init → Pre-Op → Safe-Op → Op (что сокращенно будет выглядеть как "I-P-S-O"). Здесь состояние Safe-Op не обязательно, но в стандарте фигурирует.

Для переконфигурации устройства необходимо вернуть устройство в состояние Init, а затем выполнить всю цепочку сначала: I-P-S-O. В результате прохода по этой последовательности, мастер заново переконфигурирует подчиненное устройство и гарантированно сбросит все ошибки устройства (если причина ошибки была устранена).

Смена состояния подчиненного устройства (или когда мастер управляет сам собой) происходит не сразу, а посредством управляющего регистра, т. е. сначала мастер запрашивает требуемое состояние, и только затем подчиненный какое-то время пытается изменить свое состояние, по результату изменяя значение регистра состояния. Если подчиненный не смог переключиться в требуемое состояние, то в итоге получится разное значение для запрошенного состояния подчиненного (Requested State) и текущего состояния подчиненного (Current State). Этот процесс хорошо отслеживается на закладке "Online" в System Manager.

Множество тонких настроек поведения EtherCAT-устройства доступны во вкладке "EtherCAT", диалог "Advanced Settings...".


Библиотека TcEtherCAT.lib


Библиотека входит в стандартный комплект TwinCAT и содержит множество низкоуровневых и чуть-выше функций для работы по шине EtherCAT:
  • CoE Interface (CAN over EtherCAT) -- работа с параметрами подчиненных устройств у которых внутренняя шина -- CAN: многие модули расширения, дискретные и аналоговый входа/выхода и пр.
  • SoE Interface (SERCOS over EtherCAT) -- функции работы с параметрами SERCOS-устройств; например, сервоусилители серии AX5000.
  • FoE Interface (File over EtherCAT) -- функции заливки прошивки в устройства.
  • Множество других функций: диагностика рабочих счетчиков (WcState), подсчет контрольных сумм, функции конвертеры для распределенных часов и т. п.

Для переключения состояния подчиненного можно воспользоваться функциями FB_Ec[Get|Req|Set]SlaveState. Для мастера -- аналогично, только Slave нужно заменить на Master.

Функция Get вернет текущее состояние в виде структуры ST_EcSlaveState, которая состоит из двух битовых полей:
  • deviceState - состояние подчиненного устройства.
  • linkState - состояние линии связи.

В библиотеке доступны следующие константы состояний: EC_DEVICE_STATE_INIT, EC_DEVICE_STATE_PREOP, EC_DEVICE_STATE_xxx, ...

Перед определением текущего состояния необходимо обработать поле deviceState битовой маской EC_DEVICE_STATE_MASK. Недостаточно просто вытащить из структуры поле и сравнить его с константой состояния! Например, выясняем, что в настоящий момент устройство не способно полноценно работать:

IF ( curState AND EC_DEVICE_STATE_MASK ) <> EC_DEVICE_STATE_OP THEN


Кроме текущего состояния, поле deviceState содержит биты-флаги ошибок. Для них специальной маски нет, поэтому проверить устройство на ошибки можно следующим образом:

IF ( currState.deviceState AND 16#70 ) > 0 THEN


Подробнее о состоянии устройства можно прочитать в описании структуры ST_EcSlaveState.


Изменение состояния подчиненного устройства

Для изменения состояния устройства, в библиотеке существуют два набора функций: FB_EcReqSlaveState и FB_EcSetSlaveState. Разница в том, что Req отправляет запрос и заканчивает свою работу. Set же будет ожидать, пока устройство не переключится в необходимое состояние и, если этого не произойдет в течение времени tTimeout, выбросит ошибку: 16#745; (*ADSERR_DEVICE_CLIENT_TIMEOUT*)
Если в проекте не требуются нюансы работы с EtherCAT-шиной, то лучше воспользоваться функциями Set.
Не нужно изобретать свою функцию, когда уже есть готовая Set: она использует Req как основу, организуя внутри себя опрос состояния подчиненного устройства.

June 14, 2015

OPC-сервер

OPC-сервер покупается на каждый контроллер отдельно, затем устанавливается. Существует два вида:
  • OPC DA/XML-DA -- только для настольных операционных систем: XP, 7, Embedded Standart, и т. п. [TS6120]. Для его работы необходим DCOM и пр. системные сервисы, и это единственная причина, почему его нет для компактных операционок.
  • OPC UA (IEC 62541) -- не только для настольных [TS6100], но и для компактных: CE, Emb. Compact, ... [TS6100-0030]
Если тип OPC-сервера не важен, то стоит выбрать OPC UA.
Обе версии настраиваются через XML-файл. Существует конфигуратор, который умеет создавать этот XML-файл и активировать его на ПЛК. Немного про настройку можно прочитать в "OPC сервер: настройка и тестирование".

June 9, 2015

Форматы времени и даты

Посмотрим на полный список форматов времени и даты. Немного об этом было в ST и C#, или туда и обратно, теперь рассмотрим подробнее.
Все переменные типа даты, времени, промежутков, длительности и т. п. хранятся в ПЛК как 32-х разрядные целые, беззнаковые.

TIME


Длительность или промежуток времени в миллисекундах. Аналогом в C# можно считать TimeSpan.

Формат:
:= T#521h33m23s231ms;
:= TIME#521h33m23s231ms;

Время в строку: TIME_TO_STRING(T#12ms);
Результат типа STRING: 'T#12ms'

Строка во время: STRING_TO_TIME('T#127ms');
Результат типа TIME: T#127ms


DATE


Только дата  — как число секунд, прошедших с 1 января 1970 года.

Формат:
:= D#1993-06-12;
:= DATE#1993-06-12;

Дата в строку: DATE_TO_STRING(D#2002-08-18);
Результат типа STRING: 'D#2002-08-18'


DATE_AND_TIME или DT


Дата и время — как число секунд, прошедших с 1 января 1970 года. В C# можно использовать DateTime, не забывая, что в ST дата-время начинаются в Unix-стиле с 1970 года, а в C# с нулевого года.

Формат:
:= DT#1993-06-12-15:36:55;
:= DATE_AND_TIME#1993-06-12-15:36:55;

Дата-время в строку: DT_TO_STRING(DT#1998-02-13-14:20);
Результат типа STRING: 'DT#1998-02-13-14:20'

Несложно избавиться в строке от префиксов T#DT#, TOD# и т. п. Функция DELETE входит в стандартную библиотеку STANDART.lib. Удаляем слева n-символов:

str := DELETE(str, 2, 1); (*   T#... TIME_TO_STRING *)
str := DELETE(str, 3, 1); (*  DT#... DT_TO_STRING   *)
str := DELETE(str, 4, 1); (* TOD#... TOD_TO_STRING  *)


TIME_OF_DAY или TOD


Время дня: количество миллисекунд, прошедших начиная от начала дня — от ноля часов и ноля минут (00:00).

Формат:
:= TOD#12:34:56.123;
:= TIME_OF_DAY#12:34:56.123;

Время дня в строку: TOD_TO_STRING(TOD#14:01:05.123);
Результат типа STRING: 'TOD#14:01:05.123'



FILETIME (T_FILETIME)


Структура из двух DWORD (udint) полей. 64-х разрядное целое, содержит число 100-наносекундных интервалов с 1 января 1601 года (UTC). Для вменяемой работы с этим форматом (распаковки), существуют вспомогательные функции FILETIME_TO_DTFILETIME_TO_SYSTEMTIME, и в обратную сторону [...]_TO_FILETIME.


SYSTEMTIME (TIMESTRUCT)


Удобная структура с большим количеством удобных 16-разрядных полей типа WORD (uint):
  • wYear — год, 1970..2106;
  • wMonth — месяц, 1..12 (1 - январь, 2 - февраль и т. д); 
  • wDayOfWeek — день недели, 0..6 (0 - воскресенье (!), 1 - понедельник, ...);
  • wDay — день месяца, 1..31;
  • wHour — час, 0..23;
  • wMinute — минуты, 0..59;
  • wSecond — секунды, 0..59;
  • wMilliseconds — миллисекунды, 0..999.

Существует функция для преобразования строки в системное время: STRING_TO_SYSTEMTIME( 'YYYY-MM-DD-hh:mm:ss.xxx' ). На выходе получаем TIMESTRUCT.

Формат входной строки жестко фиксирован: через разделители '-' и ':' должны быть введены все цифры, а недостающие — заменены нулями:
  • YYYY — год,1601..9999;
  • MM — месяц, 01..12;
  • DD — день, 01..31;
  • hh — час, 00..23;
  • mm — минуты, 00..59;
  • ss — секунды, 00..59;
  • xxx — миллисекунды, 000..999.

Например:

ts := STRING_TO_SYSTEMTIME( '2012-01-30-05:12:09.567' );


Обновлено: 5 февраля 2017 г.

June 8, 2015

Энергонезависимые переменные

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

RETAIN
По сути применимы только для серии BC. Можно и в других случаях, но неудобно, т. к. сохраняют свое значение только при корректном завершении работы TwinCAT. Не спасут при внезапном пропадании электричества (*). Совершенно не экономят ресурс флэш-памяти. На контроллерах BC сохраняют свое значение при изменении значения переменной и могут удлинить время цикла (если нужно).

PERSISTENT
Аналогично RETAIN, но сохраняются при вызове специального функционального блока (FB_WritePersistentData из TcUtilities.lib), либо при корректном выключении TwinCAT (*). Экономят ресурс флэш-памяти.
При использовании RETAIN и PERSISTENT данных, значения переменных по прежнему сбрасываются на флэш-диск. TwinCAT самостоятельно восстанавливает данные и может отследить нарушение целостности сохраненных данных (об этом можно узнать из специальной системной переменной: SYSTEMINFO). Остальные подробности - в справочной системе: TX1200 | TwinCAT PLC.

NOV/DP-RAM


Nonvolatile DualPort RAM - энергонезависимая двухпортовая  память.

Память двухпортовая, т. е. состоит из двух компонентов: оперативная память и долговременная память, плюс - собственный источник питания. Все это, в совокупности, позволяет сохранять переменные в любой момент, сколько угодно раз, а при отключении питания, успеть сбросить и хранить данные в долговременной памяти за счет собственного источника питания. Автоматически.

Но(!) не все контроллеры поддерживают этот вид памяти.

Настраивается и конфигурируется в системной конфигурации линковкой выходных переменных ПЛК-проекта с выходными переменными NovRAM. Дальше работает автоматически, поэтому на младших контроллерах постоянная работа с переменными этой памяти может вызвать ощутимую нагрузку на процессор ПЛК. Для снижения нагрузки существует специальный функциональный блок, для записи блоков данных только при необходимости (FB_NovRamReadWriteEX).


Односекундные бесперебойники


Теперь вернемся к звездочке в скобках (*): ограничение на аккуратное завершение работы TwinCAT снимается "односекундным бесперебойником" (S-UPS: capacitive seconds UPS). За счет энергии, накопленной в ионисторах, эта опция позволяют подпитывать контроллер некоторое время, достаточное для сброса данных во флэш-память. Для работы этой функции необходимо обрабатывать функцию FB_S_UPS из библиотеки TcSUPS.Lib.

Но(!), опять-таки, не все контроллеры и не для всех.
Для всех видов переменных, при использовании файловых фильтров EWF или FBWF, необходимо разрешить на запись каталог Boot. Это происходит автоматически при включении фильтров, но проверить, не помешает.

June 1, 2015

Free Run не нужен

Со временем выработалось правило: "Free Run не нужен", но пытливые умы все-равно пытаются приспособить что-то незнакомое, под что-нибудь полезное.

Устройства при включенной опции Free Run пытаются оставаться в состоянии OP даже в режиме конфигурации, и часто им это удается, но задачи (Tasks) системы реального времени конечно же не работают. Поэтому единственное применение этой опции - подергать за выхода в режиме конфигурации при еще не написанной ПЛК-программе.
Кстати, иногда модули расширения реагируют на такое безобразие "как-то не так", что заставляет разработчика искать несуществующую ошибку.
Кроме того, существует режим синхронизации "free run", но это уже другая история, не имеющая никакого отношения к этому окошку.


Как подергать за входа без Free Run?


Если "Free Run не нужен", но хочется подергать за аппаратные выхода, можно воспользоваться веткой "Additional Tasks". Она позволяет создавать задачи, которые умеют перегонять данные, и только, что собственно и нужно, чтобы в рабочем режиме (Run Mode) обеспечить активность шины, избегая такого сообщения:



Создаем дополнительную задачу, а в ней какую-нибудь переменную, которую затем линкуем с переменной состояния EtherCAT-шины:


При создании дополнительной задачи, не забываем сразу же выставить опцию "Auto start", т. к. в отличии от ПЛК-задач, дополнительные задачи автоматически не стартуют.
После этого можно активировать конфигурацию и наслаждаться полноценным рабочим режимом (Run Mode) с активной шиной и устройствами.