вторник, 14 июля 2020 г.

Дата и время: S7-1200 и панели оператора Siemens

Постоянно приходится иметь дело с настройкой даты/времени панелей оператора Siemens и контроллеров S7-1200. В этой статье я расскажу как делается синхронизация даты/времени панелей операторов (HMI) с этим PLC. Основное предназначение такого мероприятия: правильное отображение даты/времени в аварийных и иных сообщениях понели оператора, и чтобы эти дату и время не нужно было задавать каждый раз при включении панели.

Принцип


Принцип установки и синхронизации даты/времени выглядит так:

- дата и время хранятся на PLC, поскольку в этом устройстве они не сбиваются при отключении питания

- HMI периодически синхронизирует свои дату/время с PLC

- на HMI есть ячейки, которые позволяют изменять дату и время PLC и, таким образом, менять дату и время HMI (которая синхронизирована с PLC)

Возможности


Возможности предоставляются следующие.

Со стороны HMI:

1. Считывать текущее дату/время HMI и использовать её для каких-то целей на ПЛК. Для этого надо выделить ячейки памяти в Data Block'е PLC для сохранения этих даты/времени и задать ячейку памяти Job MailBox - это та ячейка, которая воспринимается панелью оператора как внешняя команда, в частности, значение 40 в этой ячейке - это команда скопировать время HMI в заданную область память PLC.

2. Дать задание HMI обновлять один раз в заданный период времени (раз в секунду, минуту, час...) свои дату/время в соответствии со значениями, задаваемыми в заранее выделенной для этого области PLC. Т.е. панель оператора сама не запрашивает у PLC текущие дату/время, но если алгоритм работы PLC будет пересылать свои значения в определённые ячейки, то панель с ними синхронизируется.

Со стороны PLC:

1. Считывать текущие дату/время PLC и сохранять их в виде значений в Data Block'ах.

2. Задавать дату и время, хранящуюся в Data Block'ах, в качестве даты/времени PLC.



Отличия WinCC Flexible 2008 / WinCC Flexible Smart от WinCC TIA Portal

Стóит заметить, что есть разница между WinCC, которая встроена в TIA Portal и старой WinCC - WinCC Flexible 2008, а также сделанной на ее основе WinCC Flexible Smart.

Короче, суть вот в чём: старые WinCC Flexible разрешали как передачу текущих даты/времени, установленных на панели оператора, в память ПЛК, так и, одновременно с этим, разрешали автоматическое обновление даты/времени панели оператора через считывание. Та WinCC, которая теперь находится внутри TIA Portal, позволяет делать только что-то одно из перечисленного - либо синхронизировать HMI с PLC, либо передавать дату/время HMI на PLC, но не одновременно. Иначе будет вот что:


Почему ограничение введено - совершенно не имеет объяснения, потому что, с точки зрения HMI, значения даты/времени - это обычные данные для приёма-передачи, такие же теги, т.е. вы можете создать хоть сотню тегов, которые как угодно друг с другом переплетаются, привязаны к одним и тем же (или частично) адресам памяти, настроены на разные ячейки на чтение, запись или и то, и другое одновременно - никаких ограничений нет - но почему-то с датой/времени Siemens вдруг решил ввести ограничения. В любом случае это особо не повлияет на нашу настройку, далее я покажу в чём будет заключаться отличие.

Резервирование памяти PLC


На PLC необходимо создать блок данных и ячейки в нём, где будут хранится:

1. Job MailBox панели оператора.
Это та ячейка, которая будет давать команду HMI на пересылку её текущих даты/времени в PLC. Как только значение MailBox станет равно 40, HMI выполнит команду, а MailBox сбросит в 0.

2. Дата и время HMI в формате BCD.
Это ячейки памяти PLC, куда будут сохранены дата и время HMI. Представлены они в двоично-десятичном формате (BCD), причём каждое число в виде 1 байта, включая год. А тот самый год, который вроде как измеряется в тысячах, выглядит либо как число от 80 до 99 - это будет означать соответственно с 1980-го по 1999 год, либо как число от 0 до 29 - это будет год с 2000 по 2029-ый. Вот так это представлено в справке как WinCC Flexible:


В моём примере ниже ячейки памяти для даты/времени HMI будут обозначены как HMI2_DATETIME.

3. Дата и время тех же значений HMI, что и в предыдущем пункте, но переведённых в виде нормальных чисел.
В моём примере ниже - HMI_DATETIME.

4. Дата и время PLC в обычном формате.
В таком формате они возвращаются системной функцией PLC.
В моём примере ниже - PLC_DATETIME.

5. Дата и время PLC в формате BCD.
В таком формате они принимаются HMI для обновления её значений
В моём примере ниже - PLC2_DATETIME.


6. "Новые" дату и время для обновления на PLC.
Т.е. на HMI создаются поля для ввода даты и времени, привязанные к этим ячейкам PLC, и кнопка, по нажатию которой информация из этих ячеек передаётся в системную функцию обновления даты/времени PLC. В моём примере ниже - NEW_DATETIME.

7. Биты для управляющих кнопок:
- скопировать текущие дату/время HMI в ячейки для новых даты/времени
- скопировать текущие дату/время PLC в ячейки для новых даты/времени
- применить новую дату/время PLC (кнопка, упомянутая в пункте 6)

В общем и целом зарезервированная память в ПЛК выглядит так:


Исходный код на PLC


// Считать время HMI и отображать его в отдельных ячейках HMI
IF(#Front) THEN
   "HMI_DB".HMI_MAILBOX.Value := 40;
END_IF;

"HMI_DB".HMI_DATETIME.Year  := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Year);
"HMI_DB".HMI_DATETIME.Month := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Month);
"HMI_DB".HMI_DATETIME.Day   := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Day);
"HMI_DB".HMI_DATETIME.Hour  := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Hour);
"HMI_DB".HMI_DATETIME.Min   := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Min);
"HMI_DB".HMI_DATETIME.Sec   := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Sec);

// Записать заданное с HMI время в PLC

IF("HMI_DB".HMI_btn_Clock_Set_to_PLC) THEN
   "NotUsedInt" := WR_SYS_T(IN := "HMI_DB".NEW_DATETIME);
   "HMI_DB".HMI_btn_Clock_Set_to_PLC := false;
END_IF;

// Считать время PLC, отображать его в отдельных ячейках HMI
// и отправлять его на панель для обновления времени HMI (через PLC2_DATETIME)

"NotUsedInt" := RD_SYS_T(OUT => "HMI_DB".PLC_DATETIME);
"HMI_DB".PLC2_DATETIME.Year := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.YEAR);
"HMI_DB".PLC2_DATETIME.Month := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.MONTH);
"HMI_DB".PLC2_DATETIME.Day := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.DAY);
"HMI_DB".PLC2_DATETIME.Hour := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.HOUR);
"HMI_DB".PLC2_DATETIME.Min := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.MINUTE);
"HMI_DB".PLC2_DATETIME.Sec := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.SECOND);     

// Скопировать текущее время PLC в NEW

IF("HMI_DB".HMI_btn_Clock_Copy_PLC_to_NEW) THEN
   "HMI_DB".NEW_DATETIME.YEAR := "HMI_DB".PLC_DATETIME.YEAR;
   "HMI_DB".NEW_DATETIME.MONTH := "HMI_DB".PLC_DATETIME.MONTH;
   "HMI_DB".NEW_DATETIME.DAY := "HMI_DB".PLC_DATETIME.DAY;
   "HMI_DB".NEW_DATETIME.HOUR := "HMI_DB".PLC_DATETIME.HOUR;
   "HMI_DB".NEW_DATETIME.MINUTE := "HMI_DB".PLC_DATETIME.MINUTE;
   "HMI_DB".NEW_DATETIME.SECOND := "HMI_DB".PLC_DATETIME.SECOND;
   "HMI_DB".HMI_btn_Clock_Copy_PLC_to_NEW := false;
END_IF;

// Скопировать текущее время HMI в NEW

IF("HMI_DB".HMI_btn_Clock_Copy_HMI_to_NEW) THEN
   "HMI_DB".NEW_DATETIME.YEAR := BYTE_TO_UINT("HMI_DB".HMI_DATETIME.Year) + 2000;
   "HMI_DB".NEW_DATETIME.MONTH := "HMI_DB".HMI_DATETIME.Month;
   "HMI_DB".NEW_DATETIME.DAY := "HMI_DB".HMI_DATETIME.Day;
   "HMI_DB".NEW_DATETIME.HOUR := "HMI_DB".HMI_DATETIME.Hour;
   "HMI_DB".NEW_DATETIME.MINUTE := "HMI_DB".HMI_DATETIME.Min;
   "HMI_DB".NEW_DATETIME.SECOND := "HMI_DB".HMI_DATETIME.Sec;
   "HMI_DB".HMI_btn_Clock_Copy_HMI_to_NEW := false;
END_IF;


Настройки HMI


В HMI необходимо зайти в раздел Connections, а затем перейти во вкладку Area Pointer, где есть общая часть (For all connections), связанная с обновлением значения даты/времени HMI (синхронизация может происходить только с одним PLC) и конкретная часть для каждого PLC отдельно (For each connection) - в частности, сохранение текущей даты/времени HMI в PLC:


Следовательно, для нашего примера на PLC настройки HMI будут выглядеть следующим образом:


Теперь посмотрим, как это выглядит на панелях оператора Siemens Smart:


Как видно, номера строк не совпадают для одних и тех же параметров английской версии WinCC Flexible 2008 и WinCC Flexible Smart (и WinCC Flexible China SP4), однако, тут легко догадаться, какие строки нам нужны в китайской версии, даже не понимая иероглифов: четвёртая колонка Length указывают длину параметра (в 16-битных словах), которая для всех параметров каждого раздела разная. Т.е. тут легко сопоставить длины параметров:


Далее необходимо добавить все наши данные в таблицу тэгов.


Ну, и создаём экран такого плана:


Надеюсь, не надо объяснять, какой тэг к какой ячейке и к какой кнопке привязывается, тут и так всё очевидно. Единственное, следует обратить внимание, что год в считываемой с HMI текущей дате в моём примере состоит из двух ячеек: одна просто декоративная, в которой постоянно светится число "20", а вторая часть - это двузначное число HMI_DATETIME.Year. В принципе, можно было сделать и по-другому, переводя считываемое с HMI значение в полноценное четырёхзначное число (в функции на PLC).

WinCC в TIA Portal


Тут всё почти тоже самое, кроме того, что мы не можем считывать с HMI текущие дату/время, поскольку мы должны выбирать: либо задаём время на HMI, либо считываем его. Иначе получаем такую ошибку:  

The area pointer 'Date/time' is invalid. The "Date/Time" and "Date/Time PLC" global area pointers cannot be set at the same time

Поскольку у нас основная задача как раз задавать время, то функцию считывания мы не используем. Это не смертельно, хотя, повторюсь, совершенно непонятно, зачем Siemens ввёл такое ограничение. Соответственно, мы тут тоже настраиваем раздел Connections -> Area Pointer , но в усечённом виде, поскольку задаём только параметр Date/Time PLC. Ну, и Siemens не был бы Siemens'ом, если бы в этой версии WinCC не поставил всё с ног на голову:


Т.е. заметьте, что разделы и называются по другому: тот, который был раньше For all connections, теперь зовётся Global area pointer of HMI device, а раздел For each connection тут и вовсе не имеет названия. Ну, и конечно, разделы поменяны местами, как же без этого. Поменяны местами и строки: интересующая нас единственная строка Date/Time PLC теперь последняя в списке.

Соответсвенно, на экране больше нет ячеек для считанных с HMI значений и нет кнопки для копирования значений HMI в ячейки для задаваемых даты/времени:


Всё.




5 комментариев:

  1. Не понял, зачем конвертировать время из BCD.... Там (в ПЛК) прекрасно всё в десятичном формате отображается.

    ОтветитьУдалить
    Ответы
    1. Не, там не из BCD, а в BCD - чтобы панелька приняла дату/время для обновления у себя, только для этого (которые VW62 в панели оператора). Это не для того, чтобы в ячейки HMI выводить. Поэтому и кнопка Copy_PLC_to_NEW забирает значение из PLC_, а не из PLC2_.

      Я не помню, почему у меня написано так:

      "HMI_DB".PLC2_DATETIME.xxxxxxx := "BCD_TO_BYTE"("HMI_DB".PLC_DATETIME.xxxxxxx);

      Ну, т.е. PLC_ - это десятичное, а PLC2_ - это BCD, следовательно, вроде как наоборот должно быть (не BCD_TO, а TO_BCD). Это в теории. А на практике вот так, как оно написано, так оно 100% работает правильно.

      Удалить
    2. Ну, короче, я посмотрел сегодня еще раз. Так получается, что функция BCD_TO_BYTE фактически делает преобразование 8-битного десятичного числа в BCD-формат, т.е. превращает последовательность DEC#1, DEC#2, DEC#3, DEC#n... в 16#1, 16#2, 16#3, 16#n, что в двоичном представлении эквивалентно BCD#1, BCD#2, BCD#3, BCD#n. Если в качестве аргумента передаешь не 8-битное десятичное число, а 16-битное, то она просто отрезает старший байт, т.е. получается, что числа 10#2019, 10#2020, 10#2021 (год в формате UInt внутри DTL) превращаются в 16#19, 16#20, 16#21 - т.е. в том виде, как это и нужно для передачи в панель оператора. Как оно так получается, я не знаю. BCD16_TO_INT и BCD32_TO_DINT преобразуют так, как и заложено в их названиях, а почему BCD_TO_BYTE работает "наоборот" - ?

      Т.е. вот взять, например, строчку:

      "HMI_DB".HMI_DATETIME.Sec := BCD16_TO_INT("HMI_DB".HMI2_DATETIME.Sec);

      Казалось бы, "HMI_DB".HMI_DATETIME.Sec имеет тип BYTE, а "HMI_DB".HMI2_DATETIME.Sec - это 8-битный BCD. Ну, вроде как самая стать использовать BCD_TO_BYTE, а не BCD16_TO_INT, где производятся лишние неявные преобразования из-за несовпадения размера. Но нет, с BCD_TO_BYTE оно неправильно работает, потому что оно не из BCD переводит, а наоборот в BCD. Вот как-то так...

      Удалить
  2. и год "там" сразу в формате 2020. не надо прибавлять ничего

    ОтветитьУдалить
    Ответы
    1. В ПЛК год по-человечески выглядит, это да. А вот если текущую дату из HMI считываешь, то она приходит в формате двухзначного числа 80-99/0-29. Поэтому если где-то надо потом это значение использовать, то тогда прибавить нужно 2000 (или 1900). Но это только для той кнопки "Copy HMI Clock to NEW". Если ее не делать, то тогда как бы и не надо ничего прибавлять.

      Удалить