Страница 2 из 7 ПерваяПервая 1234 ... ПоследняяПоследняя
Показано с 11 по 20 из 64

Тема: ST, паузы, async/await/coroutines

  1. #11
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,225

    По умолчанию

    Цитата Сообщение от Владимир Ситников Посмотреть сообщение
    Где я такое предлагаю? Показывайте где и что зависнет и заблокирует другие задачи.
    в этом коде. Если максимум цикла например две секунды, а бибка вернет DONE только после третьей, плк уйдет в перегрузку
    Изображения Изображения
    • Тип файла: png owen.png (51.2 Кб, Просмотров: 28)
    • Тип файла: png owen1.png (7.3 Кб, Просмотров: 14)
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  2. #12

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    в этом коде. Если максимум цикла например две секунды, а бибка вернет DONE только после третьей, плк уйдет в перегрузку
    Слушайте, ну неужто вы меня подозреваете в непонимании watchdog механизма?

    Прочитайте, пожалуйста, ещё раз 1-е сообщение в этой теме. Я же написал, что "команда ПАУЗА" будет компилироваться в CASE-автомат.

    Касательно вашего возражения: команда "ПАУЗА" как раз и будет приводить к выходу в основной цикл.
    Как раз в моём REPEAT цикле пауза есть:
    Код:
    	REPEAT
    		res:=OwenFileOpenAsync('usb:test.dat','a',ADR(handle));
    		IF res = ASYNC_WORKING THEN
    			ПАУЗА;  <--- ВОТ ОНА, ПАУЗА!!!
    		END_IF;
    	UNTIL res<>ASYNC_DONE
    	END_REPEAT;
    Как раз, если OwenFileOpenAsync вернуло ASYNC_WORKING, то это означает, что функция ещё не доработала и нам нужно вернуть управление в ПЛК и пробовать в следущий раз.
    Именно это ПАУЗА и сделает. Она вернёт управление в ПЛК, а при следующем вызове мы продолжим как раз с этого момента.

    К слову, если возвращаемых значений более чем 2 (ASYNC_WORKING / ASYNC_DONE), то это не меняет саму суть.


    Использовать примерно так:

    Код:
    PROGRAM PLC_PRG
    VAR
      i: INT;
      filesCreated: INT;
    END_VAR
    
    	i := i+1;
      (* Т.е. в основном цикле ПЛК пинаем программу FileWriteRead, она продвигается (или не продвигается) и тут же возвращает управление нам *)
    	ВЫПОЛНИТЬ_ШАГ FileWriteRead;
    	filesCreated := FileWriteRead.cntr;
    END_PROGRAM
    
    ASYNC PROGRAM FileWriteRead
    VAR_OUTPUT
      cntr: INT;
    END_VAR;
    WHILE TRUE
    	res := OwenFileOpenAsync2('usb:test.dat','a',ADR(handle));
    
    	IF res<0 OR handle=0 THEN
    		CONTINUE; (* ошибка, поехали сначала *)
    	END_IF
    
    	res := OwenFileWriteAsync2(handle,ADR(bufout),14,ADR(result));
    
    	IF result=14 THEN
    		res := OwenFileReadAsync2(handle,ADR(bufin),14,ADR(result));
    	END_IF;
    	
    	res := OwenFileCloseAsync2(handle,ADR(result));
    	cntr := cntr+1;
    END_WHILE;
    END_PROGRAM;
    Последний раз редактировалось Владимир Ситников; 10.10.2017 в 12:44.

  3. #13
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,225

    По умолчанию

    Именно это ПАУЗА и сделает. Она вернёт управление в ПЛК
    как она это сделает? Из цикла REPEAT она не вырвется пока не выполниться условие, пока не наступит ASYNC_DONE и не будет ни какого следующего цикла плк, только постоянный вызов ПАУЗЫ. Если Ваш пример работает, то только потому что запись или чтение успевают свершиться до максимального времени цикла поставте его чуть больше минимального, нагрузите проект дополнительной работой и сразу начнутся перегрузки. Если так нужна асинхронность процессов, используйте разные задачи, это более перспективно чем жонглировать циклами
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  4. #14

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    как она это сделает? Из цикла REPEAT она не вырвется пока не выполниться условие, пока не наступит ASYNC_DONE и не будет ни какого следующего цикла плк, только постоянный вызов ПАУЗЫ.
    Да прочитайте пожалуйста, 1-е сообщение. Там написано в какой код будет компилироваться ПАУЗА.

    Рассмотрим, для простоты вот такой код:

    Код:
    ASYNC FUNCTION OwenFileOpenAsync2 : ASYNC_RET_VALUE
    VAR_INPUT
    	stFileName: STRING(255);
    	stMode : STRING[3];
    	returnvalue:POINTER TO DWORD;
    END_VAR
    VAR
    	res: ASYNC_RET_VALUE;
    END_VAR
    	REPEAT
    		res:=OwenFileOpenAsync(stFileName, stMode, returnvalue);
    		OwenFileOpenAsync2 := res;
    		IF res = ASYNC_WORKING THEN
    			ПАУЗА;
    		END_IF;
    	UNTIL res<>ASYNC_DONE
    	END_REPEAT;
    END_FUNCTION
    Он будет компилироваться в такой код. Паузы как таковой вообще не останется в финальной программе.

    Код:
    FUNCTION_BLOCK OwenFileOpenAsync2 : ASYNC_RET_VALUE
    VAR_INPUT
    	stFileName: STRING(255);
    	stMode : STRING[3];
    	returnvalue:POINTER TO DWORD;
    END_VAR
    VAR_INPUT_OUTPUT
    	state : INT; (* эту переменную создал компилятор *)
    END_VAR
    VAR_OUTPUT
    	res: ASYNC_RET_VALUE;
    END_VAR
    WHILE true DO
      CASE state OF (* и этот case тоже создал компилятор *)
      0:
    		res:=OwenFileOpenAsync(stFileName, stMode, returnvalue);
    		IF res = ASYNC_WORKING THEN
    			state := 1;
    			RETURN; (* !! вернуть управление *)
    		END_IF;
    		state := 1;
      1:
    		IF res<>ASYNC_DONE THEN (* это ошмёток UNTIL res<>ASYNC_DONE *)
    			state := 0;
    		ELSE
    			state := 2;
    		END_IF;
      2:
    		RETURN;
      END_CASE;
    END_WHILE;
    END_FUNCTION_BLOCK
    Иными словами, за 1 вызов оно 1 раз вызовет OwenFileOpenAsync. Если же получен ответ ASYNC_DONE, то оно прекратит вызовы OwenFileOpenAsync.

    Ну и "код, вызывающий функцию OwenFileOpenAsync2" тоже будет компилироваться не в простой одноразовый вызов а в вызов "пока она не выполнится до конца" (разумеется, с немедленным возвращением управления, если внутренняя функция вернула управление, а до конца не доработала).
    Последний раз редактировалось Владимир Ситников; 10.10.2017 в 14:49. Причина: FUNCTION -> FB

  5. #15

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    не понимаю этого кода. Может быть не ретурн должен использоваться ( или ФБ вместо функции), он должен выкинуть из функции, следовательно state при следующем вызове функции вновь будет равна нулю и ни когда не случиться поимка ASYNC_DONE в таком случае
    Ну, да, тут подразумевается, что "state" будет принудительно сбрасываться в 0 "только перед самым первым вызовом" и что state будет сохраняться от вызова к вызову.
    Поправил на FB.
    Последний раз редактировалось Владимир Ситников; 10.10.2017 в 14:50.

  6. #16
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,225

    По умолчанию

    1:
    IF res<>ASYNC_DONE THEN (* это ошмёток UNTIL res<>ASYNC_DONE *)
    state := 0;
    ELSE
    state := 2;
    END_IF;
    чему в этом кейсе равен res?
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  7. #17

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    чему в этом кейсе равен res?
    Тому, что вернула функция OwenFileOpenAsync на шаге
    Код:
      0:
    		res:=OwenFileOpenAsync(stFileName, stMode, returnvalue);
    ASYNC_WORKING, ASYNC_DONE и т.п. статусы.

    В чём вопрос-то? Оно же не может сходу взять и зайти в case 1. Туда попадают только из case 0.

  8. #18
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,225

    По умолчанию

    а зачем проверка условия, если вдруг в нулевом кейсе не выполнилось условие res = ASYNC_WORKING?
    а если мы попали из нулевого кейса с результатом res := ASYNC_WORKING, то когда он узнает что наступило ASYNC_DONE?
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  9. #19

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    а если мы попали из нулевого кейса с результатом res := ASYNC_WORKING, то когда он узнает что наступило ASYNC_DONE?
    Если мы попали из 0-го с результатом res := ASYNC_WORKING, то это и означает, что "ASYNC_DONE ещё НЕ наступило".
    Оно увидит, что res<>ASYNC_DONE, выполнит state:=0, тут же (RETURN-а то не было) выполнит ещё одну итерацию внешнего WHILE TRUE, зайдёт ещё раз в CASE, выполнит OwenFile..., посмотрит на res, и так далее.

  10. #20

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    а зачем проверка условия, если вдруг в нулевом кейсе не выполнилось условие res = ASYNC_WORKING?
    Я не пытался показать оптимальный код решения конкретной задачи.
    Я показал в какой код может компилировать *тупой* компилятор. Так, чтобы было видно, что "из кода на паузах" легко и непринуждённо может автоматически сгенерироваться код на CASE'ах.

    Если посмотреть логику исходной программы, то там такой код:
    Код:
    		IF res = ASYNC_WORKING THEN
    			ПАУЗА; (* <-- после "выхода" из паузы, код проваливается ниже и всё равно сравнивает DONE, хотя очевидно, что равенства там не будет *)
    		END_IF;
    	UNTIL res<>ASYNC_DONE
    	END_REPEAT;
    Т.е. исходная программа сравнивала "<>DONE" даже в случае "res = ASYNC_WORKING". Да, была такая "неоптимальность".

    Технически, можно было бы написать исходную программу чуть более оптимально (ну, человеку понятно, что если было ASYNC_WORKING, то условие UNTIL можно не проверять, а сразу переходить к новой итерации):

    Код:
    		IF res = ASYNC_WORKING THEN
    			ПАУЗА;
    			CONTINUE; (* <--- оптимизация, переходим к новой итерации без проверок на _DONE *)
    		END_IF;
    	UNTIL res<>ASYNC_DONE
    	END_REPEAT;
    И тогда компилятор сделал бы такой код:
    Код:
    FUNCTION_BLOCK OwenFileOpenAsync2 : ASYNC_RET_VALUE
    VAR_INPUT
    	stFileName: STRING(255);
    	stMode : STRING[3];
    	returnvalue:POINTER TO DWORD;
    END_VAR
    VAR_INPUT_OUTPUT
    	state : INT; (* эту переменную создал компилятор *)
    END_VAR
    VAR_OUTPUT
    	res: ASYNC_RET_VALUE;
    END_VAR
    WHILE true DO
      CASE state OF (* и этот case тоже создал компилятор *)
      0:
    		res:=OwenFileOpenAsync(stFileName, stMode, returnvalue);
    		IF res = ASYNC_WORKING THEN
    			state := 0; (* CONTINUE -- значит новое состояние это "начало цикла" -- т.е. 0 *)
    			RETURN; (* !! вернуть управление *)
    		END_IF;
    (* state=1 используется из одного места -- можно не создавать отдельную case ветку *)
    		IF res<>ASYNC_DONE THEN (* это ошмёток UNTIL res<>ASYNC_DONE *)
    			state := 0;
    		ELSE
    			state := 2;
    		END_IF;
      2:
    		RETURN;
      END_CASE;
    END_WHILE;
    END_FUNCTION_BLOCK

Страница 2 из 7 ПерваяПервая 1234 ... ПоследняяПоследняя

Похожие темы

  1. Ответов: 4
    Последнее сообщение: 11.05.2018, 13:01
  2. Режим паузы в ТРМ251 на прошивке 2.10
    от Brewer в разделе Эксплуатация
    Ответов: 2
    Последнее сообщение: 29.03.2016, 16:10
  3. Реализация паузы в SFC
    от KoT'86 в разделе ПЛК1хх
    Ответов: 7
    Последнее сообщение: 05.06.2013, 22:28
  4. ПЛК63 - непонятные паузы в исполнении при опросе по 485
    от Alex_yu в разделе Помощь Разработчикам
    Ответов: 9
    Последнее сообщение: 02.07.2011, 23:54

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •