15 декабря 2011 г.

Общая модель ПЛК: лестничная логика, память, переменные

Статья посвящается самым азам работы с ПЛК. Зная их, вы не потеряетесь, только открыв среду разработки для незнакомого контроллера.

Если вы не знаете, что такое:
  • Языки программирования МЭК 61131-3
  • Память контроллера, регистры и их виды;
  • Переменные/тэги
Вообщем, первый раз столкнулись. А задача есть, и её нужно решать, то эта статья - для вас :).

Стандарты МЭК

Всего их пять:
  • SFC (Sequential Function Chart),
  • LD (Ladder Diagram),
  • FBD (Function Block Diagram),
  • ST (Structured Text)
  • IL (Instruction List)
Я не хочу разводить совсем уж общеизвестной лирики, благо что в интернете достаточно начальной информации.
Скажу лишь, что писать программы стоит на лестничной логике (LD) по следующим причинам:
  1. Она очень похожа на релейную схему и будет легка для освоения тем, кто работает(тал) с принципиальными схемами (а таких, я думаю, большинство)
  2. Поддерживается практически всеми контроллерами, в отличии от других языков
  3. Решает большую часть задач для ПЛК. К тому времени, когда вам понадобится другой инструмент, вы сами поймете, какой (FBD подойдет, где много ПИД-регуляторов. ST/IL - если нужно очень высокое быстродействие (самый оптимальный код), что бывает очень редко. SFC-если предполагается большое количество последовательных действий исполнительных механизмов).
  4. На нем пишу я и, следовательно, большая часть примеров в этом блоге будет на нем :).
Опять же, не хочу повторять множество уже существующих ресурсов по этой теме. Все встанет на свои места, если представить, что вертикальная линия слева - это шина "+" питания, а справа "-". Все, что вы поместите между ними, будет передавать, или не передавать (в зависимости от своей логики) ток (сигнал). В конце, около шины "-" - ставится потребитель этого тока. Будь то "катушка" или какая-то функция, этот потребитель будет действовать согласно пришедшим сигналам "1" (есть ток) или "0" (нет тока) от всей цепи левее. Шины питания разбиваются на звенья (Rung/Network), которые выполняются последовательно. Проход по всем звеньям является одним циклом сканирования программы. Это основа.

Существуют различия в передаче сигналов по линиям связи, которые зависят от производителя. Главное из этих различий - это так называемые "обратные токи". Это соответствует чистой релейной логике, когда ток (сигнал), может пройти через замкнутые контакты и в обратную сторону по схеме. Но в основном такого нет - сигнал передается только вправо, вверх или вниз. Это соответствует лестничной логике. Тут уже можно строить довольно сложные цепи и не отвлекаться, выискивая все возможные ошибки, связанные с обратными токами. Хотя иногда с их помощью можно реализовать интересные решения.

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

В большинстве сред разработки с базовым функционалом языка вы разберетесь мгновенно. Вопросы возникнут на стадии разбора работы некоторых блоков функций, но об этом напишу в будущих статьях. Пока необходимо четко определить, какие инструменты и объекты мы ищем в среде разработки, создать представление общей модели ПЛК.

Память контроллера

Подойду к этому вопросу издалека.

Почему для программ, что разрабатываются для контроллеров, все среды разработки и компиляторы разные? Ведь определен стандарт МЭК, почему все же нет унификации?

Скорее всего у вас должен будет возникнуть такой вопрос. И это очень правильный вопрос. Во-первых, то, что мы пишем для контроллера - это не является базовым кодом. Ведь что такое ПЛК? Это устройство, в основе которого лежит микропроцессор. Да хоть тот же AVR или PIC, с уже встроенной системой команд, каким-то объемом памяти, небольшой периферией. Что делают производители контроллеров? Добавляют источники питания, цепи управления, средства индикации, датчики, интерфейсы, схемы ввода-вывода, расширяют память, все это обвешивают полагаемой рассыпухой в виде резисторов, конденсаторов, кварцевых резонаторов и т.д. И, в конце концов, пишут ОСРВ и собственную программу управления на этот микропроцессор, в которой они увяжут все, что они надстроили, а также добавят обработку и управление любого кода, который мы напишем и скомпилируем в среде разработки (написанной этим же производителем). Соответственно, сколько людей, столько и мнений.
Так уж исторически сложилось, что стандарты основываются на уже существующих решениях. Но к 1993, году введения IEC 1131-3 (тогда он был без цифры "6"), существовало довольно много производителей оборудования. Я считаю, они не стали убивать результаты своих инвестиций в виде ПО, а просто подогнали его в общие рамки. Кстати, вопрос глобальной унификации сейчас решается (например). Однако, самый нижний уровень не будет затронут в таком подходе, а, значит, никто не застрахован от ошибок.

Так вот, разработчики с помощью своей операционной системы избавляют нас от множества проблем, в том числе низкоуровневой адресации памяти и предоставляют её разбитие (не той памяти, что на борту микропроцессора, в ней явно будет расположен загрузчик и прошивка контроллера, а той, что они сами подключили к нему по шине i2c. Хотя, процессоры бывают разные...) в виде регистров разных типов:
  • Энергозависимых и энергонезависимых
  • С побитовым доступом и без
Это типы, которые встретятся на всех контроллерах. Производители, каждый по-своему, разбивают все регистры по группам. Например, регистры ввода-вывода и рабочие (с побитовым доступом), данных и хранения (без побитового (однако с помощью специальных команд можно получить управление над отдельными битами)), системные и т.д., на сколько хватит фантазии. С энергонезависимыми регистрами производители поступают по-разному. Одни позволяют самостоятельно определить объем энергонезависимых регистров для каждой группы, другие определяют под них отдельную группу, третьи вообще придумывают целые методы копирования и чтения данных из энергонезависимых регистров (например Omron, думаю, посвящу этой теме целую статью).
Также нам предоставляется доступ к некоторым системным регистрам. Это может быть информация о времени выполнения вашей программы, заряде оставшейся батареи, объеме стека, отладочная информация и еще великое множество всего. Или, с помощью записи данных в системные регистры, мы можем инициировать какую-либо подпрограмму операционной системы и поставить задачу/условие контроллеру. Все эти регистры должны быть задокументированы.

Группу, как правило, обозначают буквенно, и регистры идут в ней по-порядку: CIO0, CIO1, CIO2 или M0, M1, M2... Если группа позволяет побитовый доступ, то каждый бит обычно отделяется точкой (один регистр составляют 16 бит): CIO0.1, CIO0.2...CIO0.15. Бывает, что биты регистров выделяют в отдельную группу. Например, X0, X1, X2... В таком случае доступ к регистру целиком может быть получен только виртуально, или организовывается другой группой.

Переменные

Следует четко представлять, как информация хранится в регистрах. Я предполагаю, вы знакомы с основными типами данныхдвоичной и шестнадцатиричной системами счисления. На начальном этапе нас интересуют типы bool (бит), byte (байт), word (слово), float (число с плавающей точкой).

Bool - логический тип, реализуется состоянием бита - 1 (истина) или 0 (ложь). Только такую информацию и может нести данный тип. Числовые данные хранятся в следующих типах. 8 бит образуют тип byte. В десятичной системе, максимальное хранимое целое число в типе byte (1111 1111)2=255. Маловато. Поэтому в основном используется тип word. Он состоит из двух байт, которые в составе слова зовутся HI и LO байты - старший (8..15 биты) и младший (0..7 биты). Старший идет впереди, младший - после. Соответственно , 2 байта = 16 бит, и словом у нас является регистр целиком. Названия HI и LO байт применяются и к регистрам.

Переменными (тэгами) являются именованные области памяти. Объявленная переменная может быть лишь одного типа. Однако можно одну и ту же область памяти объявить разными переменными, если подобное позволяет среда разработки.
Также при объявлении переменных необходимо следить за пересечениями в памяти. Например, если вы объявите переменную типа word, а потом один из битов этого слова как bool, то, если вы такое пересечение сделали неумышленно, изменение bool будет менять содержание word, что приведет к ошибкам.

Приведенные типы просто определяют количество бит, отводимых под переменную, но не определяют способы обработки содержащейся информации.

Такие типы как integer (целое), char (символ), float (real), определяют также, как будет представлена содержащаяся информация. Например, целые могут быть знаковые или беззнаковые. У беззнакового целого нет отрицательных значений и все биты отвечают за данные, поэтому максимальное хранимое значение: (1111 1111 1111 1111)2 = 65535. У знакового уже существуют отрицательные значения, за знак "-" отвечает 15й бит, поэтому, максимально хранимое значение: (111 1111 1111 1111)= 32767. Поэтому необходимо представлять, какие значения вы собираетесь хранить в переменной, чтобы избежать переполнений.
Для этого существуют модификации типов. Например, двойное слово (double word (dword)) или large (lword)). Он займет, соответственно, уже два регистра в памяти контроллера (32 бит) и позволит хранить целые беззнаковые значения до 2^32=4294967296.

Другие типы сразу занимают несколько регистров. Например, real (ссылка). И хранится информация в нем уже не так однозначно (ссылка). Кстати, раз уж зашел разговор о плавающей точке, неплохо знать некоторые особенности работы с таким типом.
Real так же имеет удвоенные модификации (double float, large float (lfloat), double real, large real (lreal)- это все одно и то же, кто как называет), которые позволят обеспечить необходимую точность и/или максимальное значение.
С такими переменными надо быть особенно внимательными при размещении их в памяти, не допуская пересечений. Удобно, если среда разработки позволяет авто-размещение данных (auto allocation).

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

Как будет написана программа, останется скомпилировать и записать её в контроллер. В этом процессе у каждого производителя так же есть свои особенности. В некоторых контроллерах вообще компиляция отдельно недоступна - вы подключаетесь к контроллеру со своим проектом и код в него записывается сразу, редактируется он в проекте и прямо в его памяти, так что не следует искать кнопку записи программы в ПЛК.

Вот вроде все, что как минимум необходимо знать перед началом работы. Пожалуйста, оцените статью. Если считаете, что необходимо её чем-то дополнить, говорите. Все пожелания учту и надеюсь, в итоге мы получим статью, что поможет начинающим программистам ПЛК.

Комментариев нет:

Отправить комментарий