Бывают случаи, когда необходимо получить некоторые данные в том же месте кода, где делается их запрос. В этом случае используется вызов функции, при котором происходит ожидание возврата вычисленного значения. Программа, вызывающая такую функцию, приостанавливает свою работу до получения результата. Такое исполнение кода, при котором возвращаемое значение функции определено на момент завершения её работы, называется синхронным.
В ПЛК для работы с внутренней и внешней периферией принято использовать функциональные блоки, результат работы которых определяется специальными внутренними флагами. Момент завершения работы такого блока зависит не от окончания вызова его тела, а от состояния флагов. Такое исполнение кода называется асинхронным. Использование синхронных и асинхронных функций может иметь свои плюсы и минусы в зависимости от контекста. Одним из минусов асинхронной работы является зависимость от времени цикла задачи. В качестве примера можно привести запрос по протоколу modbus rtu.

Представим, что у нас есть сложное многозадачное приложение. Входные данные для алгоритма управления берутся с внешнего удалённого модуля ввода. Мы назначаем задаче обмена по протоколу какое-то время цикла, а в настройках протокола – значение для времени ожидания ответа. Вопрос: Какое значение таймаута ожидания ответа установить?
Дело в том, что при выполнении асинхронного запроса проверка наличия ответа будет осуществляться через время цикла, которое может зависеть также от сложности приложения. Может случиться ситуация, когда какая-то программа или задача однократно в случайное время работает дольше, чем значение таймаута, либо очерёдность их выполнения приводит к превышению времени ожидания. В таком случае мы получим пропуск ответа и нестабильную работу последовательного канала связи. Эту проблему можно решить, увеличивая время таймаута и число повторов при ошибке обмена, но это сразу сказывается на время реакции алгоритма управления. Ещё можно использовать синхронные запросы.

Пример асинхронного запроса

В качестве тестового будем использовать проект Raspberry.ReadCoilsAsyncTest.ST.project из git репозитория codesys, доступного для скачивания в виде архива (кнопка ZIP).

Результат работы под отладчиком: t = 40 мсек (время цикла 20 мсек).

Пример синхронного запроса

Преобразуем программу так, чтобы тело функционального блока вызывалось в цикле. Просто зациклить вызов блока нельзя, т.к. при этом возрастёт нагрузка на CPU. Нужно отдавать процессорное время на выполнение других задач. В этом нам поможет функция SchedWaitSleep() из системной библиотеки CmpSchedule. Она осуществляет задержку, не нагружая процессор.

Проект: Raspberry.ReadCoilsSyncTest.ST.project .

Результат работы под отладчиком: t ~= 16 мсек (время цикла 20 мсек).

При асинхронном запросе интервал обмена включает целое число времени цикла задачи, при синхронном этот интервал определяется моментом чтения ответа из приёмного буфера, либо установленным таймаутом, т.е. не зависит от структуры приложения. Минусом в таком подходе является то, что при синхронном запросе приложение останавливает свою работу на гораздо большее время. Это можно заметить, наблюдая статистику в мониторе конфигуратора задач во время работы.

Теоретическое значение интервала обмена на скорости 19200 для функции 0x01 при заданных параметрах равно: ( 8 + 9 ) * 10 / 19200 ~= 9 мсек.

Обсудить на форуме.

Синхронная функция на базе функционального блока
Метки:        

Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *