Уважаемые коллеги, мы рады предложить вам, разрабатываемый нами учебный курс по программированию ПЛК фирмы Beckhoff с применением среды автоматизации TwinCAT. Курс предназначен исключительно для самостоятельного изучения в ознакомительных целях. Перед любым применением изложенного материала в коммерческих целях просим связаться с нами. Текст из предложенных вам статей скопированный и размещенный в других источниках, должен содержать ссылку на наш сайт heaviside.ru. Вы можете связаться с нами по любым вопросам, в том числе создания для вас систем мониторинга и АСУ ТП.


Начальные сведения по языку LD

В прошлой статье мы научились создавать проект, настраивать среду выполнения runtime и написали простейшую программу. В этой статье мы начнем изучать описываемый в стандарте МЭК 61131-3 язык программирования LD.

Код на языках стандарта МЭК 61131-3 (далее кратко языки МЭК) содержится в программных компонентах (POU, Англ. Program Organization Bloc). Каждый программный компонент состоит из раздела объявлений и кода. Раздел объявлений переменных находится в верхней части программного компонента, раздел кода в нижней.

Состав программного компонента (POU)

Переменные

Согласно определению, данному в стандарте ГОСТ Р МЭК 61131-3-2016 «КОНТРОЛЛЕРЫ ПРОГРАММИРУЕМЫЕ»:

переменная (variable): Объект программного обеспечения, который может принимать различные значения, в каждый момент времени только одно значение.

В языке LD, как и во всех языках стандарта МЭК 61131-3, любые элементы, будь то контакты, катушки или функциональные блоки, должны быть соотнесены какой-либо переменной. Это значит, что, если мы хотим в своей программе использовать катушку, мы должны объявить переменную типа BOOL, в которой будет хранится состояние этой катушки. Если на катушку «подано напряжение», переменная будет иметь значение «1», если на катушке «напряжения нет», переменная примет значение «0». Если мы повторно хотим использовать переменную, задействовав контакт, соответствующий этой переменной, то заново переменную объявлять не нужно и даже нельзя. В пределах одного программного компонента не должно быть одноименных переменных.

Для создания переменной ее необходимо объявить в разделе объявлений программного компонента, в секции переменных между ключевыми словами «VAR» и «END_VAR». Для объявления переменных действует следующий синтаксис:

  1. <Идентификатор> {AT <Адрес>}: <Тип данных> {:=<Начальное значение>}; (*Комментарий*)

Значения, содержащиеся между скобок из символов <>, являются обязательными. Значения, содержащиеся между скобок из символов {}, являются необязательными и указываются только при необходимости. Важно не пропускать символы «:», «;» и «=».

<Идентификатор> — имя переменной, именно оно указывается над контактами, катушками и т.д. Идентификатор обязательно должен соответствовать правилам присвоения идентификаторов.

{AT <Адрес>} — (не обязательный элемент) ключевое слово AT может использоваться для непосредственной привязки переменной к определенному адресу. Присваивание адреса переменной мы будем разбирать статьях об указателях, массивах, привязки переменных к входам выходам, передаче данных по Modbus TCP.

<Тип данных>— здесь указывается к какому типу данных относится переменная. В этой статье мы познакомимся только с типом данных BOOL, который может принимать два значения «1» (Истина, Англ. TRUE) и «0» (Ложь, Англ. FALSE). Перед типом данных в объявлении переменной обязательно должен быть поставлен знак «:».

{:=<Начальное значение>} — (не обязательный элемент) это значение будет иметь переменная при запуске программы (функционального блока, функции). Если не указать начального значения, переменная примет начальное значение, присваемое по умолчанию для соответствующего типа данных, как правило ноль.

Объявление переменной должно заканчиваться символом «;».

Крайне желательно добавлять к переменным комментарии, которые поясняют назначение переменной. Комментарии — это поясняющие строки в программном коде, которые позволяют понять смысл написанного. Они пишутся для людей и не влияют на выполнение программы. В TwinCAT 3 любые надписи, заключенные между символами (* и *), являются комментарием. Так же весь текст после символов // и до начала новой строки является комментарием (в TwinCAT 2 этот способ не работает, пользуйтесь только (*…*)).

Правила присвоения идентификаторов переменным:

  1. Идентификатор должен содержать следующие буквы и цифры: 0…9; A…Z; a…z.
  2. TwinCAT не чувствителен к регистру, то есть: VAR1 и var1 обозначают одну и ту же переменную.
  3. Идентификатор не может начинаться с числа.
  4. Идентификатор не может содержать пробелы, специальные символы (!, &, ß, …) или дефисы.
  5. Использование подчеркиваний разрешено. Это означает, что, например, A_BCD и AB_CD рассматриваются как два разных идентификатора. Обычно между словами не используются разделители, такие как подчеркивание.
  6. Следует избегать двойного подчеркивания (‘__’), потому что они используются для внутренних переменных.
  7. Длина идентификатора не ограничена.
  8. Идентификатор не должен совпадать с ключевым словом, например, типом переменной.

Всегда используйте «говорящие» имена для переменных в своем коде. Имя переменной должно отражать ее назначение. Хорошие имена для переменных будут «pressure_PV11» или «Counter», плохие имена «a», «x», «Var1»

В рамках одного проекта старайтесь придерживаться единого стиля наименования переменных.

Пример объявления переменных:

  1. VAR
  2. SB1_Start : BOOL; (*Состояние кнопки пуск SB1*)
  3. nVar2 : INT; (*Пример «плохого» имени переменной*)
  4. pressure_PV11 : REAL := 12.0; //Давление манометра PV 11, МПа
  5. Counter : INT := 13 + 8; (*Счетчик входных импульсов*)
  6. END_VAR

Релейно-контактные схемы (язык LD)

Язык LD представляет собой программную реализацию электрических схем на базе электромагнитных реле. Больше всего этот язык напоминает то, как в России принято изображать схемы релейной защиты.

Код на языке LD и аналогичная ему электрическая схема

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

Релейно-контактные диаграммы состоят из «цепей». Цепь — это совокупность элементов обрабатываемых совместно. В TwinCAT цепь выделяется номером и горизонтальной чертой.

Цепь номер один состоит из контактов «Stop», «Start», «Coil» и катушки «Coil». Цепь номер два состоит из контакта «Coil» и катушки «Out».

В TwinCAT язык LD поддерживает 4 вида катушек:

НаименованиеГрафическое изображениеОписание
1КатушкаСостояние левого контакта копируется в связанную логическую переменную
2Обратная обмоткаВ связанную логическую переменную копируется состояние обратное состоянию левого контакта
3Устанавливающая катушка (с фиксацией включения)Связанная логическая переменная устанавливается в состояние ON, когда левая связь находится в состоянии ON, и остается установленной до сброса катушкой RESET
4Сбрасывающая катушка (с фиксацией выключения)Связанная логическая переменная сбрасывается в состояние OFF, когда левая связь находится в состоянии ON и остается сброшенной до установки за счет катушкой SET

В TwinCAT язык LD поддерживает 2 вида контактов:

НаименованиеГрафическое изображениеОписание
1Нормально разомкнутый контактСостояние левой связи копируется в правую связь, если состояние связанной логической переменной равно ON. В противном случае состояние правой связи равно OFF
2Нормально замкнутый контактСостояние левой связи копируется на правую связь, если состояние связанной логической переменной равно OFF. В противном случае состояние правой связи равно OFF

В терминах языка LD присутствие напряжения эквивалентно состоянию «ON», что соответствует логическому значению 1 или TRUE. Так как контакты и катушки могут принимать только два состояния «ON» и «OFF», им соответствует переменная типа BOOL. Отсутствие напряжения эквивалентно состоянию «OFF», что соответствует логическому значению 0 или FALSE. Состояние левой шины всегда соответствует «ON». В TwinCAT правая шина не изображается, но подразумевается ее наличие. Катушки — это элементы управляющие состоянием соответствующей им переменной. При подаче на левый контакт катушки состояния «ON», катушка меняет состояние соответствующей ей переменной. Контакты — это элементы, управляемые состоянием соответствующей им переменной. В зависимости от состояния переменной, соответствующей контакту, он копирует или не копирует состояние левого контакта на правый контакт.

Описанное выше поведение релейно-контактных диаграмм полностью соответствует поведению электрических цепей. Теперь разберем отличия:

  1. Электрические контакты не передают состояние «ON» справа налево.
  2. Нельзя разместить катушку левее контактов.
  3. Цепи обрабатываются не все сразу, а по очереди, сверху вниз. Состояние любого контакта всегда будет соответствовать последней обработанной одноименной катушке.
  4. Контакты и катушки в рамках одной цепи может соединять только одна горизонтальная связь.
  5. При выводе состояния цепи на экран все переменные имеют значение принимаемое ими на момент окончания обработки всей программы.
Пример условностей языка LD

На рисунке видно, что контакт «SB2_Stop» хоть и замкнут, но не пропускает через себя приходящий на правый контакт сигнал «ON».

Так же на рисунке видно, что при обработке первой цепи катушка «Start_Coil», как и катушка «K1», имеет состояние «ON». При обработке второй цепи нормально замкнутый контакт «Start_Coil» разомкнут, вторая катушка «Start_Coil» размыкается. В третий цепи контакт «Start_Coil» имеет состояние, соответствующее второй катушке «Start_Coil».

Пробная программа и ручная запись переменных

Давайте откроем проект, который мы создали в предыдущей статье. В прошлый раз мы создавали программный аналог пускателя с кнопками пуск и стоп. Давайте повторим прошлую работу с применением знаний, полученных в этой статье. Вместо катушки «K1» с удерживавшим контактом мы будем использовать устанавливающую катушку и сбрасывающую катушку. Ранее мы просто записали текст в раздел объявления переменных, сейчас внимательно рассмотрите его, уже зная, как объявляются переменные. Мы объявили три переменные типа BOOL с названиями «SB1_Stop», «SB2_Start» и «K1». Удалите все цепи из файла POU и нарисуйте схему как на рисунке.

Схема с устанавливающей и сбрасывающей катушкой.

В статье «Создание проекта в TwinCAT» был подробно разобран процесс создания и запуска программы, сейчас мы приведем его кратко. Для запуска проекта нажмите TwinCAT→Activate Configuration, если необходимо введите капчу для активации пробной лицензии. После запустите выполнение, последовательно нажав PLC→Login и PLC→Start. Так же откройте файл с визуализацией. Вывести изображение сразу двух окон можно командами Window→New vertical tab group. Запустив выполнение, убедитесь, что программа выполняется корректно. Если у читателя возникли трудности с запуском проекта, стоит повторить статью «Создание проекта в TwinCAT«.

При нажатой кнопке «SB2_Start» и отпущенной кнопке «SB1_Stop» будет активирована катушка «K1», соответствующей переменной будет присвоено состояние TRUE. Если нажата кнопка «SB1_Stop», она блокирует устанавливающую катушку в первой цепи и подает сигнал на сбрасывающую катушку во второй цепи. Таким образом, при одновременном нажатии кнопок «SB2_Start» и «SB1_Stop» будет выполнено действие, соответствующие нажатию кнопки «SB1_Stop». Для того, что бы убедиться в корректной работе схемы при одновременном нажатии обоих кнопок, воспользуемся одним из отладочных инструментов TwinCAT. Во время выполнения программы дважды кликнем по прямоугольнику, отображающему состояние контактов «SB2_Start». Рядом с контактом появится прямоугольник с готовым для записи значением, в данном случает TRUE. Произведем запись нового значения в переменную «SB2_Start», нажав PLC→Write values. Переменная «SB2_Start» приобретёт значение TRUE, на окне визуализации кнопка «Start» будет изображаться утопленной. Повторим такие же действия с переменной «SB1_Stop». Убедимся, что, при одновременно нажатых кнопках старт и стоп, приоритет имеет кнопка остановки. Вернем схему к изначальному состоянию либо только что описанным способом, либо нажатием кнопок «Start» и «Stop» в окне визуализации.

Теперь давайте немного упростим нашу программу. Так как цикл работы ПЛК состоит из чтения входов, выполнении кода и записи выходов, а также, вспомнив, что цепи программы обрабатываются последовательно, сверху вниз можно сделать вывод, что кнопка «стоп» будет иметь приоритет, даже если удалить нормально замкнутый контакт «SB1_Stop» из первой цепи.

Изменим схему:

Схема с устанавливающей и сбрасывающей катушкой без блокирующего контакта «SB1_Stop»

Проделав описанные выше шаги, убедитесь, что схема продолжает работать корректно.

Действительно, теперь ПЛК выполняет следующие шаги:

  1. Из окна визуализации считывает состояние кнопок «Start» и «Stop» и копирует их состояние в переменные «SB2_Start» и «SB1_Stop».
  2. Выполняет первую цепочку из контакта «SB2_Start» и устанавливающей катушки «K1». Если «SB2_Start» имеет состояние TRUE, переменная «K1» также устанавливается в состояние TRUE. Если «SB2_Start» имеет состояние FALSE, переменная «K1» не меняет свое значение.
  3. Выполняет вторую цепочку из контакта «SB1_Stop» и сбрасывающей катушки «K1». Если «SB1_ Stop» имеет состояние TRUE, переменная «K1» сбрасывается в состояние FALSE. Если «SB1_ Stop» имеет состояние FALSE, переменная «K1» не меняет свое значение.
  4. Выводит в окно визуализации состояние переменной «K1».

Таким образом работы схемы остается полностью корректной.

Домашнее задание

В этой статье, когда мы осуществляли ручную запись значения переменной мы пользовались командой PLC→Write values. Эта команда действует точно так же, как если бы значение переменной было бы изменено самой программой. Кроме того записанная переменная остается доступной для изменения из программы. Такой способ ручной записи значения переменной бывает не всегда удобен. Есть еще одна команда для ручной записи значения переменной PLC→Force Values. Эта команда осуществляет «силовой» вариант записи переменной. После ее применения переменная становится недоступной для изменения из программы и сохраняет свое значение до повторного применения команды PLC→Force Values или ее отмены командой PLC→Unforce Values.

Предлагаем читателям самостоятельно попробовать воспользоваться командами PLC→Force Values и PLC→Unforce Values. А также разобраться как себя ведут записанные с помощью команды PLC→Force Values переменные при остановке отладчика. Запуск и остановка отладчика выполняются командами PLC→Login и PLC→Logout соответственно.