Просмотр полной версии : Как разместить адресное пространство MODBUS в энергонезависимой области ПЛК?
Васильев
01.11.2023, 19:02
прошу помощи..
в разрешении вопроса размещения регистров MODBUS в энергонезависимой памяти ПЛК.
Сейчас ПЛК не доступен, проверить не могу..
если я объявляю регистры MODBUS в области RETAIN (на картинке переменные value_998 value_999),
будут они сохранять свое значение или необходимо в цикле их переписывать в память RETAIN?
Компилятор не ругается на такое объявление переменных..
Спасибо большое.
Тезисы:
1. Все Slave-регистры в конфигурации ПЛК автоматичеси становятся RETAIN.
2. Все такие вот переменные и настройки проще собрать в структуру и ОДИН раз отобразить её на память Slave в конфигурации ПЛК. Чтобы с прямыми адресами так не возиться.
прошу помощи..
в разрешении вопроса размещения регистров MODBUS в энергонезависимой памяти ПЛК.
Сейчас ПЛК не доступен, проверить не могу..
если я объявляю регистры MODBUS в области RETAIN (на картинке переменные value_998 value_999),
будут они сохранять свое значение или необходимо в цикле их переписывать в память RETAIN?
Компилятор не ругается на такое объявление переменных..
Спасибо большое.
Добавлять RETAIN при объявлении сетевых переменных с использованием прямой адресации не нужно и даже вредно, т.к. тогда не происходит присвоение начальных значений этим переменным
Васильев
01.11.2023, 19:22
благодарю
по поводу второго пункта не понимаю как структуру отобразить на память Slave.
разъясните пожалуйста. Я могу массив записывать в память slave, а как отобразить структуру?
kondor3000
01.11.2023, 19:22
прошу помощи..
в разрешении вопроса размещения регистров MODBUS в энергонезависимой памяти ПЛК.
Сейчас ПЛК не доступен, проверить не могу..
если я объявляю регистры MODBUS в области RETAIN (на картинке переменные value_998 value_999),
будут они сохранять свое значение или необходимо в цикле их переписывать в память RETAIN?
Компилятор не ругается на такое объявление переменных..
Спасибо большое.
Что вас всех так тянет указывать прямые адреса? Не нужно этого делать, достаточно дать имена переменным в конфигурации или или в глобальных и всё.
Переменные в слейве (уже будут RETAIN) или в глобальных RETAIN.
Васильев
01.11.2023, 19:32
в конфигурации задавать - для меня не удобно..
если придется что то поменять, то придётся очень долго делать изменения,
а в файле переменных сделать изменения проще (для меня по крайней мере)
kondor3000
01.11.2023, 19:38
благодарю
по поводу второго пункта не понимаю как структуру отобразить на память Slave.
разъясните пожалуйста. Я могу массив записывать в память slave, а как отобразить структуру?
Тода делайте через структуру.
Считаете сколько занимает места структура, если она повторяется умножаете на кол-во повторов и набиваете в слеве (Ctrl C, Ctrl V ) нужное кол-во 2Byte или 4 Byte .
Васильев
01.11.2023, 19:43
а как структуру скопировать в область slave?
понятно массив присвоением...
каждый элемент отдельно?
kondor3000
01.11.2023, 19:51
а как структуру скопировать в область slave?
понятно массив присвоением...
каждый элемент отдельно?
Вашу структуру просто кладёте по адресу первого регистра в набитой области в слейве, как раз тут используете 1 раз прямой адрес, всё.
Вот тут примеры, если интересно, там обсуждений страниц на 10-15, почитайте
https://owen.ru/forum/showthread.php?t=10555&page=987
https://owen.ru/forum/showthread.php?t=10555&page=988#9876
благодарю
по поводу второго пункта не понимаю как структуру отобразить на память Slave.
разъясните пожалуйста. Я могу массив записывать в память slave, а как отобразить структуру?
Разъясняю скриншотами. Тезисы такие:
1. Создаём в Slave нужное число регистров.
2. Присваиваем переменную первому из них.
3. Открываем Эксель и делаем таблицу из номеров регистров и их значений. Она же потом поможет программировать панель оператора и вообще в документацию пойдёт.
4. Набиваем тип-структуру для удобства работы.
5. Объявляем переменную-УКАЗАТЕЛЬ на этот тип.
6. В задаче где-то в самом начале присваиваем адрес первого элемента Slave этому указателю.
7. Дальше в коде обращаемся к указателю и через точку получаем все нужные регистры и поля.
8. Для того, чтобы первый раз загрузить настройки по умолчанию, объявляем нашу же структуру константой с нужными значениями.
В структуре делаем какой-нить флаг типа "SettingsOK" и, если он False - загружаем настройки по умолчанию.
71311 71312 71313 71314 71315 71316 71317
Просьба ВНИМАТЕЛЬНО изучить все скриншоты. И потом думать =)
Разъясняю скриншотами. Тезисы такие:
1. Создаём в Slave нужное число регистров.
2. Присваиваем переменную первому из них.
3. Открываем Эксель и делаем таблицу из номеров регистров и их значений. Она же потом поможет программировать панель оператора и вообще в документацию пойдёт.
4. Набиваем тип-структуру для удобства работы.
5. Объявляем переменную-УКАЗАТЕЛЬ на этот тип.
6. В задаче где-то в самом начале присваиваем адрес первого элемента Slave этому указателю.
7. Дальше в коде обращаемся к указателю и через точку получаем все нужные регистры и поля.
8. Для того, чтобы первый раз загрузить настройки по умолчанию, объявляем нашу же структуру константой с нужными значениями.
В структуре делаем какой-нить флаг типа "SettingsOK" и, если он False - загружаем настройки по умолчанию.
71311 71312 71313 71314 71315 71316 71317
Просьба ВНИМАТЕЛЬНО изучить все скриншоты. И потом думать =)
"Фантики" - это хорошо, структурированно и красиво, но с ними ("фантиками") потом копаться в чужом коде то еще "удовольствие"...:cool:
Такие больше всего нравятся:
71409
:D
"Фантики" - это хорошо, структурированно и красиво, но с ними ("фантиками") потом копаться в чужом коде то еще "удовольствие"...:cool: Не понял юмора. То есть, местным гопникам вместо того, чтобы открыть ОДИН список переменных VarsOP, прочитать там описания, нумерацию и назначение всех полей и битов, удобнее видеть что-то типа
* word1.14
* ipa7.12
* zzbq
* ton1
* rtrig1
Я понимаю, что я эээ.. со свиным рылом в калашный ряд, и что в программировании ПЛК вообще очень мало людей с культурой и стандартами кода (только я и Евгений Кислов, ахаха), но всё же реакции вида "Высмеять всё, что не понятно вместо того, чтобы спросить", я не ожидал.
Ну, дополняю скриншотами.
71410 71411 71412 71413
Не понял юмора. То есть, местным гопникам вместо того, чтобы открыть ОДИН список переменных VarsOP, прочитать там описания, нумерацию и назначение всех полей и битов, удобнее видеть что-то типа
* word1.14
* ipa7.12
* zzbq
* ton1
* rtrig1
Я понимаю, что я эээ.. со свиным рылом в калашный ряд, и что в программировании ПЛК вообще очень мало людей с культурой и стандартами кода (только я и Евгений Кислов, ахаха), но всё же реакции вида "Высмеять всё, что не понятно вместо того, чтобы спросить", я не ожидал.
Ну, дополняю скриншотами.
71410 71411 71412 71413
Cs-Cs, Вы что, "не с той ноги встали?"
Никто ваш код и не высмеивал, лишь поделился своим мнением.
Я на самом деле считаю, что это хорошо, структурированно и красиво, только читается не просто. Зря Вы так...
Cs-Cs, Вы что, "не с той ноги встали?"
Никто ваш код и не высмеивал, лишь поделился своим мнением.
Я на самом деле считаю, что это хорошо, структурированно и красиво, только читается не просто. Зря Вы так...
Я барабанщик с карданом. У меня две ноги одинаково нагружены. Встать могу с любой.
Я же сказал, не понял юмора:
а) Что значит, копаться в чужом коде, если он структурирован?
б) Что за прикол по поводу обращения к именованному битовому полю? Что тут не так?
Cs-Cs, не обращайте внимания на мои "фломастеры", мне красные "вкуснее"...:cool:
Для меня лично в правом. Читая код и доходя до "SysOPLink^.BitsStatus2.3", сразу становится очевидным (как минимум), что BitsStatus2 - это "конец"(нет более никаких "A : stuct1 : struct2 : struct3" и не нужно их искать), дальше (после точки) только её (BitsStatus2) "внутренности". Как бы парадоксально это не выглядело, но, на мой взгляд, именование, порой (и в данном конкретном случае, как примере), привносит обезличивание (если можно так выразиться). Нужно будет "иметь под рукой" (и далее по коду держать в голове, ну или "скакать" постоянно в) "OP-Links-2.gif", чтобы понимать - это те самые "внутренности" (искомые) или же нет.
А с магическими числами в программировании ты(вы) знаком? Это - убийственно плохая практика программирования, когда вместо понятных констант используются сразу подставленные числа, а потом, когда надо это число поменять, его надо везде искать по коду и исправлять, но не перепутать с другим.
Образно, вот написали мы что-то там типа BlaBla.27, а потом почему-то нам надо 27 поменять на 24, которое тоже было использовано в коде в разных местах. Ну, например, какую-то тревогу (для которой был бит), надо вставить именно вот в это место. И дальше нам надо поискать в коде все места с 27, замменить их на 24, но не перепутать эти "новые" 24 со "старыми" 24, которые относятся не к тому. В таких задачах даже полнтекстовый поиск по всему проекту может не помочь.
Чтобы такого не было, правильная практика программирования предлагает выносить всё в константы. Сейчас, к примеру, я достал исходники одного своего проекта на СИ++ из 2003 года (да, 20 лет прошло!), кое-чего там исправляю, и мучаюсь в некоторых местах из-за магических чисел.
Как мудрый камрад, я бы предложил перевести обсуждение вот к чему: как корректно и красиво адресовать битовые маски, если их много. Ведь я сам не нашёл ничего умнее (и это сарказм), чем их просто поименовать и наплодить цифры.
Варианты:
а) Обозвать маски по именам типа BitsAlarmsMain, BitsAlarmsDevices. Но тогда есть риск, что их всё равно не хватит, или что биты тревог будут идти оп последовательно (и панель их не прочитает групповым запросом). Я его отмёл.
б) Накатать вообще какую-то хbтромутную функцию вида GetBit/SetBit, которая будет обращаться к глобальной переменной структуры панели оператора целиком и принимать на входе описание нужного бита в виде адресации НомерDWORD/НомерБИТА, закрученной в структуру и константу. Вот это я бы попробовал.
Тогда код выглядел бы как SetOPBit(AlarmsILCStatusUPS, TRUE), а в "AlarmsILCStatusUPS" было бы описано, что на деле это DWORD номер 4, бит 18ый.
Надо так попробовать, хаха! =)
Образно, вот написали мы что-то там типа BlaBla.27, а потом почему-то нам надо 27 поменять на 24, которое тоже было использовано в коде в разных местах. Ну, например, какую-то тревогу (для которой был бит), надо вставить именно вот в это место. И дальше нам надо поискать в коде все места с 27, замменить их на 24, но не перепутать эти "новые" 24 со "старыми" 24, которые относятся не к тому. В таких задачах даже полнотекстовый поиск по всему проекту может не помочь.
Так а имена, разве, не придется менять во всем коде, если у вас что-либо, где-либо "съехало"? Например, Vhod, который был нулевым, на Vihod, который им стал, а иначе всё поименование теряет смысл...
По мне так "те же яйца, только в профиль", да, опрятнее ну и смысла в имени больше (если оно адекватное, а не SB1, SB2, SB3 и т.д.) чем в числе (том же нуле) и не более того.
Чтобы такого не было, правильная практика программирования предлагает выносить всё в константы.
Возможно, не спорю. Я самоучка (в плане программирования, только не нужно в меня "помидорами кидать", жрать варить у домашней плиты тоже в университете не обучаются...), частенько "копаюсь" в чужих кодах, понравившиеся и логически обоснованные практики беру "на вооружение".
Как мудрый камрад, я бы предложил перевести обсуждение вот к чему: как корректно и красиво адресовать битовые маски, если их много. Ведь я сам не нашёл ничего умнее (и это сарказм), чем их просто поименовать и наплодить цифры.
Варианты:
а) Обозвать маски по именам типа BitsAlarmsMain, BitsAlarmsDevices. Но тогда есть риск, что их всё равно не хватит, или что биты тревог будут идти оп последовательно (и панель их не прочитает групповым запросом). Я его отмёл.
б) Накатать вообще какую-то хbтромутную функцию вида GetBit/SetBit, которая будет обращаться к глобальной переменной структуры панели оператора целиком и принимать на входе описание нужного бита в виде адресации НомерDWORD/НомерБИТА, закрученной в структуру и константу. Вот это я бы попробовал.
Тогда код выглядел бы как SetOPBit(AlarmsILCStatusUPS, TRUE), а в "AlarmsILCStatusUPS" было бы описано, что на деле это DWORD номер 4, бит 18ый.
Надо так попробовать, хаха! =)
С формированием прямой адресации области памяти Slave-переменных вполне справляется Excel с несложными формулами, потом достаточно вводить тип, имя и при необходимости начальное значение и комментарий.
71449
После остаётся только скопировать полученный список в глобальные переменные.
Если устройство-мастер поддерживает какой-либо импорт переменных, то на основе этого файла можно подготовить и список для импорта, не говоря уж о простой карте регистров
Spawn
Так а имена, разве, не придется менять во всем коде, если у вас что-либо, где-либо "съехало"?
Хм. Смотри. Ежели речь идёт о случае, когда битов нам хватит, но надо в середину что-то воткнуть - то мы меняем константы.
Например, БЫЛО:
AlarmKotel = 9;
AlarmDrainVanna = 10;
AlarmDrainTualet = 11;
СТАЛО:
AlarmKotel = 9;
AlarmDrainKuhna = 10;
AlarmDrainVanna = 11;
AlarmDrainTualet = 12;
...то в этом плане код мы НЕ трогаем: поименованные константы нам в этом помогут.
Это как раз то, чего мне не хватало в программее 2003 года, которую я ща исправляю. У меня там всталялись элементы в дерево (как папки), и надо было указывать номера значков этих элементов: выбранный и обычный. Элементы вставлялись в разных местах дерева: в диалоге Импорта, в Добавлении, в Свойствах, в Перетаскивании элемента.
Сейчас мне надо сделать изменяемые значки. И надо найти все места кода, где я их вставляю. Если бы я тогда сделал бы константы типа IconTreeNormal, IconTreeSelected - то сейчас я бы их просто заменил на переменные (или по их именам нашёл места кода) - а ща надо всё вспоминать вручную.
Если же у нас сдвинутся все биты - то тогда да, придётся и DWORD тоже изменять.
Но опять же, если у нас используются поименованные константы, то нам проще сделать везде в коде поиск по слову AlarmDrainVanna и найти, где оно используется.
Если говорить о Входах и Выходах - то я тут использую концепт создания IO-переменных. Вот, погляди у меня тут, я про это писал: https://cs-cs.net/technologii-testirovaniya-i-otladky-shhgitov-s-svtomatikoy-na-plk#4_____io
1exan Идея КРУТАЯ! Мне не надо (я не люблю прямую адресацию), но прям респектище!
Ну, размещение структуры в Slave-переменных - тоже по сути, прямая адресация.
Для структуры кстати тоже можно организовать такой файл - чтобы следил за выравниванием и автоматически считал адреса регистров для мастера.
В CDS2.3 есть ещё такая штука как "bitaccess". Но мне это показалось несколько замороченным способом обращения с битами
1exan
Ну, размещение структуры в Slave-переменных - тоже по сути, прямая адресация. Я сделал не так (в исходном сообщении ранее показано): я назначил переменную на самый первый регистр и подставляю структуру по её адресу через ADR. То есть, если адрес этой переменной изменится, ADR() всё автоматически подсчитает. Руками править ничего не надо.
В CDS2.3 есть ещё такая штука как "bitaccess". Но мне это показалось несколько замороченным способом обращения с битами Ой! Так я ж через это и сделал, если мы про одно и то же: через именованные биты.
Валенок
Пройдет некоторое время и маска аварий будет формироватся тупо одном месте
BitsAlarmsMain, BitsAlarmsDevices превратятся просто в Alarm[1..XX], т.к. достаточным комментарием будет путь к источнику (а не в приемник)
А имена битов аварий уйдут как страшный сон т.к. смысла в именах для юзания в одном месте не будет. Так я бы и номера битов в массие бы тоже константами окучил бы. Чтобы красиво было.
МихаилГл
09.11.2023, 17:37
я бы и номера битов в массие бы тоже константами окучил бы. Чтобы красиво было.
Просто вы работаете с малыми проектами, а там где механизмов 1000 и более, а ещё и scada сторонняя, то удобнее делать массив как alarm[i].
А кроме этого ещё и статусы и прочее. Да, когда всё расписано, удобно, согласен, но когда всё как массив, то это позволяет код из 2000 строк свернуть в код до 50 строк. А работоспособный код нет смысла менять, он уже опробован на живучесть и его проще переносить на другие объекты ничего в нём не меняя. Главное файл ексель не потерять, где всё расписано)
МихаилГл
удобнее делать массив как alarm[i].
О чём идёт речь? Массив структур-объектов? Или прям подряд массив типа "10 тревог объекта 1, 10 тревог объекта 2"?
МихаилГл
09.11.2023, 18:03
МихаилГл
О чём идёт речь? Массив структур-объектов? Или прям подряд массив типа "10 тревог объекта 1, 10 тревог объекта 2"?
Mec(i).Alarm(j) я реализую так. Куча механизмов с другой кучей аварий именно этого механизма. Сейчас у меня например 32 типа аварии на механизм, ограничено только из-за modbus формата работы с панелью СП315, а так можно и больше. Но пока хватает 32 (механизм не запустился, не остановился, не сошёл с концевого при запуске..., выбило автомат какой либо, силовой или цепей автоматики, сработал датчик защиты и пр. с выдержкой времени или без).
Кроме того в программе добавлены массивы вывода из работы соответствующих защит, квитирования и пр.
Просто мне удобней видеть программу, ужатую до 3..4 циклов с минимумом строк.
У меня механизм это структура, которая в зависимости от количества сама как массив. А внутри структуры массив аварий и прочих элементов.
МихаилГл Блин, так мы об одном и том же. Массив структур или массив массивов. Всё ОК, мысль принята.
Но это не отменяет того, что надо нормально именовать все объекты. Вот эта вот советская школа програмирования с i, j, k - меня тошнит от этого.
МихаилГл
09.11.2023, 19:14
МихаилГл Блин, так мы об одном и том же. Массив структур или массив массивов. Всё ОК, мысль принята.
Но это не отменяет того, что надо нормально именовать все объекты. Вот эта вот советская школа програмирования с i, j, k - меня тошнит от этого.
Кстати, о массиве структур. У rockwell, например, если делать каждый булевый элемент значимым, то структура по объему памяти занимает кратное вордовскому значение. Ввели в структуру 1 буль, структура 32 буля минимум стала, поэтому или завести ещё 31 буль, чтоб использовать тот же объем, или просто массив воткнуть из 32 булей. Не знаю как ведёт себя кодесис.
Васильев
02.12.2023, 18:54
Cs-Cs
Спасибо огромное за разъяснение. Всё понятно и доступно.
Cs-Cs
Спасибо огромное за разъяснение. Всё понятно и доступно. Пожалуйста! Мне ОЧЕНЬ приятно это слышать!
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot