Цитата Сообщение от 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м посте темы (но я не проверял т.к. думаю, что для понимания идеи его работоспособность не важна).
Допустим, есть проект. ПЛК перезагружается на вызове этого ФБ.
Я открываю код, и вижу:
Код:
WHILE TRUE DO
бесконечный цикл внутри ФБ для ПЛК.

Пишу письмо: "Так мол, и так, у Вас бесконечный цикл вот в этом ФБ."
Приходит ответ: "Нет там ничего бесконечного. Раньше работало, а теперь, вот, перестало".
Волосы на моей голове поднимаются дыбом с мыслью "Ну как так? Не могло это работать".
Начинаю изучать внимательно, ставлю точки останова, прощелкиваю в пошаговой отладке.
Вижу:
  1. ага, с этого шага выход через EXIT, с этого есть, а вот с этого шага как должно выходить?
    А, EXIT потеряли.
  2. или, для разнообразия, проблема вообще не в самом цикле, а на шаге RESETTING есть запись по некорректному указателю.



Я, конечно, утрирую. Но такая ситуация вполне могла возникнуть.

С другой стороны:
Получаю программу, ПЛК все так же перезагружается на вызове ФБ, но реализован так, как в 1м посте
Код:
m_xNeedToChangeState := TRUE;
WHILE m_xNeedToChangeState DO
Первая мысль: где-то внутри цикла переменная m_xNeedToChangeState не изменяется на FALSE.
Пробегаю, смотрю, нет, все хорошо, меняется на FALSE везде, где должна.
Начинаю искать проблему в других местах.