РЕКЛАМА НА ФОРУМХАУС Добрался до дому. Со смарта не удобно писать. И так. @Felix3000, если не получилось - сделайте второй эксперимент. На сколько помню, то сами операции чтения/записи модбас всегда оперируют регистром. Т. е. 2 байта. 1. Покажите как Вы создали в модбас-слейве два байта. 2. Попробуйте еще раз Код: modbus: tcp. slave1.connection=192.168.0.108:502 modbus: tcp. slave1.id=1 modbus: tcp. slave1.start=0 modbus: tcp. slave1.length=2 modbus: tcp. slave1.type=coil Switch Beckhoff_Input0 (gModbus) { modbus="slave1:0"} Switch Beckhoff_Input1 (gModbus) { modbus="slave1:1"} Меняя первые два бита на контроллере в модбас - следите за логами OH. В сети modbus всегда есть один мастер и много слейвов (для каждого интерфейса отдельно) OH выступает для ПЛК в качестве мастера по интерфейсу Ethernet. На ПЛК, на интерфейсе Eth Вы должны создать Modbus Slave в котором будут все Ваши переменные. Если нужно передавать значение со входа контроллера в openhab - у Вас будут две переменные. Одна связана со входом и вторая в слейве. В программе сделайте присваивание Переменная_Слейва = Вход_Контроллера. Если к примеру нужно управлять освещением то в слейве указываем переменную, которая будет тем самым "включателем" и уже ее будете анализировать в ПЛК на предмет "чего делать вкл или выкл" Если управление этой переменной предполагается не только со стороны OH но и ПЛК должен ее по своему передергивать то тогда нужно использовать тригеры для управления этой переменной, что бы переменной присваивалось управляющее воздействие только в течении одного цикла программы управления. Нет не нужно. Все делается в одном. Но для простоты я сделал два слейва. В первом у меня все переменные типа BOOL, вот втором INT, REAL, DWORD Так удобнее в rule программировать. Ну если у вас в слейве Switch Beckhoff_Input0 (gModbus) { modbus="slave1:0"} Просто присваивайте значение этой переменной. Передать состояние кнопок в переменные Slave Описываем переменную в слейве и получаем ее в OH Switch Beckhoff_Input0 (gModbus) { modbus="slave1:0"} В OH устанавливаем эту переменную в CLOSED и эта переменная станет true в слейве. В программе ПЛК присваиваем значение выходная_переменная=Переменная_Слейва
@Smith2007, спасибо за помощь. Проблема заключается в том, что как только я ставлю в конфиге OpenHab "modbus: tcp. slave1.type=coil" вместо "modbus: tcp. slave1.type=holding", в логе вижу только сообщения об ошибке подключения. А когда стоит holding - получается добраться до переменных в памяти Beckhoff. Сейчас в такой вот конфигурации: modbus: tcp. slave1.connection=192.168.0.108:502 modbus: tcp. slave1.id=1 modbus: tcp. slave1.start=0 modbus: tcp. slave1.length=16 modbus: tcp. slave1.type=holding modbus: tcp. slave2.connection=192.168.0.108:502 modbus: tcp. slave2.id=1 modbus: tcp. slave2.start=16384 modbus: tcp. slave2.length=16 modbus: tcp. slave2.type=holding у меня получается прочитать переменные из PLC (через slave1) и сохранить их в памяти PLC (через slave2). Причем slave1.0..15 читает почему-то из области %IB128..%IB%143, а slave2.0..15 читает/пишет в область %MB0..%MB15. Да и фиг бы с ним, меня бы устроил и такой вариант - но это не дает мне возможности напрямую обращаться ко входам-выходам PLC, что резко усложняет коммуникацию. Продолжаю эксперименты в направлении триггеров.
так делать я уже научился. Проблема в отсутствии непосредственной обратной связи - если у меня состояние выхода меняется в зависимости от состояния входа логикой PLC, и при этом я еще и присваиваю состоянию выхода значение их OH - возникают проблемы с приоритетом (что главнее - кнопка на входе или OH). Гораздо удобнее было бы связать напрямую аппаратный выход PLC с свитчем ОН, так чтобы при изменении выхода логикой PLC соответствующее изменение отражалось в ОН, и наоборот - при перещелкивании выхода в ОН это бы мгновенно отражалось на состоянии выхода, без дополнительных промежуточных переменных и присваиваний.
Вечером доберусь до компа и скину пример. В двух словах по управлению с кнопки и плк. За сигнал переключения берем не вход плк, а переменную модбас слейв. Которую мы научились переключать из oh. Плк может так же легко управлять этой переменной по своему алгоритму. Но надо учесть, что нельзя сделать простое присваивание переменной слева значением входа. Нужно сгенерировать одиночный импульс тригером при переходе состояния входа из 0 в 1 и во время этого импульса установить переменную модбас. Это особенности работы программ на плк. Плк программа выполняется от нача до конца за несколько микросекунд. Через несколько миллисекунд вызов повториться и т. д. С таким способом управления можно еще добавлять источники управления. Например смс
Буду признателен за пример. Вообще, кое-что уже проясняется - простую логику совместного управления с кнопки и из ОН я уже поднял, застрял на этапе включения-выключения из ОН выхода, который управляется ПЛК с помощью таймера. Вот как у меня выглядит код простой лампочки, которая управляется и с ПЛК, и из ОН: Переменные: Код: VAR_GLOBAL OH_O1 AT %MB0: INT; (* переменная, которую я могу читать/писать по Modbus *) IN_E_K1 AT %IX0.0: BOOL; (* аппаратный вход ПЛК *) OUT_E_L1 AT %QX0.0: BOOL; (* аппаратный выход ПЛК на реле лампочки *) END_VAR Функциональный блок кнопки: Код: FUNCTION_BLOCK SM_BUTT VAR_INPUT IN: BOOL; (* состояние входа-кнопки *) END_VAR VAR_OUTPUT Q:BOOL := FALSE; (* выход - состояние лампочки *) END_VAR VAR MEM:BOOL := FALSE; (* память состояния кнопки на входе *) END_VAR IF IN AND NOT MEM THEN Q:= NOT Q; END_IF MEM := IN; и сама программа Код: PROGRAM MAIN VAR BUTT_E_B1:SM_BUTT; (* объект кнопки *) OutState: BOOL := FALSE; (* память состояния выхода *) END_VAR IF NOT (INT_TO_BOOL(OH_O1) = OutState) THEN (* если состояние слейва в ОН не совпадает с памятью состояния выхода *) BUTT_E_B1 (IN:=TRUE); (* вызвать принудительное нажатие кнопки *) ELSE BUTT_E_B1 (IN:=IN_E_K1); (* иначе вызвать стандартную процедуру кнопки *) END_IF OUT_E_L1 := BUTT_E_B1.Q; (* передать выход блока кнопки на лампочку *) OH_O1 := BOOL_TO_INT(OUT_E_L1); (* передать выход блока кнопки в ОН *) OutState := OUT_E_L1; (* запомнить состояние выхода *) По факту - работает как задумано (лампочка включается/выключается независимо с кнопки и из ОН, Switch в ОН исправно меняет свое состояние). Буду признателен за комментарии к коду (я только начинаю осваивать программирование ПЛК).
Я могу выслать Вам проект а формате cds 2. x Я использую библиотечные ф. блоки, что бы не изобретать колесо заново
Вот так реализовал простейший алгоритм управления уличным освещением. Включается и выключается автоматически в зависимости от месяца. Так же можно включить и выключить через OpenHab Несколько грубовато, но вполне устраивает не и не требует существенных ресурсов на ПЛК. Выполняется данный код около 0,3 мс. Код: PROGRAM lighting VAR NightMode : ARRAY[1..12] OF tLigtMode := (H_OFF := 9, M_OFF := 00, H_ON := 18, M_ON := 30), (* Январь *) (H_OFF := 8, M_OFF := 00, H_ON := 19, M_ON := 30), (* Февраль *) (H_OFF := 7, M_OFF := 00, H_ON := 20, M_ON := 30), (* Март *) (H_OFF := 6, M_OFF := 00, H_ON := 21, M_ON := 30), (* Апрель *) (H_OFF := 4, M_OFF := 30, H_ON := 22, M_ON := 30), (* Май *) (H_OFF := 4, M_OFF := 00, H_ON := 23, M_ON := 00), (* Июнь *) (H_OFF := 4, M_OFF := 30, H_ON := 23, M_ON := 00), (* Июль *) (H_OFF := 5, M_OFF := 00, H_ON := 22, M_ON := 00), (* Август *) (H_OFF := 6, M_OFF := 00, H_ON := 21, M_ON := 00), (* Сентябрь *) (H_OFF := 7, M_OFF := 00, H_ON := 19, M_ON := 30), (* Октябрь *) (H_OFF := 8, M_OFF := 00, H_ON := 18, M_ON := 30), (* Ноябрь *) (H_OFF := 9, M_OFF := 00, H_ON := 18, M_ON := 30); (* Декабрь *) GetTime: CurTimeEx; Sys_DateTime, Z: SystemTimeDate; Sys_Time: SysTime64; t_current, t_off, t_on: INT; lamp0_on : R_TRIG; lamp0_off : F_TRIG; sw_lamp0: BOOL; END_VAR Sys_DateTime := Z; GetTime (SystemTime:=Sys_Time , TimeDate:= Sys_DateTime); t_current := Sys_DateTime.Hour * 60 + Sys_DateTime.Minute; t_off := NightMode[Sys_DateTime.Month].H_OFF * 60 + NightMode[Sys_DateTime.Month].M_OFF; t_on := NightMode[Sys_DateTime.Month].H_ON * 60 + NightMode[Sys_DateTime.Month].M_ON; (*************************************************) IF t_current >= t_off AND t_current <= t_on THEN sw_lamp0 := FALSE; ELSE sw_lamp0 := TRUE; END_IF; lamp0_on(CLK := sw_lamp0); lamp0_off(CLK := sw_lamp0); IF lamp0_on.Q = TRUE THEN cmdLamp0 := TRUE; END_IF; IF lamp0_off.Q = TRUE THEN cmdLamp0 := FALSE; END_IF; lamp0 := cmdLamp0; lamp0 - это выход контроллера к которому нагрузка подключена cmdLamp0 - переменная modbus slave lamp0_on: R_TRIG; lamp0_off: F_TRIG; Тригеры генерирующие одиночный импульс
@Smith2007, спасибо за пример кода. Можно еще часть с описанием переменных? Мне как новичку сложно понять - где системные типы, а где описанные вами. Как, например, описывается tLightMode? В целом логика кода понятна, буду учиться использовать триггеры. У меня получилось реализовать задачу несколько по-другому - я просто передаю на вход функц. блока кнопки "внешний сигнал" (состояние переменной modbus slave) и на основании ее значения принимаю решение о включении/выключении выхода вентилятора. Функционал в блоке следующий: короткое нажатие на аппаратную кнопку включает/выключает свет, длинное нажатие при выключенном свете (1 сек) включает свет и вентилятор, длинное нажатие при включенном свете выключает свет и вентилятор, короткое нажатие при включенном свете выключает свет и запускает таймер, по истечении которого вентилятор выключается сам. Код: FUNCTION_BLOCK SM_BUTT_TIMER VAR_INPUT IN: BOOL; (* input to watch *) TS: INT; (* ext signal for 2nd out *) TC: TIME; (* time for a long press *) TC2: TIME; (* time to switch the fan off *) END_VAR VAR_OUTPUT Q1: BOOL := FALSE; (* light state *) Q2: BOOL := FALSE; (* fan state *) END_VAR VAR TX: TON; TX2: TON; MEM1, MEM2, MEM3: BOOL; END_VAR IF IN AND NOT MEM1 THEN (* button pressed *) Q1 := NOT Q1; (* change lamp state immediately *) END_IF CASE TS OF (* принимаем решение о включении/выключении вентилятора *) 1: (* signal to turn fan on *) Q2 := TRUE; 2: (* signal to turn fan off *) Q2 := FALSE; ELSE (* no ext signal *) IF TX.Q AND NOT MEM2 THEN (* timer1 signal when lamp is on *) Q2 := Q1; (* set fan state to lamp state *) END_IF IF TX2.Q AND NOT MEM3 THEN (* timer2 signal *) IF NOT Q1 THEN (* if the lamp is off now *) Q2 := FALSE; (* switch the fan off *) END_IF END_IF END_CASE; MEM1 := IN; MEM2 := TX.Q; MEM3 := TX2.Q; А как измерить время выполнения программы?
Да, это я забыл привести описание пользовательского типа данных Код: TYPE tLigtMode : STRUCT H_ON: INT; M_ON: INT; H_OFF: INT; M_OFF: INT; END_STRUCT END_TYPE Из документации по CodeSys Конфигуратор задач в режиме онлайн В режиме онлайн дерево конфигурации задач отображает статус каждой задачи и число отработан- ных ею циклов. Временная диаграмма работы задач показана в правой части окна. Предварительное условие: для поддержки функции мониторинга времени библиотеки SysTaskInfo. lib и SysLibTime. lib должны быть включены в проект. Данные библиотеки отсутствуют, если не установлены целевые платформы, поддерживающие мониторинг задач. @Felix3000, поверьте, что моя работа очень далека от программирования, поэтому могу только поделиться своим опытом но давать советы в этой части не возьмусь Что бы проверить Ваш алгоритм нужно его на контроллер загрузить и пошагово пройти по нему. зы. Одну и ту же задачу на ПЛК можно решить множеством различных способов. И каждый из них будет иметь свои плюсы и минусы и будет верным. Для себя я выбрал приоритетом - минимально-необходимое время для выполнения программы. При этом в угоду читаемости кода иногда отступаю от правила экономии времени, что бы в последствии (через год или два) не вспоминать все хитрости программирования.
эти вычисления можно исключить, если в массиве сразу указать значение в минутах от начала суток. Но я думал, что может потребоваться редактировать эти значения в системе через интерфейс OH. Хотя сейчас уже склоняюсь исключить эту пустую трату вычислительных ресурсов. Надо понимать, что значения эти практически статичны и по нескольку раз в секунду делать вычисления по меньшей мере бессмысленно. Оставить просто массив значений INT. Ну а если понадобиться редактировать со стороны OH то там так же можно будет разложить кол-во минут на часы и минуты. Вот как-то так.
Добрый день. Есть вопрос по openhab: возможно ли к нему прикрутить управление шлюзом noolite ? У него же есть api, может он команды на шлюз отправлять и данные с датчиков получать ?
@ktulhufhtagn, судя по описанию можно управлять по GET запросам. OH имеет поддержку запросов. Смотрите HTTP Binding или напрямую вызов из скриптов/
Здравствуйте. Хотел управлять Болидом с2000пп по modbus. Оказалось что в с2000пп адресация регистров отличается от modbus binding. Какой программой можно отредактировать modbus binding.
@llentiai, что значит отличается адресация? Протокол modbus он стандартизирован. И если с200пп поддерживает modbus, то он может быть подключен к OH