
Сообщение от
capzap
так это равнозначно относиться как к while так и к repeat, только из-за того чтоб кто то не на косячил с условиями перед while Вы вынуждены присваивать переменной TRUE
Если накосячить с условиями - то WHILE совсем не выполниться (и понятно, где искать проблему: в условии входа в цикл),
если же в теле цикла есть оператор, прерывающий выполнение, то программа войдет в цикл, но до места, которое Вы хотите отладить не дойдет (и, если внутри цикла много кода, будет сложно понять, куда смотреть).
Тут Вы можете сказать, что
- функции должны быть макисмально аскетичны,
- не должны содержать больше 2х уровней вложенности
- и т.д.
тогда их будет легко отладить.
Со всем вышеперечисленным я соглашусь.
Но бывают ситуации, когда этим приходиться пренебрегать в связи с ограничениями.
Например В ПЛК63\ПЛК73 есть ограничение на 256 POU и в больших проектах в это ограничение легко упереться.
Приходиться функции делать больше.
К примеру, я переписал цикл из тела ETrig, ориентировав его на использование оператора оператора EXIT:
Код:
WHILE TRUE DO
CASE m_eState OF
BM_DORMANT:
IF xExecute THEN
xBusy := TRUE;
m_eState := BM_EXECUTING;
(* TODO: запомнить состояние остальных входов *)
ELSE
EXIT;
END_IF
BM_EXECUTING:
(* TODO: m_xIsExecutionDone должно стать TRUE, когда выполнение операции завершено успешно *)
m_xIsExecutionDone := TRUE;
(* TODO: m_xIsExecutionFail должно стать TRUE, когда возникла ошибка выполнения операции *)
m_xIsExecutionFail := FALSE;
IF m_xIsExecutionFail THEN
m_eState := BM_ERROR;
ELSIF m_xIsExecutionDone THEN
m_eState := BM_DONE;
; (*ЗДЕСЬ ДОЛЖНО БЫТЬ ELSE EXIT *)
END_IF
BM_DONE:
IF xDone AND (m_xResetRequest OR NOT xExecute) THEN
m_eState := BM_RESETTING;
ELSE
xBusy := FALSE;
xDone := TRUE;
m_xResetRequest := NOT xExecute;
EXIT;
END_IF
BM_ERROR:
IF xError AND (m_xResetRequest OR NOT xExecute) THEN
m_eState := BM_RESETTING;
ELSE
xBusy := FALSE;
xError := TRUE;
m_xResetRequest := NOT xExecute;
EXIT;
END_IF
BM_RESETTING:
(* TODO: освобождение ресурсов здесь *)
xBusy := FALSE;
xDone := FALSE;
xError := FALSE;
m_eState := BM_DORMANT;
m_xResetRequest := FALSE;
m_xIsExecutionDone := FALSE;
m_xIsExecutionFail := FALSE;
EXIT;
END_CASE
END_WHILE
Работать он должен точно так же, как в 1м посте темы (но я не проверял т.к. думаю, что для понимания идеи его работоспособность не важна).
Допустим, есть проект. ПЛК перезагружается на вызове этого ФБ.
Я открываю код, и вижу:
бесконечный цикл внутри ФБ для ПЛК.
Пишу письмо: "Так мол, и так, у Вас бесконечный цикл вот в этом ФБ."
Приходит ответ: "Нет там ничего бесконечного. Раньше работало, а теперь, вот, перестало".
Волосы на моей голове поднимаются дыбом с мыслью "Ну как так? Не могло это работать".
Начинаю изучать внимательно, ставлю точки останова, прощелкиваю в пошаговой отладке.
Вижу:
- ага, с этого шага выход через EXIT, с этого есть, а вот с этого шага как должно выходить?
А, EXIT потеряли. - или, для разнообразия, проблема вообще не в самом цикле, а на шаге RESETTING есть запись по некорректному указателю.
Я, конечно, утрирую. Но такая ситуация вполне могла возникнуть.
С другой стороны:
Получаю программу, ПЛК все так же перезагружается на вызове ФБ, но реализован так, как в 1м посте
Код:
m_xNeedToChangeState := TRUE;
WHILE m_xNeedToChangeState DO
Первая мысль: где-то внутри цикла переменная m_xNeedToChangeState не изменяется на FALSE.
Пробегаю, смотрю, нет, все хорошо, меняется на FALSE везде, где должна.
Начинаю искать проблему в других местах.