Объектно-ориентированное программирование CDS V3

Для понимания материала необходимо: Установка CoDeSys v3 , общие представления об ООП.

История «Священной войны» сторонников процедурного подхода против сторонников объектно-ориентированного подхода насчитывает более 3-х десятков лет. Объектно-ориентированное программирование, впервые появившись в 1967 году в языке Симула, резко набрало обороты и уступало процедурному подходу только в области системного программирования. В программировании ПЛК в силу консервативности этой области до сих пор понятия ООП были неприменимы. Стандарт МЭК предоставлял нам статический надежный, проверенный временем программный компонент – Функциональный блок (ФБ). ФБ формировал хорошую основу для развития его до классического понятия класса. Этот шаг был совершен в 3-й версии CoDeSys, который предоставил программистам ПЛК новый инструмент - ООП, тем самым открыв новую площадку для “Holy War”. Но это все лирика. Давайте перейдем к практике и рассмотрим объектный подход на примерах.

Итак, постановка задачи:
Представим, что у нас есть гостиница с тремя типами номеров: простой, полулюкс и люкс. В простом номере ночью загорается одна лампочка общего освещения, днем она гаснет. В полулюксе ночью загорается лампочка общего освещения и дополнительного освещения. Днем также все лампочки гаснут. В номере люкс помимо основного и дополнительного освещения присутствует климатическая установка, которая поддерживает разную температуру ночью и днем.

Объектно-ориентированный подход решения:
Сначала мы создаем класс простых комнат и описываем логику работы (включение и выключение) с одной лампочкой. Затем класс простых комнат наследуем в новый класс – класс комнат полулюкс, где дополняем код описанием логики дополнительной лампочки, логика основной лампочки наследуется от предка, и описывать её уже не надо. И в конце класс комнат полулюкс наследуем в класс комнат люкс, где добавляем методы работы с климатической установкой, лампочки в последнем классе нам программировать не придется, они были описаны в классах-предках, и в классе люкс мы их получаем по наследству.

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

Запускаем CoDeSys 3.3 и создаем новый Standard Project. Указываем Device: CoDeSys SP Win V3, язык ST. После этих действий получаем новый пустой проект (рис. 1).

img1_3.JPG
Рис 1. Главное окно CoDeSys 3.3.

Наша первоначальная задача - создать класс простых комнат.
Все комнаты обладают методами включения и выключения лампочки и методами, описывающими операции днем (выключение лампы) и ночью (включение лампы). Эти методы должны быть внешними для того, чтобы мы могли обращаться к ним вне объекта. Выведем эти методы в отдельные интерфейсы, которые реализуем в классах комнат.
Для этого создадим интерфейс ILight, который определит методы работы с лампочкой, и интерфейс IRoom, который определит операции дня и ночи в комнате.
В левой части окна рис. 1 на ветке Application щелкаем Левой Клавишей Мышки (ниже сократим последние три слова этой фразы, как ЛКМ) и в выпадающем меню выбираем Add Object. Откроется окно добавления новых объектов к проекту (рис. 2). На всякий случай отметим, что это объекты - элементы самой системы CoDeSys, и их не надо путать с объектами, которые мы описываем и создаем в проекте.

img2_3.JPG
Рис 2. Окно добавления объектов CoDeSys.

В левой части выбираем Interface, в правой части задаем Name ILight, нажимаем Open.
После этих действий в дереве вкладки Devices появится новый элемент – интерфейс ILight (рис. 3)

img3_3.JPG
Рис 3. Интерфейс ILight.

Теперь нам требуется определить в этом интерфейсе методы, которые будут работать с лампочкой. Определим два метода – это SetLight, который будет включать, и выключать лампочку и метод GetLight будет сообщать нам текущее состояние лампочки. Последний метод нам нужен для соблюдения правил инкапсуляции («некрасиво» обращаться к переменным объекта напрямую, не используя методы этого объекта, да и некоторые объекты этого не позволяют).
Добавим эти методы в интерфейс. Для этого щелкаем ЛКМ на этом интерфейсе и выбираем Add Object. Обращаем внимание на новое содержание уже знакомого нам окна добавления объектов (рис. 4).

img4_3.JPG
Рис 4. Добавление методов в интерфейс.

Выбираем Method, задаем имя SetLight и устанавливаем возвращаемый тип bool (тут можно воспользоваться ассистентом ввода – кнопка правее Return Type). Вообще, в нашем примере нам возвращаемый тип понадобится только в методах Get, но отдавая дань традициям ООП (внешние методы должны возвращать хотя бы код ошибки выполнения этого метода) мы введем bool и использовать будем по необходимости.
Нажимаем Open.
В дереве объектов главного окна в ветке интерфейса появляется метод, а в центре окна открывается текстовая часть описания метода на ST Рис. 5.

img5_3.JPG
Рис 5.Метод в интерфейсе.

В тестовой части в секцию VAR_INPUT добавим переменную b:bool; , которая будет получать и устанавливать состояние лампочки. Реализация методов всех интерфейсов будет происходить в классах.
Аналогично методу SetLight добавляем метод GetLight с возвращаемым типом bool (рис. 6).

img6_3.JPG
Рис 6.Метод GetLight в интерфейсе ILight.

Следующим шагом сделаем интерфейс IRoom и добавим в него методы OperationDay и OperationNight (рис. 7). Оба метода возвращают bool.

img7_3.JPG
Рис 7.Интерфейс IRoom.

Теперь у нас есть необходимые методы для описания первого класса простых комнат.
На ветке Application ЛКМ и в выпадающем меню выбираем Add Object. Тут выбираем POU, задаем имя, тип POU – Function Block, язык реализации ST. Ставим галочку Implements и в поле правее через запятую пишем названия интерфейсов, которые мы хотим реализовывать в данном классе (Рис. 8).

img8_3.JPG
Рис 8.Создание класса простых комнат RoomType1.

На рис. 8 мы видим два поля выбора языка реализации. Первый Method implementation language задает язык реализации Методов класса. Второй Implementation language задает язык реализации функционального блока (ФБ), если этот ФБ будет использоваться как ФБ, а не как Класс.
Нажимаем Open и видим, что в дереве Devices появился ФБ с автоматически включенными методами вышеописанных интерфейсов. ФБ с методами представляет собой Класс. Обратим внимание: входной параметр b:bool метода SetLight нового класса RoomType1 был также автоматически взят из описания интерфейса (Рис. 9).

img9_3.JPG
Рис 9.Класс простых комнат RoomType1.

Теперь нам нужна сама лампочка, введем переменную bLight, опишем ее работу, и пропишем работу этой лампочки в операциях дня и ночи. Двойным щелчком правой КМ на имени класса RoomType1 во вкладке Devices попадаем в окно редактора, где в верхней части опишем переменные (свойства), а нижнюю часть, предназначенную для реализации ФБ, трогать не будем.
Таким образом, в секцию VAR введем нужную нам лампочку - переменную bLight типа bool.

img10_3_0.JPG
Рис 10.Свойства Класса RoomType1.

Переходим к реализации методов. Двойным щелчком по имени метода в классе (не в интерфейсе) переходим в редактор, где будем реализовывать методы. Начнем сверху вниз. Первым идет SetLight который получает входной параметр b и присваивает его bLight.

img11_3_0.JPG
Рис 11.Реализация метода SetLight в классе RoomType1.

Следующий метод GetLight просто возвращает значение переменной bLight.

img12_3_0.JPG
Рис 12.Реализация метода GetLight в классе RoomType1.

Метод OperationDay выключает лампочку.
img13_3_0.JPG
Рис 13.Реализация метода OperationDay в классе RoomType1.

Метод OperationNight включает лампочку.
img14_3_0.JPG
Рис 14.Реализация метода OperationNight в классе RoomType1.

Все, класс простых комнат готов. Можем приступать к созданию объектов и использованию оных.
Отредактируем PLC_PRG (аналогичным образом как редактировали методы), как показано на рис 15.

img15_3_0.JPG
Рис 15.Описание PLC_PRG.

В строке 3 верхней части окна мы создали экземпляр (объект) r1 класса RoomType1.
В строке 4 ввели переменную Day, которая будет объявлять время суток. Закат и восход солнца будет производиться вручную.
В нижней части окна реализована логика: если день, то выполняем операции дня этого объекта, если ночь - соответственно операции ночи.

Запускаем проект и проверяем работу!

Для запуска проекта надо поставить галочку в меню Online->Simulate Device, «отбилдить» проект (Build->Build Application). После этого убедиться в отсутствии ошибок по фразе « Compile complete -- 0 errors, 0 warnings» в окне сообщений. Подключаемся к устройству (в нашем случае к его симуляции) Online->Login to Application и запуск на исполнение Online-> Start Application.
Получаем окно, как на рис 16.

img16_3_0.JPG
Рис 16.Окно PLC_PRG запущенного проекта.

Тут мы видим, что изначально у нас ночь (Day=FALSE) и лампочка горит (bLight=TRUE). Двойным щелчком мышки в поле Prepared value в строке переменной Day устанавливаем TRUE и производим запись этого значения в переменную нажав Ctrl+F7. Замечаем, что переменная bLight стала FALSE – свет выключился с восходом солнца.
Останавливаем проект Online->Stop Application и отключаемся от устройства.
На данный момент, мы сделали класс простых комнат и поработали с объектом этого класса.
Следующим действием будет создание класса комнат полулюкс путем наследования класса простых комнат и дополнением методов работой лампы дополнительного освещения. Это будет проще, чем то что мы уже делали.
Создаем новый класс (добавляем в дерево вкладки Devices новый ФБ как RoomType1) RoomType2 рис 17. Выбираем галочку Extend и указываем в поле правее наследуемый класс RoomType1.

img17_3_1.JPG
Рис 17.Добавление класса с наследованием.

После нажатия Open появится новый класс RoomType2 не содержащих (на первый взгляд) в своем составе методов. В действительности же этот класс имеет все свойства и методы родительского класса RoomType1, т.е. так же неявно имеет переменную bLight и может с ней работать теме же методами что и класс предок. Нам остается добавить только дополнительную лампочку. По аналогии добавления свойств (bLight) в классе RoomType1 добавим bAdditionalLight:bool; в RoomType2 (рис. 18).

img18_3_0.JPG
Рис 18. Добавление дополнительного освещения.

За включение и выключение лампы отвечает метод SetLight. Нам требуется научить его включать дополнительное освещение. Для этого добавим этот метод, как новый в RoomType2, но с тем же названием, с тем же возвращаемым типом и с тем же входным параметром. В тело метода добавляем две строки, как на рис. 19.
img19_3_0.JPG
Рис 19. Переписанный метод SetLight в классе RoomType2.

Первая строка в теле метода вызывает метод SetLight предка с параметром b. Метод предка включит основную лампочку. Вторая строка включает дополнительное освещение.
Таким образом, тот же самый метод SetLight в классе RoomType2 включает 2 лампочки.
Все, класс комнат полулюкс готов. Добавим объект этого класса в PLC_PRG и проведем те же эксперименты, переключая переменную Day (рис. 20 и рис. 21).

img20_3_0.JPG
Рис 20. Добавление объекта класса RoomType2.

img21_3_0.JPG
Рис 21. Работа объектов в исполняемом проекте.

Как хорошо видно на рис. 21, в комнате r2 синхронно зажигаются две лампочки. Одна лампочка - доставшаяся по наследству bLight, вторая - добавленная нами.
Итак, мы вышли на финишную прямую и приступаем к созданию самого сложного класса - комнат люкс. Мы создадим интерфейс ITemperature который будет содержать методы работы с климатической установкой. Метод SetTemperature с входным параметром типа INT будет устанавливать требуемую температуру. Метод GetTepmerature будет возвращать значение температуры типа INT. Так же сделаем это, как сделали до этого ILght и IRoom (рис 22). Только не забудем остановить работающий проект и отключиться от Симулируемого Девайса.

img22_3_0.JPG
Рис 22. Добавление интерфейса климатической установки.

При создании метода GetTemperature возвращаемый тип должен быть INT - не забываем про это.
Теперь у нас есть интерфейс Климатконтроля. Создаем Класс Люкс RoomType3, наследуя RoomType2 и реализуя интерфейс ITemperature (рис. 23).

img23_3.JPG
Рис 23. Добавление Класса комнат люкс.

После этого мы добавляем Методы OperationDay и OperationNight для включения в них логики работы климатической установки – аналогично добавлению дополнительного освещения в классе полулюкс. Точно так же как bAdditionalLight в RoomType2 добавляем iTemp:int; (поддерживаемая температура в комнате) в RoomType3 (рис. 24).

img24_3.JPG
Рис 24. Класс RoomType3.

Опишем методы (рис. 25-28)

img25_3.JPG
Рис 25. Метод SetTemperature класса RoomType3.

img26_3.JPG
Рис 26. Метод GetTemperature класса RoomType3.

img27_3.JPG
Рис 27. Метод OperationDay класса RoomType3.

img28_3.JPG
Рис 28. Метод OperationNight класса RoomType3.

В последних двух методах в первых строках происходит включение и выключение обоих ламп методами предка - RoomType2. Во вторых строках устанавливается предпочитаемая температура днем и ночью.
Класс комнат люкс готов.
Добавляем объект в PLC_PRG так же, как мы это делали прежде, и запускаем проект (рис. 29).

img29_3.JPG
Рис 29. Пример рабочего проекта со всеми классами.

Все три класса мы создали и можем теперь порождать объекты в любом количестве и любого класса. Объекты с любым общим интерфейсом можем объединять в массивы для удобства использования. К примеру, в нашем случае три разных комнаты, мы можем их создать множество и обращаться к объектам в цикле (Рис. 30).

img30_3.JPG
Рис 30. Объединение объектов по общему интерфейсу.

Можем объединить все объекты-комнаты в одном объекте (этаж) и работать со всеми комнатами одними методами.

Обсуждение на форуме