Сегодня я уже должен идти. Завтра с удовольствием прокомментирую свой код.
Сегодня я уже должен идти. Завтра с удовольствием прокомментирую свой код.
а какой смысл в листинге? если человек не может объяснить алгоритм своей программы, это уже ни в какие ворота, а сделав попытку интерпретировать написанную прогу без алгоритма словами, в большинстве случаев приводит к нахождения способов её опьимизации или выявления багов
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
к Вашему сведенью программа подверглась измегениям со слов автора,правда в другой теме и почему я должен обращаться к давно выложенному файлу, чтоб возникло новое гедопонимание, кста на форуме поднималась не раз тема считать затраченое время и выкладывались достойные решения
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
capzap, пруфлинк, пожалуйста, на достойное решение с поллингом (диспетчером опроса группы ведомых с разным интервалом опроса для каждого)
Spectrum48k, я так понимаю, что Вы уже сами разобрались.
Действительно, ничего сложного. Каждый ФБ модуль имеет параметр PoolingTime, который определяет через какое время модуль требует опроса. В случае истечения этого времени модуль выставляет флаг ReqForPooling. Диспетчер в каждом цикле последовательно бегает по массиву модулей и как только увидел, что какой-то модуль выставил флаг на опрос, передает ему такое право, устанавливая переменную AdressForPooling в
значение адреса данного модуля. Когда модуль завершил опрос, он выставляет флаг готовности и диспетчер снова сканирует массив модулей на предмет запроса на опрос. Это общая схема.
Далее дам свое мнение по Вашим вопросам.
Действительно, можно так поступить. В сущности это будет тоже самое. Копирует он в область Var_input не весь массив, а только указатель. Так же он поступает в случае Var_In_out. Но подход с указателем все же имеет преимущество. Его Вы можете один раз проинициализировать (у меня это делается тут: If FirstScan ...). А вот переменную Var_IN_out вы должны при каждом вызове устанавливать.
Я об этом не думал, но задумаюсь над этим. Может, действительно, так сделаю. Но вообще-то это не должно влиять на время опроса, так как у меня последовательность вызовов такая: диспетчер, модуль1, модуль2 и т.д. Т.е. как только диспетчер выдаст кому-то разрешение на опрос, то на этом же скане модуль начнет опрос.
Так как время скана в тестовом примере меньше 1 мс, то любые подобные вещи (Case, вызов модуля из диспетчера) могут увеличить время опроса максимум на 2 мс, а мы видим, что для опроса 4 байт на 115 Кбод требуется 7мс. Я думаю причина где-то глубже.
Вспомнил. Я задумывался над тем, что могу тратить несколько сканов на разрешение опроса модулю. Поэтому, как видно, делаю так, что модуль вызывает диспетчер когда готов:
Base.Ready := TRUE;
pDisp^();
Но в этом случае диспетчер переходит из состояния Pooling в Scaning и не проводит сканирование.
Зато если написать так:
Base.Ready := TRUE;
pDisp^();
pDisp^();
То он еще и сканирование проведет.
А если вот так:
Base.Ready := TRUE;
pDisp^();
pDisp^();
pDisp^();
То проведет сканирование и если найдет нужный модуль, то сразу же даст ему разрешение на опрос и опрос следующего модуля начнется на этом же скане.
Спасибо за критику.
Последний раз редактировалось Спорягин Кирилл; 18.09.2015 в 12:19. Причина: Уточнил текст
SKV, CASE в любом случае нужно убирать и не тиражироать вызовы (CASE заменить на IF Step = .. ;;;; IF Condition THEN Step := Step +1; IF Error THEN Step := 0; и т.д.), тк дисперчер должен после освобождения одного слейва тут же посылать запрос другому. Например, так (фрагмент моего "диспетчера"):
возможно, когда откатаю на паре объектов, выложу полностью. А пока не готов к жесткой критике со стороны старослужащих))Код:2: (*RUN*) (*WatchDog*) TON_WD(IN := TRUE, PT := Set_Poll.WDT); IF TON_WD.Q THEN ErrCode := ErrCode_WatchDog; Step := 3; RETURN; END_IF (*Last Cycle 'Busy' Slave: Busy Flag Check*) IF Busy THEN SLAVE[BusyNum](Busy => Busy); IF SLAVE[BusyNum].Done THEN DoneNum := BusyNum; END_IF END_IF (*No 'Busy' Slave: Check all slaves for busy again *) (*ДОБАВИЛ ДЛЯ ПОЯСНЕНИЯ В ЭТОМ ТОПИКЕ: в цикле и далее вызывается Массив из FB-слейвов, в каждом из них буффер чтения, буффер записи, флаги диагностики, таймеры таймаутов, счетчики ошибок, и естественно единственный код опроса на всех напрямую с ком портом без modbus.lib. При вызове обновляются таймеры и если какой-то из них превышает время поллинга больше других слейвов , то он "отправляется на опрос". Также есть вотч-дог диспетчера, если слейвы перестали опрашиваться в течение заданного интервала. *) IF Busy = FALSE THEN OverT:= t#0ms; KickNum := 0; BusyNum := 0; FOR Cnt := 1 TO Set_Poll.SlaveCnt DO IF SLAVE[Cnt].Set.Use THEN SLAVE[Cnt]( Start:= FALSE, Poll:= FALSE, Reset:= FALSE ); (*'Busy' Slave detected: Set common 'Busy' flag and return*) IF SLAVE[Cnt].Busy THEN Busy := TRUE; BusyNum := Cnt; RETURN; END_IF (*Calc Higher OverTime Slave number*) IF SLAVE[Cnt].ByTime AND SLAVE[Cnt].OverTime > OverT THEN OverT := SLAVE[Cnt].OverTime; KickNum := Cnt; END_IF END_IF END_FOR (*'Kick-start' slave with higher OverTime *) IF KickNum > 0 THEN (*New 'Kick-Start' : Reset WatchDog*) TON_WD(IN := FALSE); SLAVE[KickNum](Poll:= TRUE, Busy => Busy); IF Busy THEN BusyNum := KickNum; END_IF END_IF END_IF
Еще раз по поводу быстродействия: в modbus.lib есть мистический таймер с вызовом PT:=t#3ms, точно не помню, но какжца, он все тормозит как минимум на один цикл. Модифицировать биб-ку или уходить от нее - это уже дело вкуса)
Последний раз редактировалось spectrum48k; 18.09.2015 в 13:59.