Применение SWITCH-технологии при разработке прикладного программного обеспечения для микроконтроллеров.
Часть 5. Реализация таймеров
Встатье [1] при рассмотрении механизма работы таймеров виртуальные таймеры в SWITCH-программе были условно разделены на два типа: локальные и глобальные. При этом локальным таймером был назван таймер, отсчитывающий время с момента входа в состояние¹ конечного автомата, который используется для определения условий выхода из данного состояния по истечении определенного интервала времени. Также было отмечено, что глобальный таймер, область действия которого охватывает несколько состояний, обладает гораздо большей гибкостью (рис. 1). Итак, рассмотрим пример применения глобального таймера и его программную реализацию.
¹ В каждое состояние автомата, разумеется (прим. автора).
Глобальные таймеры
Глобальным будем называть виртуальный таймер, значение которого инициализируется в одном состоянии автомата, а применяется в качестве условия перехода — в другом. С его помощью можно придать временной детерминизм процессу, который управляется группой состояний автомата.
Для того чтобы понять, зачем нужны глобальные таймеры, рассмотрим в качестве примера систему управления установкой подачи воды в трубопровод. Функциональная схема установки подачи воды в трубопровод приведена на рис. 2. Вода поступает в бак через клапан налива, а затем поступает из бака в технологический трубопровод через клапан подачи.
Система должна подавать в трубопровод воду в количестве (предположим) десяти объемов бака за один рабочий цикл. С целью экономии оборудования обойдемся без расходомера, а будем вычислять объем воды исходя из времени заполнения бака. При этом расход воды в единицу времени заранее неизвестен, но предполагается, что он существенно не изменяется за время одного рабочего цикла. Скорость заполнения бака легко измерить по времени его заполнения (от срабатывания датчика нижнего уровня до срабатывания датчика верхнего уровня) при отсутствии отбора воды из бака (клапан подачи закрыт). Пусть при этом скорость набора воды в бак выше скорости отбора воды из бака. Поэтому нельзя просто открыть клапан налива и отсчитать определенное время, так как бак переполнится. Следовательно, необходимо применить более гибкий подход.
Изобразим алгоритм работы установки в виде конечного автомата с глобальным таймером (рис. 3).
Цикл системы начинается с открывания клапана налива. При этом клапан подачи закрыт. Одновременно с началом рабочего цикла начинается отсчет времени таймером (состояние 1 «Начало налива»). Поступление воды продолжается до достижения верхнего уровня бака (состояние 2 «Конец первого налива»). После этого закрывается клапан налива, измеряется время заполнения бака, вычисляется полное время налива требуемого количества воды, открывается клапан подачи в трубопровод. После осушения бака автомат переходит в состояние «Продолжение налива». По мере заполнения бака и его опустошения автомат переключается между состояниями 3 «Заполнение бака» и 4 «Опорожнение бака». При этом отсчет времени происходит только при открытом клапане налива. По прохождении полного времени налива автомат переходит в состояние 5 «Слив остатка воды», а затем завершает работу (состояние 6 «Конец налива»).
На приведенном примере хорошо видны отличия глобального таймера от локального. Первое отличие, уже обсуждавшееся выше, заключается в том, что запуск таймера происходит в одном состоянии автомата, а его значение служит условием перехода в другое состояние (или несколькj состояниq). Второе отличие состоит в том, что отсчет времени глобальным таймером можно приостановить («поставить на паузу»)², а потом снова запустить. Благодаря этому мы можем контролировать время протекания не только непрерывных процессов, но и таких процессов, выполнение которых периодически приостанавливается (как набор воды в приведенном примере). Третья особенность глобального таймера состоит в том, что мы можем в любой момент времени прочитать его текущее значение и использовать в вычислениях (для локального таймера мы тоже можем прочитать его текущее значение, но так как он «существует» только в пределах одного состояния, это не так интересно с практической точки зрения).
² Может быть, выражение «поставить таймер на паузу» несколько громоздко и не слишком удачно, но позволяет более четко разграничить состояние полного останова таймера, в котором он сброшен «в ноль», и состояние временной приостановки его работы, в котором он сохраняет текущее значение счетчика времени. Здесь можно провести аналогию с магнитофонной кассетой, которую можно перемотать к началу (перевести таймер в состояние останова) или нажать кнопку «пауза», а затем, через какое-то время, продолжить воспроизведение (прим. автора).
Итак, поняв, что такое глобальный таймер и для чего он нужен, опишем его функционирование более формально. Для обеспечения работы с глобальными таймерами используем следующие функции:
Теперь мы легко сможем описать поведение глобального таймера в виде конечного автомата (рис. 4).
Отметим, что на практике конечный автомат, приведенный на рис. 3, можно упростить, объединив состояния 1 и 3 и избавившись от функции StopGTimer (так как она становится эквивалентной функции PauseGTimer). Упрощенный таким образом конечный автомат изображен на рис. 5.
Перейдем к программной реализации механизма глобальных таймеров.
Программная реализация механизма глобальных таймеров
Небольшое отступление. Как видно из приведенного выше листинга, программа, которая реализует управление глобальными таймерами, построена по графу конечного автомата, показанного на рис. 4, предназначена для использования в SWITCH-программах, однако сама по себе построена не по SWITCH-технологии. Это вызвано тем, что переходы между состояниями таймера происходят под воздействием вызовов функций и наиболее удобной в данном случае является реализация этих переходов непосредственно в функциях управления таймером, а не в едином операторе switch. Таким образом, мы несколько пожертвовали «чистотой концепции» ради простоты реализации.
Сейчас мы легко сможем построить программу, реализующую конечный автомат, изображенный на рис. 3.
Сделаем некоторые пояснения к коду. В программе присутствует флаг entry, принимающий значение 1 на следующей итерации цикла после изменения автоматом состояния. Он нужен для того, чтобы действия в состояниях выполнялись однократно после входа автомата в состояние. В самом деле, если таймер будет сбрасываться на каждой итерации цикла, то он просто не будет работать! Для отслеживания изменения состояний служит вспомогательная переменная _state. После каждой итерации переменная _state приравнивается к переменной состояния автомата state.
О некоторых аспектах применения таймеров в автоматном программировании вы можете прочитать в [3–7].
На этом мы закончим обсуждение таймеров и перейдем к описанию некоторых практических примеров применения SWITCH-технологии.
Автор выражает глубокую благодарность Анатолию Абрамовичу Шалыто за ценные замечания и редактирование статьи.
- Татарчевский В. А. Применение SWITCH-технологии при разработке прикладного программного обеспечения для микроконтроллеров. Часть 3 // Компоненты и технологии. 2007. № 1.
- Татарчевский В. А. Применение SWITCH-технологии при разработке прикладного программного обеспечения для микроконтроллеров. Часть 4 // Компоненты и технологии. 2007. № 2.
- Шахов В. Моделирование программно-аппаратных «реактивных» систем раскрашенными сетями Петри // RSDN Magazine. 2006. № 3.
- Петриковский А. Субъектное программирование // Компьютера. 2006. № 13.
- Козаченко В. Ф. Эффективный метод программной реализации дискретных управляющих автоматов во встроенных системах управления // www.motorcontrol.ru
- Шалыто А. А., Туккель Н. И. SWITCH-технология — автоматный подход к созданию программного обеспечения «реактивных» систем // Программирование. 2001. № 5.
- Альтерман И. З., Шалыто А. А. Формальные методы программирования логических контроллеров // Промышленные АСУ и контроллеры. 2005. № 10.