Пример создания карты регистров Modbus Slave через структуру STRUCT
Эта статья предполагает, что вы используете язык программирования ST. Он наиболее удобен для работы со множеством переменных и разными логическими условиями. Я сожалею, но примеров на FBD/CFC не будет.
Также я предполагаю, что вы знаете про то, как работать с конфигурацией ПЛК, умеете объявлять переменные и константы, а также понимаете про то, как устроена память ПЛК и как в ней хранятся данные. Если хотите — почитайте старый пост про начальную работу с CodeSys 2.3, а ещё пост про память и переменные ПЛК (адресация).
Так как я пришёл в программирование ПЛК из СИ-подобных языков, где работа с адресами и указателями на память является обычным делом, то я невольно применяю такие методы и в ПЛК, чтобы сделать код красивым и гибким, так как больше всего мне нравятся такие решения, где при изменении размера памяти или числа её элементов не надо ничего изменять или пересчитывать.
Сегодня я расскажу вам о том, как чуть более сложно, но и более изящно и универсально работать с регистрами Modbus Slave в конфигурации ПЛК на базе CodeSys 2.3. Речь идёт о том, как удобно назначать им переменные в коде программы и работать с ними, не используя прямую адресацию через адрес AT%. Я не люблю такую адресацию, потому что она зависит от положения элементов в конфигурации ПЛК: чуть изменишь их — и все адреса поплывут. А это — плохой стиль программирования, который может приводить к ошибкам.
В самом конце статьи будет ссылка на пример прогаммы для CodeSys 2.3, который можно использовать (с сохранением копирайтов) для обучения или ваших проектов.
Регистры Modbus Slave применяются во множестве случаев. Это и подключение панелей оператора, и проброс данных в Облако ОВЕН, и работа с системами верхнего уровня (SCADA, HomeAssistant и другие). Поэтому, как я считаю, будет важно уметь работать с такими картами регистров внутри ПЛК так, чтобы сократить число ошибок в программах, и повысить комфорт работы программиста.
Содержание
- 1. Документирование карт регистров Modbus.
- 2. Проблема больших карт и кучи переменных.
- 3. Обычные способы объявления переменных Modbus Slave.
- 4. Кунг-Фу со структурами. Память ПЛК.
- 5. Привязка структуры на память Modbus Slave.
- 6. Загрузка значений по умолчанию. Инициализация.
- 7. Работа со структурой Modbus Slave.
- 8. Реальный пример проекта — Панель Оператора.
Я не говорю про CodeSys 3.5, так как там регистры Modbus Slave УЖЕ представлены в виде массивов, на которые можно легко (используя эти же методы) отобразить структуру, если это необходимо. В CodeSys 3.5 память Modbus Slave более очевидна, так как она сгруппирована в одном месте. А вот в дереве конфигурации CodeSys 2.3 поди разберись с этим всем…
Объявление Modbus Slave в CodeSys 3.5
1. Документирование карт регистров Modbus.
Сначала я снова буду ДУШНИТЬ! Я знаю, что многие проектируют всё, включая карты регистров, с идеей «Как получится — так и сделаем», и это ПЛОХО! Я заявлял и буду заявлять, что те, кто не делают документацию, — не специалисты. Сейчас я даже разрабатываю своё решение в CS CRM для автоматического расчёта карты регистров (их номеров), чтобы упростить автоматическое создание документации.
Почему документация важна? Я приведу такие аргументы применительно к картам регистров:
- Документировать то, что означает каждый регистр и бит. Ведь по Договору часто передаются исходные коды программ и документация на неё. Проще составить документацию сразу при разработке программы, чем потом мучиться и заставлять себя делать «какие-то бумажки», когда работа почти сдана.
- Проверять выравнивание. Ведь для DWORD и FLOAT (REAL) нужно, чтобы адреса регистров начинались с чётных номеров. Если мы сами рассчитываем карту регистров, то мы можем это проверить и точно знать, на каком номере регистра окажутся наши данные.
- Нумеровать биты и регистры. Это будет нужно для привязки их к панели оператора или другим системам верхнего уровня. Если мы всё пронумеруем заранее, то не надо будет ничего рассчитывать и угадывать. А значит, мы сэкономим себе много времени на пусконаладке.
Я делаю свои карты регистров в XLS-файле (в нём же я составляю таблицу IO-синалов и делаю расчёт мощностей блоков питания ПЛК; я писал про это в посте про технологии отладки программ и работу с IO ПЛК).
Чтобы не возиться с расчётом битов старших номеров, я все биты ставлю в начало карты регистров. Они все нумеруются с нуля и группируются по 16 штук в каждый регистр. Вот как это выглядит (стрелками я показал следующий регистр):
Пример документации на карту регистров: Биты
А потом уже заполняю все регистры в нужном мне порядке. Заодно я указываю номер экрана панели оператора, на котором эти регистры используются. Это очень удобно:
Пример документации на карту регистров: Регистры
Вот, мы видим выделенный регистр 111 на экране «SetWater-5». Заходим в него, и видим его в редакторе панели оператора:
Ввод номера регистра на панели оператора
Таким образом мы можем заполнять привязки битов и регистров в панели Оператора, сверяясь с нашим XLS-файлом. Мы просто берём оттуда рассчитанные цифры.
2. Проблема больших карт и кучи переменных.
Если нам надо передать 10 регистров — то это не страшно. А если 200 или 300 штук? Заполнение конфигурации ПЛК превращается в рутину, где нет наглядности. И мне это не нравится вот чем:
- Ведь каждой переменной надо дать имя, чтобы обращаться к ней. Значит, нам надо иметь множество имён переменных, которые не будут никак сгруппированы, если мы сами это не сделаем их именами (например, добавив префиксы типа «Nasos», «Nagrev» к ним);
- Адреса и порядок регистров этих переменных зависят от того, как они расположены в конфигурации ПЛК. Если что-то изменится — вся адресация поплывёт (но это и так понятно);
- Если привязывать и именовать переменные по прямым адресам AT%, то при изменении конфигурации ПЛК вся эта адресация может сбиться напрочь, и привязку к адресам надо будет делать заново.
Всё это ещё и связано с неудобным окном CodeSys 2.3. Вот ЧТО в этом дереве можно увидеть, если тут даже нет значков или какого-то выделения цветом? Ровное месиво объектов:
Регистры Modbus Slave без именования, кроме первого
А вот примерчик с именами переменных. Они нужны, если мы хотим, чтобы эта конфигурация автоматически выгрузилась в Облако ОВЕН. И вот, чтобы передать в него инфу из 12ти датчиков WirenBoard, мне пришлось руками для каждого из датчиков создавать отдельную переменную с префиксами имён по помещениям:
Много регистров Modbus Slave с именами (ужасно неудобный труд)
И вот всё это можно запихать в структуру STRUCT (кроме переменных для Облака ОВЕН, если нам нужна автоматическая загрузка конфигурации в него) и работать с этим, почти не влезая в дерево конфигурации ПЛК и не привязываясь к прямым адресам AT%!
3. Обычные способы объявления переменных Modbus Slave.
Итак, чтобы обращаться к регистрам Modbus Slave, нам надо дать им какие-то имена. И самый первый способ — это прямая адресация AT%, которую я терпеть не могу.
Мы добавляем в ПЛК нужные нам переменные в дерево Modbus Slave, при этом проверяя то, что они все будут корректно выровнены внутри ПЛК по чётным адресам. Мы должны следить за типом переменных: WORD, REAL, DWORD и добавлять их в правильной последовательности.
Вот пример такого дерева:
Привязка регистров Modbus Slave к программе ПЛК: Запоминаем их адреса
А чтобы привязать к ним наши имена, мы должны где-то написать такие объявления, используя адреса из конфигурации:
Привязка регистров Modbus Slave к программе ПЛК: Вписываем адреса в объявления переменных
Я считаю это крайним убожеством и неуважением себя. Вот почему:
- Нужно следить за выравниванием в дереве конфигурации ПЛК;
- Нужно следить за типами объектов в дереве конфигурации ПЛК;
- Нужно запоминать адрес типа %QW7.1.0 или %QD7.4.0 и вбивать его в другое окно — список переменных;
- По этим адресам в списке переменных совершенно не ясно, где они расположены и за что отвечают. Если программист не даст им понятные имена или не напишет комментарии — разбираться в коде будет очень сложно;
- Если добавить хоть одну переменную в середину карты регистров, все адреса после неё собьются, поменяются, и нужно будет руками исправлять все эти объявления.
Да! Есть люди-роботы, которые могут сказать «А чо? Ну всего 200 строк — сел и за три часика поправил». НЕТ! Я против такого отупления! Мой час стоит 10 тыр. Я не хочу тратить его на такие ерунды, если всё можно сделать изящнее и менее рутинно.
Второй способ позволяет уйти от прямой адресации, просто вписав имена переменных в дерево конфигурации ПЛК. Для этого надо сделать двойной щелчок мышкой на пустой области перед текстом «AT%» и вписать туда название переменной, а потом нажать Enter:
Привязка регистров Modbus Slave к программе ПЛК: Задаём имена переменных в регистрах
Тут есть дурацкий прикол: если при нажатии Enter курсор стоит в начале поля с именем переменной, то оно стирается.
Этот способ убирает только одно неудобство — прямую адресацию. А вот необходимость именовать переменные, группировать их по префиксам, следить за типами элементов в дереве конфигурации ПЛК, — всё это остаётся и создаёт проблемы.
4. Кунг-Фу со структурами. Память ПЛК.
А теперь начинается высшая магия и кунг-фу. И для этого нам надо будет вспомнить пост про Память и Переменные внутри ПЛК. Хах! А я и не думал, что он пригодится.
Напоминаю вам самое важное сейчас для нас. Память внутри ПЛК — это набор байтов с их адресами (по аналогии — как и регистров Modbus). Главное правило ВСЕХ программ для ПЛК и компьютеров — это то, что память для одной переменной или объекта распределяется внутри ПЛК ПОДРЯД друг за другом. Вот это для нас сейчас и важно. И именно эту особенность мы и будем применять.
Давайте вспомним пример из того поста про память. Там я объявлял несколько переменных разных типов в одной задаче:
Организация памяти: Объявление переменных
А потом рисовал примерную схему того, как эти переменные будут находиться в памяти ПЛК. Здесь НЕ показано выравнивание адресов (когда память под переменные небольшого размера выделяется кратно шагу адресации ПЛК).
Организация памяти: Распределение переменных в памяти (без выравнивания)
Обратите внимание на то, что элементы массива arrData расположились подряд. Именно так и выполняется правило, про которое я говорил: память для одного элемента выделяется последовательно в одной общей области.
Точно так же память будет выделена, если мы определим не массив, а структуру STRUCT — составной тип данных. Его удобство в том, что обращаться к его элементам можно через точку, и в том, что в структуры можно вставлять массивы или другие вложенные структуры, удобно группируя данные.
Главное не забудьте про ВЫРАВНИВАНИЕ данных! Здесь оно такое же, как и в памяти Modbus Slave: байты дополняются до WORD, а DWORD и FLOAT (REAL) должны начинаться с чётных адресов. Позже я покажу, как не использовать байты для работы с битами, и упростить выравнивание.
Чем нам это поможет? А тем, что работа с памятью ПЛК позволяет создавать УКАЗАТЕЛИ на области внутри памяти ПЛК и обращаться к ним по имени. А это значит, что мы можем создать свою структуру STRUCT и сказать ПЛК: «А вот представь, что эта структура — это Modbus Slave». И тогда мы сможем обращаться к памяти Modbus Slave через поля этой структуры.
Указатель — это ссылка на адрес памяти внутри ПЛК. Адрес может быть связан с каким-то куском памяти, где лежат нужные нам данные. Когда мы создаём указатель на них, это похоже на то, как мы создаём ярлык для файла в компьютере: файл лежит в одной папке, а ярлык, например, на рабочем столе.
Чтобы объявить структуру, надо перейти на вкладку «Типы данных» структуры проекта:
Раздел Типов данных с созданными структурами
Дальше нужно щёлкнуть на папке «Типы данных» и выбрать команду меню «Добавить объект» и задать его имя. После этого автоматически будет создана заготовка объявления структуры, куда надо вписать её поля-элементы.
Я создал довольно сложную структуру «MBSlaveStruct», заодно в комментариях указав число регистров, которые она будет занимать. Всего она займёт 29 регистров:
Объявление структуры всех регистров Modbus Slave
Тут у меня объявлен даже массив! Он будет использоваться в нашем примере для того, чтобы задавать объёмы дозировки через панель оператора.
Так как Modbus Slave часто используют для работы с панелью оператора, а в проектах есть некоторые типовые наборы данных — например, Насосы или Технологические цепочки, то для них удобно сгруппировать данные, использя вложенные структуры.
Например, если у нас есть какой-то насос, для которого надо передавать такие поля как «Общее время наработки», «Текущее время наработки», «Режим работы», «Статус работы», то вместо создания кучи полей типа NasosLoadTime, NasosLoadMode можно создать структуру с описанием таких полей объекта «Насос»:
Другая структура, которая несколько раз вложена в основную
У меня она занимает 4 регистра. А потом в основной структуре данных объявить нужное число «насосов» (да хоть массив) с нужными групповыми именами.
Такой приём помог бы мне передавать данные от датчиков климата WirenBoard WB-MSW более наглядно и компактно. Вместо создания кучи переменных типа WB1EtGostinTemper, WB1EtKuhnaTemper, WB2EtVhodTemper я создал бы структуру WBSensor и объявил бы несколько раз — для каждого датчика.
Такой приём правильней, так как обращение к параметрам одного датчика шло бы через точку (как и принято в структурах) примерно так: WB1EtGostin.Temper и так далее. Более того, можно было бы передавать ссылку на такую структуру для её заполнения или ещё куда-то. Например, у блока FBNasos из примера выше, сразу на выходе была бы такая же структура (в переменной OPInform — «Информация для панели оператора»), и можно было бы передать все данные в панель оператора одной строчкой типа «SysOPData^.NasosLoad := fbNasos.OPInform;».
Итого, недостатки такого метода я вижу вот в чём:
- Нужно писать ссылку на структуру через указатель с крышечкой: SysOPData^.xxx. Это несколько удлиняет строки кода в программе ПЛК;
- Нужно считать вырванивание в структуре, иначе можно протупить и сбить всю нумерацию регистров.
А вот достоинств больше:
- Хорошее автоматическое именование, так как при обращении через точку CodeSys сразу выведет подсказку с именами всех полей структуры. Если им придуманы понятные имена — сразу вспомнишь о том, что они значат. Для вложенных структур это будет работать точно так же;
- Не надо помнить о типах регистров в дереве конфигурации ПЛК. Не важно, какие они будут: их тип будет обозначен структурой (в ПЛК можно набивать кучу «4 byte», и всё);
- Максимальная независимость от Конфигурации ПЛК: если она сотрётся при переносе на другую платформу, то нужно будет дать имя всего ОДНОЙ переменной, а остальные набить без имён;
- Можно группировать одинаковые блоки (Насосы, ТехПроцессы, Печи, Хранилища, Холодильники и что угодно) во вложенные структуры, что ещё лучше структурирует и упрощает код. Это сокращает число переменных на каждом шаге;
- Можно группировать повторяющиеся элементы в массив (внутри структуры) и обрабатывать их вообще в цикле. Например, в одном проекте я так сделал с массивами для групп сценариев света и присваиваю состояние света из них в цикле. Без копипасты.
5. Привязка структуры на память Modbus Slave.
Сейчас я покажу то, как я пользуюсь этой классной технологией. На данном моменте мы считаем, что документация у нас уже составлена, и размер структуры в регистрах нам известен.
Если вдруг вы не можете подсчитать размер структуры — объявите переменную с её типом и используйте оператор SIZEOF, как я показывал в посте про Память ПЛК:
Организация памяти: Настоящий размер переменной строки в байтах памяти (не равен длине строки)
Тогда вы узнаете размер структуры в байтах, и, поделив его на два, получите размер в регистрах. Нужно, чтобы в конфигурации Modbus Slave было добавлено регистров не менее, чем занимает структура. Один элемент «4 byte» — это два регистра.
Далее надо добавить в конфигурацию ПЛК нужное число регистров. Как я уже говорил выше, тип регистров НЕ важен. Можно брать блок «4 byte» и копировать-вставлять его много-много раз. Я заморачиваюсь и ещё и нумерую эти регистры.
А дальше — магия. Нужно дать ОДИН РАЗ ОДНО понятное имя ПЕРВОМУ блоку регистров.
В моём примере я назвал его «MBSlaveData»:
Конфигурация регистров Modbus Slave в ПЛК
Дальше нам надо объявить указатель на нашу структуру (её тип назван мной «MBSlaveStruct»). Указатель записывается так:
SysSlave : POINTER TO MBSlaveStruct;
Не путайте! Нам надо именно создать новую переменную с таким типом, а не обращаться к нашей структуре! То есть, так же как мы создаём Функциональный Блок (пост про них), а потом объявляем его экземпляр и обращаемся уже к этому экземпляру.
Я делаю это в списке глобальных переменных. Обычно я называю его VarsOP, если работаю с панелью оператора или VarsHA, если работаю с HomeAssistant.
Если больше нигде не объявлять ни одной переменной с типом структуры «MBSlaveStruct», то компилятор ПЛК покажет эту структуру в списке Типов данных серым цветом — как будто она не используется в проекте, и её можно удалять (а на самом деле нет). Это — глюк среды CodeSys 2.3.
Чтобы его избежать, я объявляю в программе временную переменную VAR_TEMP с типом моей структуры. Например SysSlaveTemp : MBSlaveStruct;. Такая переменная нигде не используется, а глюк уходит.
Ну а дальше нам нужно сделать одно ВАЖНЕЙШЕЕ действие. Связать наш указатель на память SysSlave и реальную память Modbus Slave. Для этого нужно использовать оператор ADR. Он получает адрес какой-нибудь переменной.
Но какой переменной? Откуда мы узнаем адрес памяти Modbus Slave, которую мы создали в дереве конфигурации ПЛК? А помните, мы набили туда дофига регистров «4 byte», и первый из них поименовали как «MBSlaveData». А так как мы знаем, что память одного объекта (регистров Modbus Slave) в ПЛК идёт по порядку (то самое важное правило организации памяти), то нам достаточно узнать адрес самой первой переменной этой области. Вот ей-то мы и задали имя «MBSlaveData».
Тогда нам надо присвоить нашему указателю SysSlave адрес переменной «MBSlaveData», взятый оператором ADR().
Делаем это одной строчкой кода «SysSlave := ADR(MBSlaveData);»:
Присваивание адреса карты регистров указателю на структуру
И после этого все поля нашей структуры будут показывать значения регистров Modbus Slave из конфигурации ПЛК. А если записывать данные в поля нашей структуры — то они попадут в регистры Modbus Slave!
Вот так всё одновременно сложно и одновременно просто: одна именованная переменная в дереве конфигурации и одна строчка кода дают нам красивый доступ к памяти регистров!
КРАЙНЕ ВАЖНО: Если вы забудете назначить адрес нашему указателю, то программа ПЛК рухнет, и всё-всё будет глючить (я рассматривал это в посте про Память ПЛК — почитайте это ещё раз)! Этот глюк проявится как постоянная перезагрузка ПЛК или то, что он просто не запустится.
Более того! Такая же ошибка (обращение по неназначенному адресу) будет, если эта строчка не выполнится самой первой — например, если в ПЛК несколько задач, и одна уже обращается к памяти через нашу структуру, а другая ещё не назначила ей адрес!
6. Загрузка значений по умолчанию. Инициализация.
Помагичим ещё немного. Как сделать так, чтобы в регистры Modbus Slave первый раз загрузились какие-то настройки или значения по умолчанию? Ведь через панель оператора обычно передаются не только данные о работе оборудования, а ещё и разные настройки: температура, время работы и какие-то другие. Как сделать так, чтобы они были не нулевыми, а заполнились нужными при первом включении?
Я вроде как знаю, что в решениях с прямой адресацией народ пишет какой-то сложный код, который реализует логику типа «Если переменная равна нулю — назначить её такому-то значению». Ну и вроде как можно просто задать ей значение по умолчанию. Даже если это и работает, это приводит к куче копипастов и сложному коду в ПЛК, который будет проблемно обслуживать: данные опять будут разбросаны по всей программе ПЛК.
Что можно сделать со структурами? Тут снова есть более удобное и целостное решение. Мы будем использовать два приёма ПЛКшечного Кунг-Фу:
- Знание о том, что все переменные Modbus Slave в ПЛК ОВЕН являются RETAIN и сохраняют свои значения при пропадании питания ПЛК;
- Функции копирования памяти из библиотеки SysLibMem.Lib.
Идея у нас будет следующая: мы объявим константу (VAR_CONSTANT) с типом нашей же структуры MBSlaveStruct и зададим там значения по умолчанию. Так как это константа — то ПЛК выделит под неё непрерывную память (и для нас это важно) и задаст нужные значения полей структуры.
Это делается таким вот кодом:
Обявление структуры значений по умолчанию в Константах
Такие объявления — стандартные для того, чтобы задать структурам значения по умолчанию. Поля структуры пишутся через присваивание «:=» с указанием их имён (порядок может быть любой) через запятую, элементы массивов задаются тоже через запятую (нужно указывать все элементы массива). Для структуры можно указывать не все элементы, а только те, значения которых надо явно задать (это позволит сократить такое объявление).
Заодно используем ещё одно Кунг-Фу — обращение к именованным битам переменных. Если объявить константу (НЕ переменную — с переменной это работать НЕ будет!) с нужным именем и присвоить ей значение номера бита, то потом можно будет обращаться к биту переменной через эту константу.
Вот тут я объявил разные константы имён битов и границ массива дозировки компонентов (я придумал такой массив для примера, мы рассмотрим его далее):
Загрузка значений по умолчанию в Slave ПЛК (начальная инициализация переменных)
Среди них есть константа «BtStDefaultsLoaded», которая будет использоваться как флаг «Загружены настройки по умолчанию» («первый запуск ПЛК прошёл успешно»). Эта константа равна нулю в моём примере. И теперь, если написать «BitsState.BtStDefaultsLoaded», то ПЛК обратится к нулевому (по значению константы) биту переменной BitsState типа DWORD.
Итак, пишем код, смысл которого следующий: если бит «BtStDefaultsLoaded» равен нулю, то копируем всю память из константы настроек по умолчанию SysSlaveDefault в память по ссылке адреса SysSlave и выставляем бит «BtStDefaultsLoaded» равным TRUE.
Вот этот код с кучей комментариев:
Код для загрузки начальных значений в структуру Modbus Slave
Его можно написать сразу после той строчки кода, которая присваивала адрес указателю на память Modbus Slave. И всё будет отлично работать!
7. Работа со структурой Modbus Slave.
А дальше можно обращаться к полям нашей структуры через этот наш указатель SysSlave^ так же, как и к обычным переменным программы ПЛК. Если всё объявлено в глобальных переменных — то в любом месте программы ПЛК.
Например, передать на панель оператора данные из FB каких-нибудь насосов (я выдумал такой пример просто так):
Передача данных в Modbus Slave через поля вложенных структур
А можем написать более сложный код: выставить какой-то бит аварии по замеренной температуре. Или даже поработать с массивом дозировки, чтобы выбрать из него значение объёма, указанное номером из панели оператора.
Пример логики ПЛК, которая работает со структурой Modbus Slave
Этот блок кода несколько сложен. Я придумал такой пример: с панели оператора указываются объёмы дозировки продукта для четырёх уставок, которые поимённо объявлены в константах: Small, Medium, Big, Max. Номера этих констант являются у меня индексами массива объёмов SetDoses. Моя выдумка в том, что эти объёмы настраиваются где-то в системных параметрах, а оператор будет использовать внешние имена «Мало», «Средне», «Много», «Полная».
Я применил массив для того, чтобы автоматически выбирать нужны объём без множества условий вида «Если выбрана дозировка такая-то, то возьми данные об объёме из такой-переменной». Это же тоже копипаста. А если расположить регистры настройки объёма подряд — то со сторону ПЛК их можно организовать в удобный массив, индексом которого будет номер дозировки. Это тоже сильно сокращает код, а ещё и делает его универсальным — на потенциально любое количество элементов.
Так вот чтобы нам узнать то, сколько же условных единиц надо дозировать, нам надо узнать, какой номер объёма выбран, а потом из массива извлечь нужное значение. Мы проверяем на то, что номер выбранного объёма НЕ выходит за границы массива (от Small до Max). Если выходит — выдаём ошибку. Потом мы получаем текущее значение объёма и проверяем, чтобы оно было больше 5 (какой-то условный минимум). Если это верно — используем значение из массива. Если меньше пяти — выдаём ошибку.
В этом коде показано правильное программирование, про которое я говорил в посте про Технологии отладки и IO ПЛК — про проверку всех входных данных на верные значения. И этот пример полностью работает с указателем на память Modbus Slave.
8. Реальный пример проекта — Панель Оператора.
В этом проекте я использую панель оператора ОВЕН ИП-320, через которую у меня настраиваются разные параметры. Эти параметры часто используют время (открытие и закрытие штор, ночной режим по разным кварталам). Такие группы настроек я выделил во вложенные структуры SysOPDataSetShtors и SysOPDataSetVents, которые внутри себя ссылаются на структуры времени CSSetTimes с двумя полями «Часы» и «Минуты».
Вот какие структуры я объявил:
Реальный пример: Объявления структур в Типах
Сама структура SysOPData жрёт у меня очень много регистров — под 200 штук.
Реальный пример: Основная структура Modbus Slave
Вложенные структуры выглядят так:
Реальный пример: Одна из вложенных структур (для удобства копирования одинаковых полей)
А основная задача работы с панелью оператора — так:
Реальный пример: Присвоение адреса структуре
Здесь в начале этой задачи я вызываю тот же код, который показал в этом посте: присваиваю адрес ссылке на память Modbus Slave и потом загружаю настройки по умолчанию.
А дальше я, используя именованные биты, передаю в панель оператора разные системные статусы и аварии:
Реальный пример: Передача данных статусов работы в панель оператора
На этом мой мастер-класс закончен. Я создал для него пример всех объявлений в виде проекта. Просьба соблюдать все копирайты и ссылаться на этот пост. Его можно скачать здесь. Видимо, это сделают те, кто дочитал до конца:
CS-PLC-Struct-Demo.zip (~21 кб)
Проекту исполнилось 15 лет! Поддержать проект материально, проспонсировать проекты Автора или сделать ему подарок можно на этой странице: "Донаты и Спонсорство, Список Желаний".
0 Отзыв на “Упрощаем CodeSys v2.3: Карты регистров ModBus через структуры вместо прямой адресации AT”