«Соколов Ю.А., Кулешов В.Г. ПОСТРОЕНИЕ СИСТЕМ УПРАВЛЕНИЯ НА БАЗЕ КОНТРОЛЛЕРОВ Direct Logic. Главы книги 1. О том, что есть в этой книге. 2. Структуры систем управления, построенных на базе ПЛК семейства Direct Logic. ...»
- независимая отработка действия каждым исполнительным устройством;
- блокировка некорректных действий;
- выявление и диагностирование ошибок.
Попробуем применить объектно-ориентированный подход. Пусть у нас имеется некое исполнительное устройство; например, вакуумный клапан, который имеет состояния: «Открыт» и «Закрыт» (входы X0 и X1), эти состояния изменяются с помощью выходов «Открыть» и «Закрыть» (выходы Y0 и Y1) по нажатию кнопок, соединенных с входами X2 – «Открыть клапан» и X3 – «Закрыть клапан». Для того, чтобы избежать дребезга и обеспечить независимую работу клапана, воспользуемся преимуществами стадийного программирования, которые предоставляет язык RLL рlus, и разобьем процессы открытия и закрытия клапана на отдельные стадии:
1) опрос кнопки управления;
2) проверка допустимости операции;
3) выполнение операции;
4) проверка результата выполнения и возврат к опросу кнопок.
Таким образом, мы создали объект «Вакуумный клапан», независимый от остальных органов управления системы, «объекты» которых можно создать аналогичным образом.
Ветви программы, реализующей данный подход, в упрощенном виде будут выглядеть так (вместо X-входов используем их образы в виде C-битов):
Стадии опроса кнопок управления другими механизмами запускаются параллельно с этой и активны, пока не будет нажата соответствующая кнопка. После этого управление передается другой стадии, на которой проверяется допустимость этой операции, а дребезг на входе, даже если он будет иметь место, программа просто «не заметит», так как до конца выполнения операции вход опрашиваться уже не будет. Если условие корректности операции выполняется (никаких блокировок нет), переходим на стадию выполнения операции. Ее необходимо разобрать более тщательно. Дело в том, что мы не можем просто установить соответствующий выход и со спокойной совестью идти на возобновление опроса кнопок. Мы ведь не знаем, чем закончилась операция! А если мы подали сигнал на открытие клапана, но он не открылся, т.е. мы не получили сигнала на входе «Клапан открыт»? Может случиться и такое – включили выход, но все равно получаем сигнал, что клапан закрыт. При отработке операции, даже самой простейшей на первый взгляд, нужно проверять все. А на выполнение операции задавать некоторое время, которое подбирается опытным путем. Внеся в нашу программу ветви, выполняющие эти проверки, мы всегда сможем адекватно диагностировать неполадку, если она вдруг произойдет.
В заключительной стадии нашего цикла обслуживания механизма проверяем наличие ошибки, и, если она произошла, производим ее обработку (например, индикацию или запись в очередь), после чего возобновляем опрос кнопок.
Конечно, если механизмов в системе много, программирование их функций по такой схеме представляется достаточно рутинной работой, но для нас главное – надежность.
Если же одновременная работа нескольких механизмов не допускается, можно ввести специальный «бит занятости» и в стадии проверки нажатия кнопки проверять, сброшен ли этот бит:
8. Программирование автоматического цикла.
Для того, чтобы программа управления технологической установкой обеспечивала успешное и гибкое функционирование в автоматическом режиме, при ее создании необходимо решить следующие задачи:
- возможность запуска одновременно нескольких независимых технологических процессов;
- легкость изменения последовательности технологических операций;
- использование в полной мере наработок по ручному режиму управления.
Последнее предполагает, что мы будем использовать весь цикл стадий, относящихся к ручному режиму. Это, во-первых, даст возможность заблокировать при отработке цикла кнопки ручного режима, а во-вторых, избавит от необходимости отдельно программировать каждую последовательность производственных операций – в этом случае изменение последовательность операций в цикле будет представлять собой достаточно трудоемкую и рутинную задачу. Тогда перед нами встает другая задача – как объединить независимые стадии, обслуживающие ручное управление исполнительными устройствами, в некую последовательность, предусмотренную конкретной технологией?
Другими словами – как «заставить» стадии, в которых опрашиваются кнопки ручного управления, включать в определенной последовательности имеющиеся в системе управления механизмы?
Ответ находится в самом вопросе: если в режиме ручного управления механизм включается по нажатию кнопки, т.е. установленному биту, то почему бы в автоматическом режиме не включать его также по наличию факта установленного бита, но – другого? Замечательно, но кто тогда будет устанавливать этот бит? Ответ – бит будет устанавливаться в специальной стадии, которая запускается по нажатию кнопки пуска автоматического цикла. Откуда эта стадия знает, какой бит нужно установить? Ответ – эта стадия занимается тем, что просматривает ячейки памяти, в которых и записаны номера нужных битов, которые требуется последовательно установить, чтобы обеспечить выполнение технологических операций в определенном порядке. Следовательно, создание производственного цикла сводится, таким образом, к созданию области числовых данных, в которой в 16-ричном коде будем хранить номера битов, а также к программированию стадии, которая и будет устанавливать эти биты.
В приведенном примере 16-ричная константа 105 – это 8-ричное число 405, 10F – 417, а 107 – это 407 в 8-ричной системе исчисления. Назовем эти константы Кодом операции (КОП). Таким образом, чтобы выполнить, допустим, операцию открытия клапана, нужно установить бит C417, а в стадию опроса кнопки управления этим механизмом внести проверку этого бита. Тогда эта стадия будет выглядеть так:
По нажатию кнопки «Пуск» считываем коды операций в V-память и создаем указатель на этот массив. Пусть в нашем примере цикл состоит из 20 операций (количество слов задаем в 16-ричном коде). Последовательность кодов завершаем нулем – это будет означать, что выборку нужно прекратить. Это придется делать не только после выполнения всех операций цикла, но и в случае возникновения на каком-нибудь этапе ошибки.
Теперь напишем стадию выборки КОП из V-памяти. Само по себе это не представляет затруднений: в процессе выборки проверять содержимое ячейки, на которую ссылается указатель, на 0, и модифицировать его. Главное в этой стадии – преобразовать 16-ричный код операции в соответствующий C-бит. (Заметим, она должна отработать раньше стадий проверки кнопок ручного управления и битов КОП) Разумеется, задача элементарно решается:
Однако можно все сделать гораздо короче и изящнее, поскольку в языке RLL Plus есть парочка команд, которых во всех известных языках программирования нет – это команды DECO (устанавливает бит по коду в аккумуляторе) и ENCO (выполняет обратную операцию – установленный в аккумуляторе бит превращает в числовое представление). По коду операции вычислим адрес ячейки V-памяти, в которой находится искомый C-бит (пространство C-битов начинается с адреса V40600), и установим соответствующий бит в аккумуляторе, после чего скопируем его в нужный C-бит:
После установки C-бита кода операции стадия выборки КОП должна быть деактивирована. Это можно сделать командой RST S100, но рациональнее перейти на другую стадию, которую в большинстве случаев придется вводить, потому как в автоматическом цикле могут быть операции, для которых ручное управление вообще смысла не имеет; например, ожидание рабочего уровня вакуума в камере в течение некоторого времени. Этим операциям также ставятся в соответствие свои коды и C-биты, которые и будут проверяется в стадии, активированной из стадии S100.
Если технологическая установка имеет несколько независимых производственных циклов (причем они могут выполняться одновременно), тогда для каждой операции зарезервируем две ячейки V-памяти, в которых будут храниться номер выполняемого цикла (эту ячейку еще можно использовать в качестве слова состояния цикла) и адрес следующего кода операции. Соответственно потребуется ввести ячейку, где будет храниться номер выполняемого в данный момент цикла. В стадию опроса кнопки ручного управления и установки бита КОП добавится новая ветвь, и стадия примет следующий вид:
Также нужно внести изменения в заключительную стадию обслуживания механизма: в случае ошибки нужно записать 0 вместо адреса кода следующей операции, чтобы прервать цикл, и если установлены биты КОП, активировать стадию, в которой будем ожидать готовности возобновить данный цикл. Сигналом для этого служит сброшенный бит стадии S100 – значит, она установила бит КОП и была деактивирована, теперь активируем ее из стадии ожидания и загружаем номер текущего цикла и адрес КОП, который должен быть выбран в стадии S100. Соответственно придется видоизменить обработку кнопки «Пуск»: просто установить флаг пуска и в следующей ветви в случае, если он установлен и сброшен бит стадии S100, загрузить в V-память коды операций цикла, номер цикла и адрес массива КОП, после чего активировать S100.
Пример программы имеется выше, с той лишь разницей, что вместо бита «Кнопка Пуск»
будет стоять бит «Флаг Пуска».
Сразу заметим, что данный подход к реализации одновременной отработки нескольких циклов не совсем безупречен: если в параллельных циклах задействованы одни и те же операции, то теоретически возможен момент, когда в текущем цикле будет установлен бит некоторой операции, а в настоящий момент не до конца выполнилась противоположная ей операция, т.е. выполняли «Закрыть», а текущая команда «Открыть».
В этом случае текущая операция выполнена не будет, а выполнение текущего цикла остановится – он просто «потеряется». Однако здравый смысл подсказывает, что подобная ситуация вряд ли возможна – в самом деле, зачем запускать параллельно выполняющемуся циклу еще один, который выполняет противоположные операции. Если же подобные циклы предусмотрены в системе управления, тогда в программу необходимо добавить дополнительные блокировки, которые исключают одновременный запуск таких циклов.
9. Чтение входов.
В системах управления многих технологических установок дискретные входы обычно отображают состояния переключателей, тумблеров, датчиков с состояниями «открыто» или «закрыто». Когда после выполнения операции показание датчика изменяется на противоположное, т.е механизм меняет свое положение, на практике имеет место дребезг контактов, и по однократному считыванию дискретного входа еще нельзя с уверенностью констатировать то или иное состояние датчика. Для того, чтобы повысить достоверность считывания X-битов контроллера, можно воспользоваться так называемым виртуальным пространством входов, в котором отображаются состояния X-битов, не меняющиеся по крайней мере в течение 3 циклов сканирования. Для создания виртуального пространства входов задействуем C-биты – в них будем перегружать соответствующие X-биты, если их состояние не изменится в течение 3 циклов.
Разумеется, использовать эти биты для других целей в программе уже нельзя. Сразу оговоримся, что этот подход применим для систем, не требующих мгновенного реагирования на изменение входа. Для считывания входов напишем стадию, которая всегда будет активна. Для примера будем считать, что в нашей системе 48 дискретных входов и адресация начинается с VX0. Зарезервируем 3 ячейки для хранения промежуточного состояния входов: V1400-V1402 и 3 C-бита в качестве флагов совпадения считанного значения и промежуточного: C260-C262. Сначала сравниваем состояние входов с промежуточными значениями и выставляем флаги совпадения (для удобства обращаемся к дискретным входам как к ячейкам V-памяти):
Если состояние входов не изменилось, увеличиваем счетчик стабильных считываний, иначе – принимаем текущее состояние входов за истинное и записываем его в буферные ячейки. Когда получим 3 стабильных считывания, будем считать, что состояние входов устойчивое, и можно перегрузить буферные ячейки в C-биты, соответствующие входам. Фрагменты программы, реализующей все вышесказанное, приведены ниже:
Теперь, чтобы проанализировать в программе состояние какого-либо дискретного входа, будем обращаться к C-битам.
10. Измерения.
Выбор модулей для аналогового ввода-вывода информации у контроллеров DirectLogic достаточно широкий. Работа с каждым из них подразумевает профессиональный подход.
10.1. Особенности работы с модулем F2-04THM.
Модуль F2-04THM предназначен для автоматического преобразования сигналов с термопар в показания температуры (в градусах Цельсия либо Фаренгейта), а также для преобразования вольтового (±5В) или милливольтового (±156мВ) сигнала в 16-битовые цифровые значения.
Модуль обеспечивает достаточно высокую точность измерений, не требует калибровки. Мы не будем подробно описывать его технические характеристики – все они приведены в документации, которую необходимо изучить перед применением модуля.
Данная глава посвящена особенностям работы с этим модулем, которые в документации не оговорены.
На первый взгляд, обработка показаний модуля не должна вызывать каких-либо сложностей, поскольку он поддерживает 9 типов термопар и еще два уровня потенциальных входов. Однако, не все встроенные градуировки соответствуют отечественным термопарам. Разумеется, можно применять и импортные термопары, но они весьма дороги.
Один из подходов к решению этой задачи – использование потенциальных входов. Без их применения не обойтись также, если нам нужно измерить не температуру, а, например, давление, и в качестве источника сигнала выступает вакуумная лампа.
Полученное цифровое представление затем преобразуется в показания температуры (давления).
В штатной ситуации модуль функционирует безупречно, но время от времени происходит такая неприятная вещь как обрыв датчика, и вот тут начинаются проблемы.
Несмотря на экранирование и изоляцию каналов, начинаются наводки на показания всех каналов всех модулей F2-04THM, используемых в системе управления.
Программное обеспечение, анализирующее показания датчиков, может в результате неадекватных показаний нарушить нормальную логику работы технологической установки: выдать сигналы несуществующих на самом деле ошибок, заблокировать какие-то механизмы и вообще спровоцировать аварийную ситуацию. К сожалению, в документации этой задаче внимание почти не уделяется, а в главе, посвященной написанию управляющей программы для чтения показаний модуля, настоятельно рекомендуется использовать для этого метод указателя. Этот метод существенно упрощает требования к программированию – процессор D2-250(D2-260) содержит специальные ячейки V-памяти, назначенные каждому слоту каркаса, в них заносится число обновляемых каналов и местоположение выходных данных, для получения результата достаточно прочитать ячейки с выходными данными. Никаких проверок на достоверность данных и обрыв датчика этот метод не предусматривает! Мы рекомендуем пользоваться методом мультиплексирования – во-первых, его алгоритм в каждом цикле сканирования позволяет определить, какой именно канал читается или в каком канале появился обрыв, а во-вторых, он более универсален, так как только его можно использовать для обработки показаний термопарных модулей, установленных в каркасе удаленного ввода-вывода.
Алгоритм метода мультиплексирования достаточно прост. Как известно, модуль F2-04THM требует 32 дискретных входа процессора. Эти входы можно (и нужно!) использовать, чтобы получить: а) признак активного канала, б) цифровое представление аналогового сигнала, в) диагностическую информацию о состоянии модуля. В нашем примере предположим, что модуль установлен в 0-й слот каркаса; стало быть, входные точки имеют адреса V40400 (VX0) и V40401 (VX20). В ячейку V40400 записываются данные активного канала, в ячейке V40401 находится информация о состоянии модуля – номер активного канала и биты обрыва. Номер активного канала в данном случае будут определять биты X20 и X21:
Биты обрыва датчика:
Фрагмент программы, обеспечивающей чтение показаний датчика 1-го канала, будет выглядеть примерно так:
Остальные каналы обрабатываются аналогично.
Однако, если мы настроили модуль на потенциальные входы, бит обрыва устанавливается только в случае нарушения питания! Если имеет место обрыв датчика, в случае использования потенциальных входов обнаружить его можно лишь по косвенным признакам, которыми являются броски показаний или же их заведомая абсурдность. Бит обрыва диагностирует обрыв датчика только если модуль настроен на один из типов термопар!
Итак, для правильного диагностирования обрыва целесообразно отказаться от использования потенциальных входов и настроить модуль на один из типов термопар.
Заметьте, «настроить» не означает «применить»!
Допустим, у нас имеется отечественная термопара типа ВР-2, и нам нужно получить значения температуры и избежать наводок вследствие обрыва. Как было сказано выше, единственный тип отечественных термопар, поддерживаемых модулем F2-04THM – это ТХА (тип К). Настроим модуль на этот тип термопары и сравним градуировочные таблицы термопар ТХА и ВР-2. Максимальному значению температуры, которую можно измерить термопарой ВР-2 – 1800°С – соответствует 27.226 мВ; нетрудно оценить, что для термопары ТХА такое напряжение соответствует примерно 660°С. Выпишем из градуировочной таблицы ВР-2 значения температур и напряжения:
Температура НапряжеВР2, °С ние, мВ В градуировочной таблице ТХА найдем интервал напряжений, в котором находится напряжение, соответствующее градусам ВР-2. Наша таблица приобретет следующий вид:
Температура Напряже- Интервал напряжений Теперь легко вычислить, сколько градусов ТХА будет соответствовать градусам ВР-2 (будем считать характеристику ТХА в интервале 1 градуса линейной):
Температура Напряже- Температура Произведя вычисления для всех значений ВР-2 и преобразовав результат в 16ричный код, получаем таблицу, по которой и будем рассчитывать температуру:
Таблица соответствия дискрет, принимаемых от термопары типа ВР, температуре, если термопарный блок F2-04THM настроен на термопару ТХА (тип К) Температура ВР Итак, мы настроили модуль таким образом, чтобы при обрыве термопары устанавливался бит, получили таблицу пересчета показаний термопары одного типа в значения другого типа, а что дальше? Если обрыв произошел, продолжать измерения невозможно: из-за наводок результаты будут неверны. Единственный выход из такой ситуации – замкнуть накоротко канал, в котором произошел обрыв. При разработке электрической схемы установки нужно встроить в нее цепь, которая при установлении бита обрыва либо автоматически замкнет канал, либо один из выходов, имеющихся на каркасе контроллера, задействовать для выполнения функции замыкания:
После замены неисправного датчика канал необходимо вернуть в цепь измерений.
Для этого наиболее рациональным решением представляется добавление на панель оператора технологической установки специальной кнопки, соединенной с одним из Xвходов. По нажатию этой кнопки бит замыкания сбрасывается:
10.2. Обработка измерений Теперь, когда мы решили проблемы с «нестандартными» для модуля термопарами и с обрывом, займемся непосредственно измерениями. Согласно документации, модулю для считывания показаний и копирования их в V-память требуется 160 мс на канал плюс один период сканирования, т.е. нам нет необходимости получать результаты измерений в каждом цикле сканирования (если, конечно, цикл сканирования не превышает 160 мс), иначе мы будем считывать одно и то же значение. Поскольку для считывания данных мы будем пользоваться методом мультиплексирования, построим алгоритм считывания следующим образом: через 160 мс плюс один цикл включаем стадию опроса всех задействованных каналов; проверяя биты активного канала, за 4 цикла получим данные 4-х каналов.
Переход на Стадию 10 произойдет с следующем цикле сканирования, так мы выполняем условие обновления показаний каналов.
В Стадии 10 проверяем биты активности каналов и биты обрыва датчика, как было показано выше, в конце стадии проверяем счетчик циклов:
Следующий вопрос – что делать с результатами измерений? Использовать только что полученный результат для индикации либо каких-то дальнейших расчетов и выводов представляется нерациональным, поскольку, во-первых, результаты всегда отличаются последней цифрой вследствие высокой чувствительности модуля; во-вторых, при частой индикации мы будем наблюдать неудобное для глаза мерцание результата; в-третьих, мы не сможем правильно определить тенденцию к изменению показаний; в-четвертых, мы не сможем отфильтровать ошибочные показания, возникшие по причине помех. Обычный способ обработки показаний (и здесь мы не открываем ничего нового) – это накопление полученных результатов в буфере и последующее их усреднение. Обычно оптимальное количество значений в буфере – 8 или 10, в этом случае цикл обновления индикации будет примерно полторы секунды, что вполне приемлемо для визуального контроля. Этот интервал также вполне приемлем для решения задач регулирования.
Для организации буфера нам понадобятся 8 последовательных ячеек V-памяти, ячейка-указатель на элемент буфера, ячейка-счетчик количества считываний, ячейкаадрес буфера, а также две ячейки, в которых будет накапливаться сумма всех считываний по данному каналу. По аналогии с объектно-ориентированным программированием можно сказать, что мы создали класс под названием Канал считывания, а ячейки V-памяти – переменные этого класса. Это не то чтобы дань моде, просто практика показывает, что так удобнее – поскольку принципы считывания показаний каналов и их последующей обработки одинаковы, программирование становится более простым и несколько приближенным к объектно-ориентированным языкам высокого уровня.
Создание переменной объекта типа Канал считывания мы проводим в Стадии 0, которая обычно используется для настройки и инициализации переменных, используемых в программе. Для примера используем один канал; пусть его буфер начинается с ячейки V1500, а переменные этого канала разместим в группе ячеек, начинающейся с адреса V3000. Для усиления тезиса объектно-ориентированного подхода добавим к переменным класса еще одну – ячейку, в которую будет помещаться результат обработки для индикации. Вот так будет выглядеть создание одной переменной типа Канал считывания:
Тогда процедура считывания показаний по этому каналу приобретет следующий вид:
Если произвели 8 считываний – идем на обработку показаний, т.е. усреднение, выбраковку и пересчет из дискрет, например, в градусы (если измеряем температуру):
Если в составе контроллера имеется несколько модулей F2-04THM, то накопить значений в буфере мы можем для нескольких каналов в одном цикле сканирования, что сделает невозможным использование ветви программы, приведенной выше. Выйти из этой ситуации можно, если разделить циклы измерения и циклы обработки, т.е пусть измерения идут своим чередом, а обрабатывать будем только те каналы, для которых произвели 8 считываний. Адреса переменной типа Канал считывания при этом заносятся с специальную очередь, а цикл обработки проверяет очередь и если обнаруживает в ней адрес переменной Канал считывания, то производит обработку. Очередь организуется тоже в Стадии 0:
С учетом этого при накоплении 8 значений в буфере записываем адрес переменной Канал считывания в очередь:
Пусть просмотр очереди осуществляется в Стадии 12. Выбираем из очереди текущий элемент, который представляет собой номер канала, готового для обработки, сохраняем его в специальной ячейке, и очищаем этот элемент очереди:
Теперь легко получить адрес объекта Канал считывания:
Если в очереди нет отличного от нуля элемента, указатели устанавливаются на начало очереди:
Сумма всех 8 считываний находится по адресу (Vадрес массива переменных канала+4).
Используем ячейку V1460 в качестве вспомогательного указателя для расчета среднего значения цикла считывания, результат сохраним в V1465:
Итак, в ячейке V1465 мы получили усредненный результат измерений в течение циклов. Как определить, насколько он правильный? По адресу (Vадрес массива переменных канала+3) будем хранить предыдущий результат усреднения, а в ячейке, например, v2775 – максимально (или минимально) допустимое значение, которое будем рассчитывать, исходя из здравого смысла: пусть для простоты расчетов текущее значение отличается от предыдущего не более чем на 50%, т.е. в V2775 будем записывать половину предыдущего:
Теперь, если текущий результат больше предыдущего, он не должен превышать суммы предыдущего значения и содержимого ячейки V2775, в которой находится величина максимально допустимой абсолютной разницы между текущим и предыдущим показаниями, иначе считаем текущее показание ошибкой и не обрабатываем, хотя сохраняем для сравнения в следующем цикле. Это необходимо для того, чтобы зафиксировать скачок показаний, который может иметь место в случае обрыва, аварийной ситуации и т.п.:
Аналогично проверяем правильность результата, если он меньше предыдущего:
Теперь перед следующим циклом считывания необходимо проинициализировать переменные объекта Канал считывания:
В заключение этой главы – рекомендации по поводу пересчета дискрет в значение температуры. Пересчет не требуется, если модуль настроен на один из стандартных типов термопар, например, тип К. Если же необходимо пересчитать показания модуля в милливольты, а затем по таблице соответствующей термопары определить температуру, можно воспользоваться алгоритмом двоичного поиска:
сравнивая напряжение с серединой интервала, в котором находится искомое значение температуры, находим более короткий интервал, и так до определения интервала напряжений, внутри которого характеристику термопары можно считать линейной (обычно это 1 градус), и на этом интервале проводим линеаризацию.
11. Алгоритм «Выход в точку с заданной скоростью».
Пусть в нашей системе управления имеется механизм, привод которого может перемещаться в положительном и отрицательном направлениях (вперед-назад, вверхвниз). Для управления приводом используем модуль ЦАП «F2-02DA-2», который установлен в слоте 0. Для настройки модуля на выходное напряжение ±10В и формат выходных данных 0-4095 соответствующим образом устанавливаем перемычки на корпусе. Описание положения перемычек подробно приводится в документации. При работе с модулем воспользуемся методом указателя, поэтому для настройки модуля требуется написать команды, которые заносят в специальные ячейки процессора количество каналов и адреса V-памяти, в которые будем записывать выходные значения.
Команды настройки, как уже не раз говорилось, помещаются в начальной стадии:
Чтобы на перегружать пример излишними подробностями, опустим некоторые детали, такие как получение текущей координаты привода и задание новой, пересчет ее в дискреты, а также обсуждение варьируемых величин – обычно их значение подбирается эмпирическим путем. Итак, сначала определяем, в какую сторону будет двигаться привод:
Теперь нужно разогнать привод до заданной скорости, а при приближении к заданной координате затормозить, т.е. выполнить традиционную траекторную задачу управления движением с участками ускорения и замедления. Сразу на ЦАП величину заданной скорости выставить из-за перегрузок нельзя, так же нельзя мгновенно остановить привод, поэтому подберем такое значение уставки ЦАП, при которой привод будет двигаться достаточно медленно, чтобы его можно было сразу остановить или сразу привести в движение без последствий для его конструкции. Назовем эту величину «ползучей скоростью». На этой скорости будем двигаться, если заданный путь меньше участков разгона и торможения. Переходим на стадию разгона, а также активируем стадии, которые осуществляют проверку, не достигли ли мы заданной координаты или же точки начала торможения:
При разгоне каждые 10 мс увеличиваем значение уставки на ЦАП на величину V разгона, пока не достигнем заданной скорости; тогда эта стадия деактивируется:
При движении определяем также, не находимся ли мы на участке торможения. В этом случае начинаем снижать скорость:
Если достигли заданной координаты, останавливаем движение:
Пока не достигли заданной точки, снижаем скорость до значения «ползучей», при которой привод можно безопасно остановить:
Алгоритм движения в противоположную сторону очень легко можно сделать из приведенного выше, внеся небольшие изменения, связанные с тем, что для увеличения скорости уставку на ЦАП нужно не уменьшать, а увеличивать.
Заметим, что в приведенном примере стадии деактивируют сами себя. Мы не считаем это примером хорошего стиля программирования на RLL Plus, однако здесь имеем как раз тот случай, когда отказ от следования стилю даёт достаточно простое и эффективное решение поставленной задачи.
12. Обмен с периферийными устройствами Долгое время контроллеры DirectLogic представляли собой замкнутую систему, способную обмениваться информацией только с аналогичными контроллерами и с «родственными» периферийными устройствами, например, с панелями оператора. Можно было также использовать коммуникационный порт 2 процессора для вывода на печать. С появлением процессора D2-260 стало возможным осуществлять через порт 2 обмен информацией с любыми периферийными устройствами по известному протоколу. Правда, в описании команд, отвечающих за посылку и прием байтов, оговаривается, что эти команды не могут применяться в одном приложении, т.е. предлагается в зависимости от поставленной задачи либо только посылать в порт строку, либо только читать из порта (в качестве примера приводятся электронные весы). На самом деле это не так. Фирмаизготовитель контроллера предлагает использовать только либо запись в порт, либо чтение из порта потому, что отсутствует аппаратная синхронизация процедур чтения и записи. Тем не менее организовать обмен реально, если удастся реализовать синхронизацию программно. В этой главе мы покажем, как это делается. Но сразу сделаем оговорку: пример с обменом был реализован на одном конкретном устройстве. Для любого другого устройства необходим индивидуальный подход. Особенность работы того или иного устройства в режиме обмена выясняется по мере написания нескольких тестовых программ. Основная же задача этой главы - предложить методологию, которая поможет справиться с задачей обмена быстрее и поможет правильному пониманию работы с портом 2.
Прежде всего нужно правильно сконфигурировать порт 2. Делается это в среде Direct Soft: меню PLC->Setup->Setup Sec. Comm port:
Значения таймаута, количество служебных битов и байтов данных, а также тип интерфейса устанавливаются согласно техническим характеристикам устройства.
Предположим, что обмен осуществляется 1 раз в секунду. С отправкой информации в порт проблем нет: строка посылки формируется в V-памяти, для анализа результата посылки резервируются два С-бита: бит «порт занят» (Busy) и бит «выполнено» (Complete), также требуется задать количество посылаемых байтов; при необходимости можно добавить заключительные символы типа «Конец строки» и «Возврат каретки» и переставить байты при посылке их в порт:
Отправка не происходит мгновенно; команда PRINTV лишь инициирует этот процесс. О завершении его можно судить по факту установления бита “Complete” (в нашем примере – бита С2). Состояние С2 проверяем в следующей стадии и, если он установился, идем на стадию приема байтов из порта. Нелишне будет перед этим очистить буфер приема, хотя большой необходимости в этом нет:
Поясним назначение этой стадии. Мы не знаем, сколько времени нужно для установления бита С2 – может, несколько миллисекунд или несколько десятков миллисекунд? У устройства, с которым мы хотим наладить обмен, есть свои временные параметры для отправки ответного сообщения, и если мы опоздаем с анализом бита С2 и не начнем вовремя принимать байты из порта, ответная посылка просто-напросто потеряется. А такое вполне может произойти, если время цикла сканирования относительно велико – скажем, до 10 миллисекунд. С другой стороны, факт установки бита С2 означает лишь то, что посылка отправлена, и нужно подождать какое-то время, пока наше устройство примет информацию, обработает ее и сформирует ответную посылку. В этом случае нам на помощь придет цикл FOR, благодаря которому мы незначительно увеличим цикл сканирования, но зато, правильно подобрав параметр цикла (значение в ячейке V4000), начнем прием сообщения примерно в то время, когда оно и должно появиться на входе порта 2, т.е. фактически эта стадия и отвечает за синхронизацию. Абсолютная точность, к счастью, здесь не требуется: команда приема позволяет задать время таймаута на прием первого символа, и нам лишь нужно, чтобы прием начался до того, как это время истечет.
Для приема строки из порта 2 нужно задать буфер для принимаемых символов, длину посылки (если длина произвольна, то ввести максимально возможную, но не более 128 байт), определить С-биты «занято» и «выполнено». Крайне важно задать время таймаута для первого символа - как сказано выше, благодаря этому параметру в сочетании с параметром цикла FOR и удается синхронизировать прием и отправку сообщений.
Можно также задать таймаут между символами. Если задан таймаут, то резервируется Сбит, который будет установлен в случае, когда время таймаута истекло:
Далее мы ждем установки одного из битов и только тогда уходим из этой стадии и производим соответствующие действия. Так, если установился бит С4 ("Complete"), анализируем принятое сообщение; если установлен один из битов таймаута - сообщаем об ошибке и т.п. Биты завершения посылки и результата приема должны быть сброшены.
Вообще природа команды AIN довольно сложна, и даже в ее описании почти ничего не говорится о том, как она работает. Выводы, которые приведены ниже, сделаны исключительно опытным путем, но, повторимся, получены они в результате обмена с одним определенным устройством, а в случае использования другого устройства команда AIN может вести себя по-другому. Выяснить, как правильно ее применить, можно только экспериментально.
Итак, стадия, в которой используется команда приема, и сама команда приема должны быть активны! Когда команда AIN активируется впервые, инициируется процесс приема и одновременно запускаются ее внутренние таймеры, отсчитывающие таймауты (если приема нет). В последующих циклах сканирования команда AIN фактически не работает, прием идет аппаратно, а активность AIN означает лишь то, что мы как бы "даем понять" процессору, что процедура приема нас все еще интересует - до тех пор, пока не установился один из битов ("Complete" или "Timeout"). Желательно, чтобы во время приема цикл сканирования был как можно короче. Для этого, если программа довольно велика по объему и времени выполнения, возможно, придется на время обмена отключать все или почти все остальные стадии.
Для работы с полученным сообщением в систему команд процессора D2- добавлены новые команды выделения подстроки AEX, выделения подстроки AFIND, сравнения строк CMPV и создания строки в V-памяти VPRINT.
13. Создание «файла событий».
Объем V-памяти контроллера DirectLogic достаточно велик. Поэтому свободные ячейки памяти можно использовать для создания так называемого «файла событий» – т.е.
фиксации всех событий в СУ (изменение состояния дискретных входов, флагов или возникновение ошибки с указанием времени события). Эти данные можно затем проанализировать, распечатав на принтере или передав на верхний уровень управления.
Задействуем верхние адреса V-памяти – с V15500 по V17474. Когда количество событий превысит размер отведенной памяти, запись снова начнется с начала массива. Массив (т.е.
указатель на него), как обычно, сформируем в начальной стадии:
Теперь создадим стадию, которая и будет формировать файл событий. Перед тем, как записать событие, проверим, не вышли ли мы за пределы нашего массива:
Запишем в массив текущее время из ячеек V7766(секунды), V7767(минуты), V7770(часы):
Сохраним текущее значение указателя массива:
Факт события будем записывать в массив таким образом:
Чуть короче это выглядело бы, если запись в массив и модификацию указателя организовать в виде подпрограммы, однако это будет иметь эффект, только если в нашей системе может произойти не более 128 разных событий.
Если в текущем цикле сканирования событий не произошло, возвращаем указатель на место для записи времени в новом цикле, если же события были – запишем в массив число FFFF в виде признака окончания списка событий в данном цикле:
При желании можно этот алгоритм сделать более совершенным: например, ввести проверку изменения времени, чтобы при печати не повторялось одно и то же время.
Произвести быстрое сравнение таблиц позволяет система команд процессора D2-260.
Теперь покажем, как файл событий распечатать на принтере. Принтер должен иметь последовательный порт, порт 2 контроллера необходимо сконфигурировать, как указано в документации (см. описание команды PRINT). Пример будет интересен еще и тем, что в нем используются команды, которые специфичны по своему действию и потому применяются относительно редко. Итак, пусть распечатка файла событий производится по нажатию кнопки. Если никаких событий в системе к моменту начала распечатки не произошло, распечатается только текущее время. Для печати элементов массива событий создадим новый указатель на этот массив:
Значения времени, которые занимают 3 ячейки V-памяти, нужно преобразовать в ASCII-коды. Для этого в языке RLL Plus имеется специальная команда HTA:
Теперь в результате выполнения этой команды мы имеем массив из 6 ячеек, начинающийся с адреса 17610, в котором находится время в ASCII-коде. Но распечатывать время пока что рано – необходимо выполнить еще одно преобразование.
Дело в том, что печать производится младшими байтами вперед, а в результате преобразования числа в ASCII-код старшие разряды времени оказались, соответственно, в старшем байте, хотя на печать должны выводиться раньше. Итак, перед нами стоит задача переставить местами байты в 3 ячейках: V17610, V17612, V17614. В ячейках с адресами V17611, V17613, V17615 находятся ASCII-коды нулей, которые не нужно ни преобразовывать, ни печатать вообще. К сожалению, в системе команд процессора D2- отсутствует команда перестановки байтов, поэтому воспользуемся тем, что есть, а именно командой перестановки знаков SHFLDGT. Для того, чтобы поменять местами старший и младший байты, порядок перестановки должен быть 2143 (разряды 16-31 не трогаем):
То же самое делаем с двумя другими ячейками. Можно было бы, конечно, организовать цикл FOR, но в данном случае сэкономить на командах не получилось бы:
пришлось бы заводить указатели и модифицировать их. Мы сделали проще и понятнее. А процессор DL-260 выполняет это преобразование одной командой:
Теперь печатаем время (лучше делать это в отдельной стадии):
Формат команды PRINT позволяет выводить содержимое ячеек V-памяти напрямую, но если бы мы поступили так, то получили бы по два нуля перед значениями часов, минут и секунд. Теперь распечатаем события, которые произошли в этот момент времени. Если весь список событий распечатан, возвращаемся на ожидание команды печати, а если изменилось время, возвратимся на стадию преобразования времени:
В заключение заметим, как обычно, что совершенству предела нет, и предложенный алгоритм можно при желании улучшить.
14. О том, чего нет в этой книге.
Как уже не раз подчеркивалось, эта книга написана на основе нашего опыта программирования на RLL Plus, и так получилось, что на практике применялись не все команды и возможности языка RLL Plus, а также не все разнообразие модулей, которые могут работать в составе системы управления на базе контроллеров DirectLogic. В частности, не было повода использовать в наших программах счетчики, барабанный командоаппарат, модули прерываний и, соответственно, процедуры их обслуживания, сдвиговые регистры и еще ряд команд и элементов языка. С одной стороны, это говорит о неполноте материала, представленного в нашей работе, но с другой – это отображение того факта, что не все богатые возможности языка RLL Plus обязательно должны иметь применение в системном программном обеспечении, что качественная и надежная программа управления технологической установкой обычно состоит из наиболее общеупотребительных и простых команд. Решение о применении той или иной команды принимается программистом в зависимости от конкретного назначения оборудования, которое ему предстоит автоматизировать, и мы не сомневаемся, что на многих предприятиях, выпускающих автоматизированное технологическое оборудование под управлением контроллеров DirectLogic, активно используются счетчики, преобразователи Грэй-кода и 7-сегментые преобразователи, барабанные командоаппараты, тригонометрические расчеты и операции со строками. Мы не ставили перед собой цель создать учебник языка с примерами, а просто хотели поделиться опытом программирования. Описания «экзотических» команд с примерами имеются в Руководстве пользователя, и на их основе профессиональный программист легко разберется в том, как работает та или иная команда, чтобы использовать ее в своей программе.
Кроме того, мы не описали работу с периферийными устройствами ввода-вывода, которые можно подключить к контроллеру через верхний порт. Имеются в виду пульты оператора и панели отображения. Дело в том, что для настройки этих устройства, а также для модуля H2-CTRIO существует специальное программное обеспечение, вследствие чего для работы с ними не требуется практически никакого программирования – обычно достаточно определить ячейки V-памяти, в которые будут вводиться данные или содержимое которых будет индицироваться.
Поскольку, как было сказано в начале книги, ее особенностью является незаконченность, мы будем признательны нашим читателям, которые предложат новые темы, незатронутые нами, новые интересные алгоритмы, концепции программирования, а также сделают свои замечания по содержанию книги.