Зачем вам экстракт, если любой бит можно распаковать ( упаковать) через точку прямо в программе?
Вид для печати
Как ни странно, приведя в пример шлюз дайкин - из 50+ устройств исключительно с ним больше всего приключений. В данный момент - не хочет опрашиваться в цикле. В чем суть - есть 5 регистров на чтение, 5 на запись. 7 файнкойлов. Каждый последующий койл хранит для себя данные, начиная от первого и +6 регистров. То есть, фактически, сводится к написанию 10 циклов For с параметром регистра StartRegister1 + ((CurrentCon-1)*6). Но, по каким-то причинам, данный шлюз так опрашиваться не хотит.. То есть, если мы пишем следующую конструкцию, то все данные у нас - нулевые. При этом - ошибок нет. В буфере мы видим наши данные, ошибки не копятся, ибо модуль ответил и все ок.
IF Mdl.ExecStep = 1 THEN
FOR CurrentCon:=1 TO 7 DO
Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);
IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN
pData := ADR(Mdl.dwDaikinRegisterRead); (*просто переменная, типа Слово, для текущего значения текущего кондея*)
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead; (* Пихаем полученные данные в объявленный массив из интов *)
ELSE
fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
Mdl.ExecStep:=Mdl.ExecStep+1;
END_IF;
Однако, если мы убираем цикл, опрашивая один регистр, на примере:
CurrentCon:=1;
IF Mdl.ExecStep = 1 THEN
Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);
IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN
pData := ADR(Mdl.dwDaikinRegisterRead);
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead;
CurrentCon:=CurrentCon+1;
Mdl.ExecStep:=Mdl.ExecStep+1;
ELSE
fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
END_IF;
(*Далее опрос следующего кондиционера на те же данные *)
IF Mdl.ExecStep = 1 THEN
CurrentCon:=2;
...
То после этого начинает все отличнейше работать. И можно было бы забить на циклы в целом, и на каждый регистр скопировать данный блок, но, исходя из того, что, в общей сложности 10 регистров * 7 койлов получается 70 блоков. Да и неаккуратно как-то.. Ткните, пожалуйста носом, что не так..
Не получится использовать цикл FOR, т.к. опрос каждого регистра занимает некоторое время, а вы пытаетесь за ОДИН программный цикл ПЛК опросить сразу ВСЕ регистры.
Во втором случае у вас счётчик CurrentCon инкрементируется только после завершения предыдущего запроса, что конечно правильно
Да, там, по документации получается, что-то типа 2 по 2,5 мс на чтение/формирование ответа и по 20мс на запрос-ответ, просто странно как-то.. фактически же одно и тоже, мы ничего лишнего не обрабатываем между перемещением к следующему регистру.. уж не на 45 мс.. При этом, мы же ждем обработку данных (IF Mdl.pDisp^.GetInputRegs.Complete THEN), или я что-то путаю? В довесок - при опросе через цикл - у нас прям все данные - нули и, если я правильно понимаю, даже, если шлюз не успевает ответить - как минимум первое значение мы же должны были получить?..
Ну и, с точки зрения опыта - есть, может быть, у кого-то мысли, как сделать правильно в данной ситуации?.. Получается, железка довольно медленная, информации с нее - много. Опрос получается нереально долгим.. Уже придется делить не то, что "сейчас - чтение, в следующее обращение - запись", а, прям "один цикл - один кондей"
Пробовал переиначить, выбросив FOR, использовав IF CurrentCon <> 7 ... CurrentCon:=CurrentCon+1; в конце обработки данных, что, по-сути около-одно и тоже, с другой стороны - не понимаю, чем использование "следующего шага" отличается настолько, что с ним все преображается..
Может пример вам поможет, как считать 280 регистров с 7 блоков за 30-80 ms. Чтение и запись надо разнести по шагам CASE.
https://owen.ru/forum/showthread.php?t=10555&page=987
https://owen.ru/forum/showthread.php...&page=988#9876
Насколько я понял, тут общение происходит через входы/выходы самого плк? По ним не было проблем, тоже довольно шустрый, в моей случае -160М02, управляет парогенератором, воздушными заслонками и частью вентиляции. Без нареканий. Как и овеновские модули, кстати - по модбас - никаких нареканий в нестабильности работы. А вот дайкиновская железяка (на секундочку - за 4.800 евро) прям расстроила.. Тогда, примем, как факт невозможность опроса в цикле..
Спасибо за помощь!