Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
Слушайте, ну неужто вы меня подозреваете в непонимании watchdog механизма?
Прочитайте, пожалуйста, ещё раз 1-е сообщение в этой теме. Я же написал, что "команда ПАУЗА" будет компилироваться в CASE-автомат.
Касательно вашего возражения: команда "ПАУЗА" как раз и будет приводить к выходу в основной цикл.
Как раз в моём REPEAT цикле пауза есть:
Как раз, если OwenFileOpenAsync вернуло ASYNC_WORKING, то это означает, что функция ещё не доработала и нам нужно вернуть управление в ПЛК и пробовать в следущий раз.Код:REPEAT res:=OwenFileOpenAsync('usb:test.dat','a',ADR(handle)); IF res = ASYNC_WORKING THEN ПАУЗА; <--- ВОТ ОНА, ПАУЗА!!! END_IF; UNTIL res<>ASYNC_DONE END_REPEAT;
Именно это ПАУЗА и сделает. Она вернёт управление в ПЛК, а при следующем вызове мы продолжим как раз с этого момента.
К слову, если возвращаемых значений более чем 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.
как она это сделает? Из цикла REPEAT она не вырвется пока не выполниться условие, пока не наступит ASYNC_DONE и не будет ни какого следующего цикла плк, только постоянный вызов ПАУЗЫ. Если Ваш пример работает, то только потому что запись или чтение успевают свершиться до максимального времени цикла поставте его чуть больше минимального, нагрузите проект дополнительной работой и сразу начнутся перегрузки. Если так нужна асинхронность процессов, используйте разные задачи, это более перспективно чем жонглировать цикламиИменно это ПАУЗА и сделает. Она вернёт управление в ПЛК
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
Да прочитайте пожалуйста, 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
Иными словами, за 1 вызов оно 1 раз вызовет OwenFileOpenAsync. Если же получен ответ ASYNC_DONE, то оно прекратит вызовы OwenFileOpenAsync.Код: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
Ну и "код, вызывающий функцию OwenFileOpenAsync2" тоже будет компилироваться не в простой одноразовый вызов а в вызов "пока она не выполнится до конца" (разумеется, с немедленным возвращением управления, если внутренняя функция вернула управление, а до конца не доработала).
Последний раз редактировалось Владимир Ситников; 10.10.2017 в 14:49. Причина: FUNCTION -> FB
чему в этом кейсе равен res?1:
IF res<>ASYNC_DONE THEN (* это ошмёток UNTIL res<>ASYNC_DONE *)
state := 0;
ELSE
state := 2;
END_IF;
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
а зачем проверка условия, если вдруг в нулевом кейсе не выполнилось условие res = ASYNC_WORKING?
а если мы попали из нулевого кейса с результатом res := ASYNC_WORKING, то когда он узнает что наступило ASYNC_DONE?
Bad programmers worry about the code. Good programmers worry about data structures and their relationships
среди успешных людей я не встречала нытиков
Барбара Коркоран
Если мы попали из 0-го с результатом res := ASYNC_WORKING, то это и означает, что "ASYNC_DONE ещё НЕ наступило".
Оно увидит, что res<>ASYNC_DONE, выполнит state:=0, тут же (RETURN-а то не было) выполнит ещё одну итерацию внешнего WHILE TRUE, зайдёт ещё раз в CASE, выполнит OwenFile..., посмотрит на res, и так далее.
Я не пытался показать оптимальный код решения конкретной задачи.
Я показал в какой код может компилировать *тупой* компилятор. Так, чтобы было видно, что "из кода на паузах" легко и непринуждённо может автоматически сгенерироваться код на CASE'ах.
Если посмотреть логику исходной программы, то там такой код:
Т.е. исходная программа сравнивала "<>DONE" даже в случае "res = ASYNC_WORKING". Да, была такая "неоптимальность".Код:IF res = ASYNC_WORKING THEN ПАУЗА; (* <-- после "выхода" из паузы, код проваливается ниже и всё равно сравнивает DONE, хотя очевидно, что равенства там не будет *) END_IF; UNTIL res<>ASYNC_DONE END_REPEAT;
Технически, можно было бы написать исходную программу чуть более оптимально (ну, человеку понятно, что если было 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